vue3项目初始化——简易版

346 阅读4分钟

webpack系列,非vite系列,非官方系列 此次记录主要解决的问题是:针对.vue文件解析失败 本次实现的代码仓库:gitee.com/tipsyspirit…

1. 工程化基础

工程化认知框架

vue3工程化的需求:

  • 1.整体框架 —— webpack & webpack-cli & webpack-dev-server
  • 2.处理html,自动生成一个html5文件同时引入webpack生成的bundle文件——html-webpack-plugin
  • 3.处理css —— style-loader & css-loader
    • 3.1处理sass/scss[可选] —— sass-loader & sass
    • 3.2处理less[可选] —— less-loader & less
    • 3.3处理postcss[可选] —— postcss & postcss-loader
    • 3.4处理stylus[可选] —— stylus-loader & stylus
  • 4.处理文件/图片[可选] —— file-loader & url-loader
  • 5.处理typescript 和 高级js语法
    • 5.1使用babel —— babel-loader & @babel/core & @babel/preset-env
      • 5.1.1通过babel处理typescript(推荐)[可选] —— @babel/preset-typescript & typescript
      • 5.1.2第三方模块导入,支持require和import —— babel-plugin-module-resolver
      • 5.1.3不通过babel处理typescript(和5.1.1互斥)[可选] —— ts-loader & typescript
  • 6.vue模板解析 —— vue-loader

2. 环境搭建

本次实验采用的css是sass,typescript使用的是babel

2.1 安装依赖

  • 安装整体环境: yarn add webpack webpack-cli webpack-dev-server -D
  • 处理html:yarn add html-webpack-plugin -D
  • 处理css:yarn add style-loader css-loader sass-loader sass -D
  • 处理js:yarn add @babel/core @babel/preset-env babel-loader -D
  • 处理ts:yarn add typescript @babel/preset-typescript -D
  • 处理vue:yarn add vue-loader -D
  • 其他基础依赖:yarn add vue

2.2 工程化配置

  • 在根目录下新建 webpack.config.js 用于配置工程化(webpack)
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const path = require("path");
    
    const { VueLoaderPlugin } = require("vue-loader")
    
    module.exports = {
      mode: "development",
      entry: path.resolve(__dirname, "main.ts"),
      output: {
        filename: "bundle.js",
        path: path.resolve(__dirname, "dist")
      },
      resolve: {
        extensions: [".ts", ".tsx", ".js", ".vue"]
      },
      module: {
        rules: [
          {
            test: /\.(ts|js)x?$/,
            exclude: /node_modules/,
            use: {
              loader: "babel-loader",
              options: {
                presets: ['@babel/preset-env', '@babel/preset-typescript']
              }
            }
          },
          {
            test: /\.vue$/,
            use: "vue-loader"
          },
          {
            test: /\.(svg|otf|ttf|woff|woff2|eot|gif|png)$/,
            use: "url-loader"
          },
          {
            test: /\.(scss|css)$/,
            use: [
              "style-loader",
              "css-loader",
              "sass-loader"
            ]
          }
        ]
      },
      plugins: [
        new VueLoaderPlugin(),
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, "index.html")
        })
      ]
    }
    
  • 项目结构调整——在根目录下新增main.ts文件(js入口文件)
  • 项目结构调整——在根目录下新增index.html文件(html容器文件)
  • 项目结构调整——在根目录下新增dist目录(打包输出文件夹)
  • 调整package.json——增加脚本——"dev": "webpack serve --config ./webpack.config.js
    "scripts": {
      "dev": "webpack serve --config ./webpack.config.js"
    }
    
  • 最终的项目结构
    vue3template
    ├─ dist    // 打包输出文件
    ├─ index.html  // html容器文件
    ├─ main.ts    // js入口文件
    ├─ package.json 
    ├─ readme.md
    ├─ webpack.config.js // webpack配置文件
    ├─ yarn-error.log
    └─ yarn.lock
    
    

