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
- 3.1处理sass/scss[可选] ——
- 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
- 5.1.1通过babel处理typescript(推荐)[可选] ——
- 5.1使用babel ——
- 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
如果命令行窗口无错误则环境正常;也可以通过浏览器验证,即输入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");如果命令行窗口无错误则环境正常;也可在浏览器界面查看有无显示。
测试结果: 异常
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" } } - 处理babel (
- "@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" } } - 处理typescript,采用非babel的方式(
- "@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