有了vue-cli的帮助,我们创建vue的项目非常的方便,使用vue create
然后选择些需要的配置项就能自动帮我们创建配置好的webpack项目脚手架了,实在是‘居家旅行’必备良药。这次借着学习webpack的机会,不用vue-cli
搭建一个vue项目。
注:基于webpack5,其运行于 Node.js v10.13.0+ 的版本。
完整代码:https://github.com/mashiro-cat/learn_webpack
webpack基础
webpack官网:https://webpack.js.org/
webpack中文官网:https://webpack.docschina.org/
安装:
npm i webpack webpack-cli -D
运行:
npx webpack ./src/main.js --mode=development # 根目录有配置文件 npx webpack
打开文档就能看到五个核心配置点:
- 入口(entry)
- 输出(output)
- loader
- 插件(plugin)
- 模式(mode)
webpack本身只提供了对js中ES Module
和压缩的支持,很多功能都要通过使用loader
或者plugin
拓展。
webpack.config.js配置文件编写:
module.exports = { // 入口 多入口则配置成对象形式 entry:"", // 输出 需使用绝对路径 output:{}, // loader module:{ rules:[] }, // 插件 plugins:[], // development 或者 production // 生产模式默认开启js和html压缩 mode:"development" }
样式资源处理
配置资源输出的路径和名称
输出:
output: { path: path.resolve(__dirname, 'dist'), filename: 'static/js/main.js' // 将js输出到 static/js 目录中 }
module中:
generator: { // 将图片文件输出到 static/imgs 目录中 // 将图片文件命名 [hash:8][ext][query] // [hash:8]: hash值取8位 直接[hash]则不截取 // [ext]: 使用之前的文件扩展名 // [name]: 会使用之前的名字 // [query]: 添加之前的query参数 filename: "static/imgs/[hash:8][ext][query]", },
css处理
安装两个loader,其使用顺序是css-loader会处理css,而将编译的css经style-loader后会动态创建style
标签。
css-loader
# 安装 npm i css-loader style-loader -D
rules: [ // 两个loader顺序按此 它会先使用后面的 { test: /.css$/i, use: ["style-loader", "css-loader"] } ]
提取css到单独文件
现在是css全部是打包到js中,然后动态插入的。若需要提取到单独文件,则可以借助插件。
// 安装插件 npm i mini-css-extract-plugin -D // 配置插件 const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 将styel-loader改为MiniCssExtractPlugin.loader { // 用来匹配 .css 结尾的文件 test: /.css$/, // use 数组里面 Loader 执行顺序是从右到左 use: [MiniCssExtractPlugin.loader, "css-loader"], }, plugins:[ new MiniCssExtractPlugin({ // 定义输出文件名和目录 filename: "static/css/main.css", }), ]
css兼容处理
// 安装 npm i postcss-loader postcss postcss-preset-env -D // 配置 { // 用来匹配 .css 结尾的文件 test: /.css$/, // use 数组里面 Loader 执行顺序是从右到左 use: [ MiniCssExtractPlugin.loader, "css-loader", { // 在css-loader之后,预处理器loader之前 loader: "postcss-loader", options: { postcssOptions: { plugins: [ "postcss-preset-env", // 能解决大多数样式兼容性问题 ], }, }, }, ], },
控制兼容性:
package.json 文件中添加 browserslist 来控制样式的兼容性的程度:
{ // 其他省略 //"browserslist": ["ie >= 8"] // 实际开发中我们一般不考虑旧版本浏览器了,所以我们可以这样设置: // 所有浏览器的最新两个版本 支持市面上99%浏览器 还没死的浏览器 "browserslist": ["last 2 version", "> 1%", "not dead"] }
css压缩
安装插件:
npm i css-minimizer-webpack-plugin -D
webpack配置:
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); plugins:[ // css压缩 new CssMinimizerPlugin(), ]
预处理器
使用less,scss等预处理都要安装对应的loader进行编译,webpack才能识别处理。
less的使用:
// 安装less-loader npm i less-loader -D // 配置 // less-loader将less转为css后还是要交给css-loader处理的 { test: /.less$/, use: ["style-loader", "css-loader", "less-loader"] }
scss, sass的使用:
// 安装 npm i sass-loader sass -D // 配置 { test: /.s[ac]ss$/, use: ["style-loader", "css-loader", "sass-loader"], },
点击查看完整配置
const path = require('path') module.exports = { // 入口 多入口则配置成对象形式 entry: "./src/main.js", // 输出 需使用绝对路径 output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' }, // loader module: { rules: [ // 两个loader顺序按此 它会先使用后面的 { test: /.css$/i, use: ["style-loader", "css-loader"] }, // less-loader将less转为css后还是要交给css-loader处理的 { test: /.less$/, use: ["style-loader", "css-loader", "less-loader"] }, { test: /.s[ac]ss$/, use: ["style-loader", "css-loader", "sass-loader"], }, ] }, // 插件 plugins: [], // development 或者 production mode: "development" }
图片资源处理
Webpack4使用file-loader 和 url-loader处理图片资源,而webpack5将那俩都内置了,直接配置开启就可。
{ test: /.(png|jpe?g|gif|webp)$/, type: "asset", },
将小于某个大小的图片转化成Base64可添加此配置:
{ test: /.(png|jpe?g|gif|webp)$/, type: "asset", parser: { dataUrlCondition: { maxSize: 10 * 1024 // 小于10kb的图片会被base64处理 } } },
点击查看完整配置
const path = require('path') module.exports = { // 入口 多入口则配置成对象形式 entry: "./src/main.js", // 输出 需使用绝对路径 output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' }, // loader module: { rules: [ // 两个loader顺序按此 它会先使用后面的 { test: /.css$/i, use: ["style-loader", "css-loader"] }, // less-loader将less转为css后还是要交给css-loader处理的 { test: /.less$/, use: ["style-loader", "css-loader", "less-loader"] }, { test: /.s[ac]ss$/, use: ["style-loader", "css-loader", "sass-loader"], }, { test: /.(png|jpe?g|gif|webp)$/, type: "asset", parser: { dataUrlCondition: { maxSize: 10 * 1024 // 小于10kb的图片会被base64处理 } } }, ] }, // 插件 plugins: [], // development 或者 production mode: "development" }
其它资源处理
若项目中引用了字体,视频等资源,则是希望不要处理它,直接输出就好了。配置为type: "asset/resource"
它就会原封不动的输出了。
{ // 处理字体图标或者视频等其它资源 test: /.(ttf|woff2?|map4|map3)$/, type: "asset/resource", generator: { filename: "static/media/[hash:8][ext][query]", }, }
点击查看完整配置
const path = require('path') module.exports = { // 入口 多入口则配置成对象形式 entry: "./src/main.js", // 输出 需使用绝对路径 output: { path: path.resolve(__dirname, 'dist'), filename: 'static/js/main.js', // 将js输出到 static/js 目录中 clean: true }, // loader module: { rules: [ // 两个loader顺序按此 它会先使用后面的 { test: /.css$/i, use: ["style-loader", "css-loader"] }, // less-loader将less转为css后还是要交给css-loader处理的 { test: /.less$/, use: ["style-loader", "css-loader", "less-loader"] }, { test: /.s[ac]ss$/, use: ["style-loader", "css-loader", "sass-loader"], }, { test: /.(png|jpe?g|gif|webp)$/, type: "asset", parser: { dataUrlCondition: { maxSize: 10 * 1024 // 小于10kb的图片会被base64处理 } }, generator: { // 将图片文件输出到 static/imgs 目录中 // 将图片文件命名 [hash:8][ext][query] // [hash:6]: hash值取6位 // [ext]: 使用之前的文件扩展名 // [query]: 添加之前的query参数 filename: "static/imgs/[hash:6][ext][query]", }, }, { // 处理字体图标或者视频等其它资源 test: /.(ttf|woff2?|map4|map3)$/, type: "asset/resource", generator: { filename: "static/media/[hash:8][ext][query]", }, }, ] }, // 插件 plugins: [], // development 或者 production mode: "development" }
js资源处理
代码质量检测 Eslint
安装:
npm i eslint-webpack-plugin eslint -D
在webpack配置中使用eslint插件
const ESLintWebpackPlugin = require("eslint-webpack-plugin"); plugins: [ new ESLintWebpackPlugin({ // 指定检查文件的根目录 context: path.resolve(__dirname, "src"), }), ],
编写配置:
配置文件由很多种写法:.eslintrc.*:新建文件,位于项目根目录
- .eslintrc
- .eslintrc.js
- .eslintrc.json
区别在于配置格式不一样package.json 中 eslintConfig:不需要创建文件,在原有文件基础上写,ESLint 会查找和自动读取它们,所以以上配置文件只需要存在一个即可
根目录创建.eslintrc.js
配置文件
// .eslintrc.js module.exports = { // 解析配置项 parserOptions: { ecmaVersion: 6, // ES 语法版本 sourceType: "module", // ES 模块化 }, env: { node: true, // 启用node中全局变量 browser: true, // 启用浏览器中全局变量 不开启则像 console Math 等全局变量无法使用 }, // 继承规则 extends: ['eslint:recommended'], // 检测规则 // 自定义的规则会覆盖继承的规则 // "off" 或 0 - 关闭规则 // "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出) // "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出) rules: { semi: "off", // 禁止使用分号 'array-callback-return': 'warn', // 强制数组方法的回调函数中有 return 语句,否则警告 'default-case': [ 'warn', // 要求 switch 语句中有 default 分支,否则警告 { commentPattern: '^no default$' } // 允许在最后注释 no default, 就不会有警告了 ], eqeqeq: [ 'warn', // 强制使用 === 和 !==,否则警告 'smart' // https://eslint.bootcss.com/docs/rules/eqeqeq#smart 除了少数情况下不会有警告 ], }, }
babel兼容处理
安装:
npm i babel-loader @babel/core @babel/preset-env -D
babel配置编写:
配置文件由很多种写法:
- babel.config.*:新建文件,位于项目根目录
- babel.config.js
- babel.config.json
- .babelrc.*:新建文件,位于项目根目录
- .babelrc
- .babelrc.js
- .babelrc.json
package.json 中 babel:不需要创建文件,在原有文件基础上写
presets 预设:
简单理解:就是一组 Babel 插件, 扩展 Babel 功能
@babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript。
@babel/preset-react:一个用来编译 React jsx 语法的预设
@babel/preset-typescript:一个用来编译 TypeScript 语法的预设
// 创建.babelrc.js module.exports = { presets: ["@babel/preset-env"], };
webpack增加babel
{ test: /.js$/, exclude: /node_modules/, // 排除node_modules代码不编译 loader: "babel-loader", },
html自动导入处理
安装html-webpack-plugin
npm i html-webpack-plugin -D
webpack配置, 配置好后就会自动的引入所需的js了。
const HtmlWebpackPlugin = require("html-webpack-plugin"); plugins: [ new HtmlWebpackPlugin({ // 以 public/index.html 为模板创建文件 // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源 template: path.resolve(__dirname, "public/index.html"), }), ]
webpackSever
使用webpacksever后,在开发时就能自动检测文件变化,并实时编译展示出来了。
// 安装 npm i webpack-dev-server -D // 配置 devServer: { host: "localhost", // 启动服务器域名 port: "3000", // 启动服务器端口号 open: true, // 是否自动打开浏览器 },
运行:
// 此时不会打包生成文件,都是在内存中进行编译的 npx webpack serve
点击查看完整配置
const path = require('path') const ESLintWebpackPlugin = require("eslint-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { // 入口 多入口则配置成对象形式 entry: "./src/main.js", // 输出 需使用绝对路径 output: { path: path.resolve(__dirname, 'dist'), filename: 'static/js/main.js', // 将js输出到 static/js 目录中 clean: true }, // loader module: { rules: [ // 两个loader顺序按此 它会先使用后面的 { test: /.css$/i, use: ["style-loader", "css-loader"] }, // less-loader将less转为css后还是要交给css-loader处理的 { test: /.less$/, use: ["style-loader", "css-loader", "less-loader"] }, { test: /.s[ac]ss$/, use: ["style-loader", "css-loader", "sass-loader"], }, { test: /.(png|jpe?g|gif|webp)$/, type: "asset", parser: { dataUrlCondition: { maxSize: 10 * 1024 // 小于10kb的图片会被base64处理 } }, generator: { // 将图片文件输出到 static/imgs 目录中 // 将图片文件命名 [hash:8][ext][query] // [hash:6]: hash值取6位 // [ext]: 使用之前的文件扩展名 // [query]: 添加之前的query参数 filename: "static/imgs/[hash:6][ext][query]", }, }, { // 处理字体图标或者视频等其它资源 test: /.(ttf|woff2?|map4|map3)$/, type: "asset/resource", generator: { filename: "static/media/[hash:8][ext][query]", }, }, { // babel配置 test: /.js$/, exclude: /node_modules/, // 排除node_modules代码不编译 loader: "babel-loader", }, ] }, // 插件 plugins: [ new ESLintWebpackPlugin({ // 指定检查文件的根目录 context: path.resolve(__dirname, "src"), }), new HtmlWebpackPlugin({ // html处理的插件 // 以 public/index.html 为模板创建文件 // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源 template: path.resolve(__dirname, "public/index.html") }) ], devServer: { host: "localhost", // 启动服务器域名 port: "666", // 启动服务器端口号 open: true, // 是否自动打开浏览器 }, // development 或者 production mode: "development" }
webpack进阶
使用sourcemap
SourceMap(源代码映射)是一个用来生成源代码与构建后代码一一映射的文件的方案。
通过查看Webpack DevTool文档可知,SourceMap 的值有很多种情况.
开发时我们只需要关注两种情况即可:
开发模式:cheap-module-source-map,优点:打包编译速度快,只包含行映射,缺点:没有列映射
生产模式:source-map,优点:包含行/列映射,缺点:打包编译速度更慢。
配置:
devtool: "cheap-module-source-map",
提升打包速度
HotModuleReplacement:它(HMR/热模块替换):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面。
module.exports = { // 其他省略 devServer: { host: "localhost", // 启动服务器域名 port: "3000", // 启动服务器端口号 open: true, // 是否自动打开浏览器 hot: true, // 开启HMR功能(只能用于开发环境,生产环境不需要了) }, };
此时 css 样式经过 style-loader 处理,已经具备 HMR 功能了。 但是 js 可以使用vue-loader, react-hot-loader实现。
OneOf配置(开发和正式都能用):
匹配到一条规则就不继续匹配了
module: { rules: [ { oneOf: [ { test: /.css$/, use: ["style-loader", "css-loader"] }, ......... ] } ] }
Include/Exclude
如在配置babel排除node_moudels
文件夹
使用缓存Cache
每次打包时 js 文件都要经过 Eslint 检查 和 Babel 编译,速度比较慢。我们可以缓存之前的 Eslint 检查 和 Babel 编译结果,这样第二次打包时速度就会更快了
// babel { test: /.js$/, // exclude: /node_modules/, // 排除node_modules代码不编译 include: path.resolve(__dirname, "../src"), // 也可以用包含 loader: "babel-loader", options: { cacheDirectory: true, // 开启babel编译缓存 cacheCompression: false, // 缓存文件不要压缩 }, }, // Eslint new ESLintWebpackPlugin({ // 指定检查文件的根目录 context: path.resolve(__dirname, "../src"), exclude: "node_modules", // 默认值 cache: true, // 开启缓存 // 缓存目录 cacheLocation: path.resolve( __dirname, "../node_modules/.cache/.eslintcache" ), })
打包启用多线程:
开启线程也需要时间,小项目可能提升不明显。
npm i thread-loader -D
安装loader,然后配置:
// nodejs核心模块,直接使用 const os = require("os"); const TerserPlugin = require("terser-webpack-plugin"); // webpack自带的js压缩模块 // cpu核数 const threads = os.cpus().length; // babel使用多线程 { test: /.js$/, // exclude: /node_modules/, // 排除node_modules代码不编译 include: path.resolve(__dirname, "../src"), // 也可以用包含 use: [ { loader: "thread-loader", // 开启多进程 options: { workers: threads, // 数量 }, }, { loader: "babel-loader", options: { cacheDirectory: true, // 开启babel编译缓存 }, }, ], }, // Eslint使用多线程 new ESLintWebpackPlugin({ // 指定检查文件的根目录 context: path.resolve(__dirname, "../src"), exclude: "node_modules", // 默认值 cache: true, // 开启缓存 // 缓存目录 cacheLocation: path.resolve( __dirname, "../node_modules/.cache/.eslintcache" ), threads, // 开启多进程 }), // js压缩使用多线程 optimization: { minimize: true, minimizer: [ // css压缩也可以写到optimization.minimizer里面,效果一样的 new CssMinimizerPlugin(), // 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了 new TerserPlugin({ parallel: threads // 开启多进程 }) ], },
减少的代码体检
Tree Shaking: 默认开启,通常用于描述移除 JavaScript 中的没有使用上的代码。
Babel优化:
@babel/plugin-transform-runtime: 禁用了 Babel 自动对每个文件的 runtime 注入,而是引入 @babel/plugin-transform-runtime 并且使所有辅助代码从这里引用。
// 安装 npm i @babel/plugin-transform-runtime -D // 配置 { loader: "babel-loader", options: { cacheDirectory: true, // 开启babel编译缓存 cacheCompression: false, // 缓存文件不要压缩 plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积 }, },
优化代码运行性能
打包代码分块
Preload / prefetch
使用Core-js
使用PWA
从零开始搭建vue-webpack项目
使用的库:
设置环境变量:
https://www.npmjs.com/package/cross-env
// 安装 npm install --save-dev cross-env // package.json
vue-loder文档: https://vue-loader.vuejs.org/zh/
安装vue-loader
npm i vue npm install -D vue-loader vue-template-compiler module: { rules: [ // ... 其它规则 { test: /.vue$/, loader: 'vue-loader' } ] }, plugins: [ // 请确保引入这个插件! new VueLoaderPlugin() ]
样式处理
style-loader 替换为 vue-style-loader,并安装预处理器loader
npm i -D css-loader vue-style-loader less-loader less-loader sass-loader stylus-loader
设置拓展名自动布局
resolve: { extensions: [".vue", ".js", ".json"], // 自动补全文件扩展名,让vue可以使用 },
Eslint配置指定为vue的
npm i -D @babel/eslint-parser // .eslintrc.js module.exports = { root: true, env: { node: true, }, extends: ["plugin:vue/vue3-essential", "eslint:recommended"], parserOptions: { parser: "@babel/eslint-parser", }, };
Bable配置
npm i -D @vue/cli-plugin-babel // babel.config.js module.exports = { presets: ["@vue/cli-plugin-babel/preset"], };
提供对js的变量,解决页面警告
// 解决页面警告 new DefinePlugin({ __VUE_OPTIONS_API__: "true", __VUE_PROD_DEVTOOLS__: "false", }),
除了以上vue中专用的配置,然后加上less,scss的loader,把前面的html插件加上去。就是一个基本的vue-cli了。完整的配置可以看最前面的仓库链接。
优化
按需引入第三库
如 elment plus 按需引入可参照其官网进行配置
https://yk2012.github.io/sgg_webpack5/
https://vue-loader.vuejs.org/zh/
https://webpack.docschina.org/