2.3 环境测试

  • 测试环境

    通过在根目录所在的命令行输入 npm run dev

1c9edcdbc66f7b1f827628ffab74220.png 如果命令行窗口无错误则环境正常;也可以通过浏览器验证,即输入webpack服务启动后的地址,默认是"http://localhost:8080/"

  • 测试ts

    在main.ts文件中输入测试代码

    
    let str: string = "hello world";
    
    console.log(str);
    

    如果命令行窗口无错误则环境正常;也可在浏览器控制台查看结果。

  • 测试vue功能[可选]

    在main.ts文件中输入测试代码

    import { createApp, h } from "vue";
    
    let App = {
      setup() {
        return () => {
          return h("h2", {}, "hello world")
        }
      }
    }
    let MyApp = createApp(App)
    MyApp.mount("#app");
    

    如果命令行窗口无错误则环境正常;也可在浏览器界面查看有无显示。

  • 测试vue文件

    新建文件:src/App.vue,代码如下

    <template>
      <h2>Hello world</h2>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    
    export default defineComponent({
      setup() {},
    });
    </script>
    

    在main.ts文件中输入测试代码

    import App from "./src/App.vue";
    import { createApp, h } from "vue";
    
    let MyApp = createApp(App)
    MyApp.mount("#app");
    

    如果命令行窗口无错误则环境正常;也可在浏览器界面查看有无显示。

image.png 测试结果: 异常

3. 分析问题

分析过程见附录1

分析结果:没有vue-template-compiler插件,以及没有对vue文件指定typescript解析

处理方法:

  • yarn add vue-template-compiler -D
  • 增加typescript配置,在webpack.config.js中配置
    {
      test: /\.(ts|js)x?$/,
      exclude: /node_modules/,
      use: {
        loader: "babel-loader",
        options: {
          presets: ['@babel/preset-env', [
            "@babel/preset-typescript",
            {
              "allExtensions": true
            }
      ]]
        }
      }
    },
    
  • 额外问题:typescript中无法加载到App.vue文件,原因是关于vue的ts类型声明文件没有
    • 增加 shims-vue.d.ts文件
    /* eslint-disable */
    declare module '*.vue' {
      import type { DefineComponent } from 'vue'
      const component: DefineComponent<{}, {}, any>
      export default component
    }
    

