Tree Shaking

为什么

开发时我们定义了一些工具函数库,或者引用第三方工具函数库或组件库。
如果没有特殊处理的话我们打包时会引入整个库,但是实际上可能我们可能只用上极小部分的功能。
这样将整个库都打包进来,体积就太大了。

是什么

Tree Shaking 是一个术语,通常用于描述移除 JavaScript 中的没有使用上的代码。
注意:它依赖 **ES Module**

怎么用

Webpack 已经默认开启了这个功能,无需其他配置。

Babel

为什么

Babel 为编译的每个文件都插入了辅助代码,使代码体积过大!
Babel 对一些公共方法使用了非常小的辅助代码,比如 _extend。默认情况下会被添加到每一个需要它的文件中。
你可以将这些辅助代码作为一个独立模块,来避免重复引入。

是什么

@babel/plugin-transform-runtime: 禁用了 Babel 自动对每个文件的 runtime 注入,而是引入 @babel/plugin-transform-runtime 并且使所有辅助代码从这里引用。

怎么用

  1. 下载包

    1. npm i @babel/plugin-transform-runtime -D
  2. 配置 ```javascript const os = require(“os”); const path = require(“path”); const ESLintWebpackPlugin = require(“eslint-webpack-plugin”); const HtmlWebpackPlugin = require(“html-webpack-plugin”); const MiniCssExtractPlugin = require(“mini-css-extract-plugin”); const CssMinimizerPlugin = require(“css-minimizer-webpack-plugin”); const TerserPlugin = require(“terser-webpack-plugin”);

// cpu核数 const threads = os.cpus().length;

// 获取处理样式的Loaders const getStyleLoaders = (preProcessor) => { return [ MiniCssExtractPlugin.loader, “css-loader”, { loader: “postcss-loader”, options: { postcssOptions: { plugins: [ “postcss-preset-env”, // 能解决大多数样式兼容性问题 ], }, }, }, preProcessor, ].filter(Boolean); };

module.exports = { entry: “./src/main.js”, output: { path: path.resolve(dirname, “../dist”), // 生产模式需要输出 filename: “static/js/main.js”, // 将 js 文件输出到 static/js 目录中 clean: true, }, module: { rules: [ { oneOf: [ { // 用来匹配 .css 结尾的文件 test: /.css$/, // use 数组里面 Loader 执行顺序是从右到左 use: getStyleLoaders(), }, { test: /.less$/, use: getStyleLoaders(“less-loader”), }, { test: /.s[ac]ss$/, use: getStyleLoaders(“sass-loader”), }, { test: /.styl$/, use: getStyleLoaders(“stylus-loader”), }, { test: /.(png|jpe?g|gif|webp)$/, type: “asset”, parser: { dataUrlCondition: { maxSize: 10 * 1024, // 小于10kb的图片会被base64处理 }, }, generator: { // 将图片文件输出到 static/imgs 目录中 // 将图片文件命名 [hash:8][ext][query] // [hash:8]: hash值取8位 // [ext]: 使用之前的文件扩展名 // [query]: 添加之前的query参数 filename: “static/imgs/[hash:8][ext][query]”, }, }, { test: /.(ttf|woff2?)$/, type: “asset/resource”, generator: { filename: “static/media/[hash:8][ext][query]”, }, }, { 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编译缓存 cacheCompression: false, // 缓存文件不要压缩 plugins: [“@babel/plugin-transform-runtime”], // 减少代码体积 }, }, ], }, ], }, ], }, plugins: [ new ESLintWebpackPlugin({ // 指定检查文件的根目录 context: path.resolve(dirname, “../src”), exclude: “node_modules”, // 默认值 cache: true, // 开启缓存 // 缓存目录 cacheLocation: path.resolve( dirname, “../node_modules/.cache/.eslintcache” ), threads, // 开启多进程 }), new HtmlWebpackPlugin({ // 以 public/index.html 为模板创建文件 // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源 template: path.resolve(__dirname, “../public/index.html”), }), // 提取css成单独文件 new MiniCssExtractPlugin({ // 定义输出文件名和目录 filename: “static/css/main.css”, }), // css压缩 // new CssMinimizerPlugin(), ], optimization: { minimizer: [ // css压缩也可以写到optimization.minimizer里面,效果一样的 new CssMinimizerPlugin(), // 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了 new TerserPlugin({ parallel: threads, // 开启多进程 }), ] ], // devServer: { // host: “localhost”, // 启动服务器域名 // port: “3000”, // 启动服务器端口号 // open: true, // 是否自动打开浏览器 // }, mode: “production”, devtool: “source-map”, };

  1. <a name="9c45b29c"></a>
  2. ## Image Minimizer
  3. <a name="cf9e9911-2"></a>
  4. ### 为什么
  5. 开发如果项目中引用了较多图片,那么图片体积会比较大,将来请求速度比较慢。
  6. 我们可以对图片进行压缩,减少图片体积。
  7. **注意:如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。**
  8. <a name="5138459f-2"></a>
  9. ### 是什么
  10. `image-minimizer-webpack-plugin`: 用来压缩图片的插件
  11. <a name="6e5fae5e-2"></a>
  12. ### 怎么用
  13. 1. 下载包

npm i image-minimizer-webpack-plugin imagemin -D

  1. 还有剩下包需要下载,有两种模式:
  2. - 无损压缩

npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D

  1. - 有损压缩

npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo -D

  1. > [有损/无损压缩的区别](https://baike.baidu.com/item/%E6%97%A0%E6%8D%9F%E3%80%81%E6%9C%89%E6%8D%9F%E5%8E%8B%E7%BC%A9)
  2. 2. 配置
  3. 我们以无损压缩配置为例:
  4. ```javascript
  5. const os = require("os");
  6. const path = require("path");
  7. const ESLintWebpackPlugin = require("eslint-webpack-plugin");
  8. const HtmlWebpackPlugin = require("html-webpack-plugin");
  9. const MiniCssExtractPlugin = require("mini-css-extract-plugin");
  10. const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
  11. const TerserPlugin = require("terser-webpack-plugin");
  12. const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
  13. // cpu核数
  14. const threads = os.cpus().length;
  15. // 获取处理样式的Loaders
  16. const getStyleLoaders = (preProcessor) => {
  17. return [
  18. MiniCssExtractPlugin.loader,
  19. "css-loader",
  20. {
  21. loader: "postcss-loader",
  22. options: {
  23. postcssOptions: {
  24. plugins: [
  25. "postcss-preset-env", // 能解决大多数样式兼容性问题
  26. ],
  27. },
  28. },
  29. },
  30. preProcessor,
  31. ].filter(Boolean);
  32. };
  33. module.exports = {
  34. entry: "./src/main.js",
  35. output: {
  36. path: path.resolve(__dirname, "../dist"), // 生产模式需要输出
  37. filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
  38. clean: true,
  39. },
  40. module: {
  41. rules: [
  42. {
  43. oneOf: [
  44. {
  45. // 用来匹配 .css 结尾的文件
  46. test: /\.css$/,
  47. // use 数组里面 Loader 执行顺序是从右到左
  48. use: getStyleLoaders(),
  49. },
  50. {
  51. test: /\.less$/,
  52. use: getStyleLoaders("less-loader"),
  53. },
  54. {
  55. test: /\.s[ac]ss$/,
  56. use: getStyleLoaders("sass-loader"),
  57. },
  58. {
  59. test: /\.styl$/,
  60. use: getStyleLoaders("stylus-loader"),
  61. },
  62. {
  63. test: /\.(png|jpe?g|gif|svg)$/,
  64. type: "asset",
  65. parser: {
  66. dataUrlCondition: {
  67. maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
  68. },
  69. },
  70. generator: {
  71. // 将图片文件输出到 static/imgs 目录中
  72. // 将图片文件命名 [hash:8][ext][query]
  73. // [hash:8]: hash值取8位
  74. // [ext]: 使用之前的文件扩展名
  75. // [query]: 添加之前的query参数
  76. filename: "static/imgs/[hash:8][ext][query]",
  77. },
  78. },
  79. {
  80. test: /\.(ttf|woff2?)$/,
  81. type: "asset/resource",
  82. generator: {
  83. filename: "static/media/[hash:8][ext][query]",
  84. },
  85. },
  86. {
  87. test: /\.js$/,
  88. // exclude: /node_modules/, // 排除node_modules代码不编译
  89. include: path.resolve(__dirname, "../src"), // 也可以用包含
  90. use: [
  91. {
  92. loader: "thread-loader", // 开启多进程
  93. options: {
  94. workers: threads, // 数量
  95. },
  96. },
  97. {
  98. loader: "babel-loader",
  99. options: {
  100. cacheDirectory: true, // 开启babel编译缓存
  101. cacheCompression: false, // 缓存文件不要压缩
  102. plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
  103. },
  104. },
  105. ],
  106. },
  107. ],
  108. },
  109. ],
  110. },
  111. plugins: [
  112. new ESLintWebpackPlugin({
  113. // 指定检查文件的根目录
  114. context: path.resolve(__dirname, "../src"),
  115. exclude: "node_modules", // 默认值
  116. cache: true, // 开启缓存
  117. // 缓存目录
  118. cacheLocation: path.resolve(
  119. __dirname,
  120. "../node_modules/.cache/.eslintcache"
  121. ),
  122. threads, // 开启多进程
  123. }),
  124. new HtmlWebpackPlugin({
  125. // 以 public/index.html 为模板创建文件
  126. // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
  127. template: path.resolve(__dirname, "../public/index.html"),
  128. }),
  129. // 提取css成单独文件
  130. new MiniCssExtractPlugin({
  131. // 定义输出文件名和目录
  132. filename: "static/css/main.css",
  133. }),
  134. // css压缩
  135. // new CssMinimizerPlugin(),
  136. ],
  137. optimization: {
  138. minimizer: [
  139. // css压缩也可以写到optimization.minimizer里面,效果一样的
  140. new CssMinimizerPlugin(),
  141. // 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
  142. new TerserPlugin({
  143. parallel: threads, // 开启多进程
  144. }),
  145. // 压缩图片
  146. new ImageMinimizerPlugin({
  147. minimizer: {
  148. implementation: ImageMinimizerPlugin.imageminGenerate,
  149. options: {
  150. plugins: [
  151. ["gifsicle", { interlaced: true }],
  152. ["jpegtran", { progressive: true }],
  153. ["optipng", { optimizationLevel: 5 }],
  154. [
  155. "svgo",
  156. {
  157. plugins: [
  158. "preset-default",
  159. "prefixIds",
  160. {
  161. name: "sortAttrs",
  162. params: {
  163. xmlnsOrder: "alphabetical",
  164. },
  165. },
  166. ],
  167. },
  168. ],
  169. ],
  170. },
  171. },
  172. }),
  173. ],
  174. },
  175. // devServer: {
  176. // host: "localhost", // 启动服务器域名
  177. // port: "3000", // 启动服务器端口号
  178. // open: true, // 是否自动打开浏览器
  179. // },
  180. mode: "production",
  181. devtool: "source-map",
  182. };
  1. 打包时会出现报错:
  1. Error: Error with 'src\images\1.jpeg': '"C:\Users\86176\Desktop\webpack\webpack_code\node_modules\jpegtran-bin\vendor\jpegtran.exe"'
  2. Error with 'src\images\3.gif': spawn C:\Users\86176\Desktop\webpack\webpack_code\node_modules\optipng-bin\vendor\optipng.exe ENOENT

我们需要安装两个文件到 node_modules 中才能解决, 文件可以从课件中找到:

  • jpegtran.exe

需要复制到 node_modules\jpegtran-bin\vendor 下面

jpegtran 官网地址

  • optipng.exe

需要复制到 node_modules\optipng-bin\vendor 下面

OptiPNG 官网地址