附录1

  • "@vue/cli-plugin-babel": "~5.0.0"
    • 处理babel (5.1)
    {
      "dependencies": {
        "@babel/core": "^7.12.16", // √
        "@vue/babel-preset-app": "^5.0.3", 
        "@vue/cli-shared-utils": "^5.0.3",
        "babel-loader": "^8.2.2", // √
        "thread-loader": "^3.0.0",
        "webpack": "^5.54.0" // √
      },
      "devDependencies": {
        "@babel/preset-env": "^7.12.16", // √
        "jscodeshift": "^0.13.0"
      }
    }
    
  • "@vue/cli-plugin-typescript": "~5.0.0"
    • 处理typescript,采用非babel的方式(5.1,5.1.3)
    {
      "dependencies": {
        "@babel/core": "^7.12.16", // √
        "@types/webpack-env": "^1.15.2",
        "@vue/cli-shared-utils": "^5.0.3",
        "babel-loader": "^8.2.2", // √
        "fork-ts-checker-webpack-plugin": "^6.4.0",
        "globby": "^11.0.2",
        "thread-loader": "^3.0.0",
        "ts-loader": "^9.2.5", // √
        "webpack": "^5.54.0", // √
        "yorkie": "^2.0.0"
      },
      "devDependencies": {
        "@types/chai": "^4.2.15",
        "@types/jest": "^27.0.1",
        "@types/mocha": "^8.2.1",
        "jscodeshift": "^0.13.0",
        "typescript": "~4.5.5", // √
        "vue-class-component": "^7.2.3",
        "vue-property-decorator": "^9.1.2"
      }
    }
    
  • "@vue/cli-service": "~5.0.0"
    • 核心处理逻辑 包括html,css,js
    {
      "dependencies": {
        "@babel/helper-compilation-targets": "^7.12.16",
        "@soda/friendly-errors-webpack-plugin": "^1.8.0",
        "@soda/get-current-script": "^1.0.2",
        "@types/minimist": "^1.2.0",
        "@vue/cli-overlay": "^5.0.3",
        "@vue/cli-plugin-router": "^5.0.3",
        "@vue/cli-plugin-vuex": "^5.0.3",
        "@vue/cli-shared-utils": "^5.0.3",
        "@vue/component-compiler-utils": "^3.3.0",
        "@vue/vue-loader-v15": "npm:vue-loader@^15.9.7",
        "@vue/web-component-wrapper": "^1.3.0",
        "acorn": "^8.0.5",
        "acorn-walk": "^8.0.2",
        "address": "^1.1.2",
        "autoprefixer": "^10.2.4",
        "browserslist": "^4.16.3",
        "case-sensitive-paths-webpack-plugin": "^2.3.0",
        "cli-highlight": "^2.1.10",
        "clipboardy": "^2.3.0",
        "cliui": "^7.0.4",
        "copy-webpack-plugin": "^9.0.1",
        "css-loader": "^6.5.0",  // √ css处理 —— 3
        "css-minimizer-webpack-plugin": "^3.0.2",
        "cssnano": "^5.0.0",
        "debug": "^4.1.1",
        "default-gateway": "^6.0.3",
        "dotenv": "^10.0.0",
        "dotenv-expand": "^5.1.0",
        "fs-extra": "^9.1.0",
        "globby": "^11.0.2",
        "hash-sum": "^2.0.0",
        "html-webpack-plugin": "^5.1.0", // √ html处理 —— 2
        "is-file-esm": "^1.0.0",
        "launch-editor-middleware": "^2.2.1",
        "lodash.defaultsdeep": "^4.6.1",
        "lodash.mapvalues": "^4.6.0",
        "mini-css-extract-plugin": "^2.5.3",
        "minimist": "^1.2.5",
        "module-alias": "^2.2.2",
        "portfinder": "^1.0.26",
        "postcss": "^8.2.6", // √ postcss处理 —— 3.3
        "postcss-loader": "^6.1.1", // √ postcss处理 —— 3.3
        "progress-webpack-plugin": "^1.0.12",
        "ssri": "^8.0.1",
        "terser-webpack-plugin": "^5.1.1",
        "thread-loader": "^3.0.0",
        "vue-loader": "^17.0.0", // √ vue处理 —— 6
        "vue-style-loader": "^4.1.3",
        "webpack": "^5.54.0", // √ webpack整体框架 —— 1
        "webpack-bundle-analyzer": "^4.4.0",
        "webpack-chain": "^6.5.1",
        "webpack-dev-server": "^4.7.3", // √ webpack整体框架 —— 1
        "webpack-merge": "^5.7.3",
        "webpack-virtual-modules": "^0.4.2",
        "whatwg-fetch": "^3.6.2"
      },
      "devDependencies": {
        "cache-loader": "^4.1.0",
        "sass": "^1.32.7", // √ sass处理 —— 3.1
        "sass-loader": "^12.0.0", // √ sass处理 —— 3.1
        "stylus-loader": "^6.1.0", // √ stylus处理 —— 3.4
        "vue": "^2.6.14",
        "vue-router": "^3.5.1",
        "vue-template-compiler": "^2.6.14",
        "vuex": "^3.6.2"
      }
    }
    
  • "sass": "^1.32.7" —— sass处理 3.1
  • "sass-loader": "^12.0.0" —— sass处理 3.1
  • "typescript": "~4.5.5" —— typescript 5.1