Webpack
学习视频: https://www.bilibili.com/video/BV1e7411j7T5?p=1
文章目录
1. 简介
参考链接: https://segmentfault.com/a/1190000017777256
webpack 是前端的一个项目构建工具,它是基于Node.js开发出来的一个前端工具。WebPack可以看做是模块打包器(module bundler),通过分析项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。
为什么要使用webpack?
- JavaScript和CSS的依赖问题。开发过程中,JavaScript和CSS的在页面中的顺序问题,经常会造成CSS没起作用,JavaScript的某个变量和方法找不到。
- 性能优化。一般浏览器请求的文件越多越耗时,请求的文件越大越耗时,尤其是为了前端项目的代码更清晰,结构更合理,我们采用了MVC,MVVM等很多架构分解出了很多JS文件,无疑又拖慢了网页的速度。为了解决这个问题,一般会采用以下两个方案:
(1)、 文件合并。浏览器需要下载多个JS文件,而浏览器是有并发限制,也就是同时并发只能下载几个文件。当需要加载的文件非常多,网页的性能可想而知,所以我们需要合并多个文件以减少文件的数量。
(2)、 文件压缩。我们知道文件越大,下载越慢,而针对JavaScript和CSS,里面的空格,换行这些都是为了让我们读代码时更容易阅读,但是对机器来说,这些对它没有影响。 - 提高开发效率。主要体现在:
(1)、 Vendor前缀。在CSS3使用越来越多的时候,我们都知道一些CSS3的新特性,在不同的浏览器中,CSS有不同的前缀,如果我们手工添加将会很繁琐,而如果使用构建工具,很多构建工具可以自动给我添加CSS的Vendor前缀。关于vendor前缀的学习
(2)、单元测试。JavaScript的单元测试在使用MVC或者MVVM的框架后,变得越来越容易,而单元测试是质量保证的一个很重要的手段,所以在提交之前,使用构建工具自动跑一遍我们的单元测试是非常有必要的,能进一步检测你的项目的健壮性和容错能力。关于MVVM的学习
(3)、代码分析。我们写的JavaScript很多时候会有一些潜在的bug, 比如忘了添加分号,某个变量没有等等,使用一些JavaScript的代码分析工具,可以很好的帮我们检查一些常见的问题。
2. Webpack打包步骤
-
首先安装
node.js
官方网址: https://nodejs.org/zh-cn/
-
初始化项目
npm init -y
-
安装
webpack
和webpack-cli
npm install webpack webpack-cli -D
-
修改
webpack.config.js
文件 -
修改
packjson.json
{ "name": "webpack_study", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack --mode development --watch" // 加上这一行 // --watch 实时监听, 如有改动立刻重新打包 }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "@babel/core": "^7.2.2", "@babel/preset-env": "^7.3.1", "babel-loader": "^8.0.5", "css-loader": "^5.1.3", "style-loader": "^2.0.0", "webpack": "^4.46.0", "webpack-cli": "^3.3.12", "webpack-dev-server": "^3.1.14" } }
-
编写
webpack.config.js
文件 -
下载相关包
-
运行命令
npm run dev
3. Webpack核心及其使用
第一步初始化项目
npm init
第二步创建
webpack.config.js
文件
-
entry
指示webpack以哪个文件作为入口起点开始进行打包
webpack.config.js
文件module.export = { // 入口起点 entry: './src/index.js', }
-
output
webpack应该在哪里输出它所创建的bundle, 如何命名文件
webpack.config.js
文件// resolve用来拼接绝对路径的方法 const { resolve } = require('path') module.exports = { entry: './src/index.js', output: { // 要输出的文件名 filename: 'my-webpack-bundle.js', // 文件存放路径 path: resolve(__dirname, 'dist') } }
-
loader
webpack只能处理
JavaScript
和Json
文件, 其他文件无法处理,loader
可以让webpack能够处理其他类型的文件, 并将它们转换成有效的模块, 以供程序使用.webpack.config.js
文件首先需要安装style-loader, css-loader
npm install style-loader css-loader -D
module.exports = { module: { rules: [ { // 匹配后缀名为css结尾的文件 test: /\.css$/, // 要使用哪些loader处理 // loader执行顺序, 从右到左, 从上到下依次执行 use: [ 'style-loader', // 使用<style>将css-loader内部样式注入到我们的HTML页面 'css-loader' // 将css整合到js中 ] // enforce:'post' 的含义是把该 Loader 的执行顺序放到最后 // enforce 的值还可以是 pre,代表把 Loader 的执行顺序放到最前面 enforce: 'post', } ] } }
-
plugins
loader
用于转换某些类型的模块, 而插件则可以用于执行范围更广的任务. 包括: 打包优化, 资源管理, 注入环境变量.webpack.config.js
文件首先需要安装
html-webpack-plugin
npm install html-webpack-plugin -D
const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { plugins: [ new HtmlWebpackPlugin({ template: './src/template.html' }) ] }
-
mode
模式选项 描述 development
(开发环境)会将 DefinePlugin
中process.env.NODE_ENV
的值设置为development
. 为模块和 chunk 启用有效的名。production
(生产环境)会将 DefinePlugin
中process.env.NODE_ENV
的值设置为production
。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin
,FlagIncludedChunksPlugin
,ModuleConcatenationPlugin
,NoEmitOnErrorsPlugin
和TerserPlugin
。none
不使用任何默认优化选项 webpack.config.js
文件// resolve用来拼接绝对路径的方法 const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode: 'development' // 开发环境 }
4. 打包样式资源
-
编写css文件
html, body { height: 100%; background-color: orange; }
-
编写入口文件
./src/index.js
import './css/index.css' function logName(name) { return `love ${name}` } console.log(logName('chenjiang'));
-
编写
webpack.config.js
文件// resolve用来拼接绝对路径的方法 const { resolve } = require('path') module.exports = { entry: './src/index.js', watch: true, output: { // 要输出的文件名 filename: 'my-webpack-bundle.js', // 文件存放路径 path: resolve(__dirname, 'dist') }, module: { rules: [ { // 匹配后缀名为css结尾的文件 test: /\.css$/, // 要使用哪些loader处理 // loader执行顺序, 从右到左, 从上到下依次执行 use: [ 'style-loader', // 使用<style>将css-loader内部样式注入到我们的HTML页面 'css-loader' // 将css整合到js中 ] } ] }, plugins: [ ], mode: 'development' }
-
下载相关包
npm install webpack webpack-cli -D npm install style-loader css-loader -D
-
修改
packjson.json
同上打包步骤 -
运行命令
npm run dev
-
测试
在
dist
目录创建demo.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="./my-webpack-bundle.js"></script> </body> </html>
-
项目结构
5. 打包HTML资源
-
安装
html-webpack-plugin
插件npm install html-webpack-plugin -D
可能出现的错误:https://blog.csdn.net/weixin_43817992/article/details/110670469
-
编辑
webpack.config.js
// resolve用来拼接绝对路径的方法 const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', watch: true, output: { // 要输出的文件名 filename: 'built.js', // 文件存放路径 path: resolve(__dirname, 'dist') }, module: { rules: [] }, plugins: [ new HtmlWebpackPlugin({ // 默认生成空白的HTML文档, 因此需要一个HTML模板, 并且自动引入模板文件的js,css等资源文件 template: './src/index.html', // 压缩HTML minify: { collapseWhitespace: true, removeComments: true } }) ], mode: 'development' }
-
模板文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>My Name is ChenJiang</h1> </body> </html>
-
修改
packjson.json
同上打包步骤 -
运行命令
npm run dev
-
打包成功后
6. 打包图片资源
第一种: js动态生成的image和css的background-image
的打包
两种打包方式:
- 使用
file-loader
: 一般用来打包较大的图片- 使用
url-loader
: 一般用来打包较小的图片
-
编写模板文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- <link rel="stylesheet" href="css/index.css"> --> </head> <body> <div class="box1"></div> <div class="box2"></div> <img src="./images/23.jpg" alt="icon"> </body> </html>
-
编写
css
文件html, body { height: 100%; } div { width: 200px; height: 200px; margin-left: 25px; float: left; } .box1 { background: url('../images/22.jpg') no-repeat center; } .box2 { background: url('../images/23.jpg') no-repeat center; }
-
编写
webpack.config.js
文件编写好过后, 安装相关插件style-loader, css-loader, file-loader, url-loader, html-webpack-plugin
// resolve用来拼接绝对路径的方法 const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', watch: true, output: { // 要输出的文件名 filename: 'built.js', // 文件存放路径 path: resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(jpg|jpeg|png|gif)$/, use: [ // 第一种使用file-loader打包图片资源 /* { loader: 'file-loader', options: { pulichPath: './dist/images', outputPath: 'images' } } */ // 第二种使用url-loader打包图片资源 { loader: 'url-loader', // 基于file-loader, 因此用url-laoder之前, 需要安装file-loader options: { pulichPath: './dist/images', outputPath: 'images', // 当打包的图片文件小于300 * 1024Byte时, 将图片编译成base64的形式,进行打包。如果大于300 * 1024Byte时,则使用file-loader进行打包 limit: 300 * 1024 } } ] } ] }, plugins: [ new HtmlWebpackPlugin({ // 默认生成空白的HTML文档, 因此需要一个HTML模板 template: './src/index.html' }) ], mode: 'development' }
-
修改
packjson.json
同上打包步骤 -
使用命令进行打包
npm run dev
-
运行结果
小于300k的图片被转换成base64的
遗留问题: HTML中img标签无法正常打包
第二种: HTML中的img标签的图片的打包
使用
html-loader
-
webpack.config.js
文件// resolve用来拼接绝对路径的方法 const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', watch: true, output: { // 要输出的文件名 filename: 'built.js', // 文件存放路径 path: resolve(__dirname, 'dist') }, module: { rules: [ //*********************************** 下面的是专门用来处理HTML文件中的img标签的 ************************************** { test: /\.html$/, // 处理html文件的img图片(负责引入, 从而能被url-loader处理) use: [ 'html-loader' ] } ] }, plugins: [ new HtmlWebpackPlugin({ // 默认生成空白的HTML文档, 因此需要一个HTML模板 template: './src/index.html' }) ], mode: 'development' }
7. 打包其他资源
例如: 字体图标之类的
-
准备字体图标
阿里矢量图标库: https://www.iconfont.cn/
-
入口文件
index.js
import './font/iconfont.css'
-
编写
webpack.config.js
// resolve用来拼接绝对路径的方法 const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', watch: true, output: { // 要输出的文件名 filename: 'built.js', // 文件存放路径 path: resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, // 除了 css js html其他文件 { exclude: /\.(css|js|html)$/, use: [ { loader: 'file-loader', options: { publishPath: './dist/font', outputPath: 'font' } } ] } ] }, plugins: [ new HtmlWebpackPlugin({ // 默认生成空白的HTML文档, 因此需要一个HTML模板 template: './src/index.html' }) ], mode: 'development' }
-
模板文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- <link rel="stylesheet" href="css/index.css"> --> </head> <body> <span class="icon iconfont icon-2"></span> <span class="icon iconfont icon-3"></span> <span class="icon iconfont icon-4"></span> </body> </html>
-
修改
packjson.json
同上打包步骤 -
运行命令
npm run dev
-
项目截图
8. CSS打包到单独文件,前缀,压缩
相关包:
mini-css-extract-plugin
提出css
到单独文件
postcss-loader autoprefixer
配合使用给css
添加前缀,处理兼容的。
cssnano
压缩css
代码关于使用的话可以去npm官网查看
-
编写
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const { resolve } = require('path') module.exports = { entry: './src/index.js', watch: true, output: { // 要输出的文件名 filename: 'built.js', // 文件存放路径 path: resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, // 将css提取到单独的文件 // 'style-loader', // 将css整合到HTML中的style中,因此不用 'css-loader', // 将css整合到js中 'postcss-loader' //添加前缀 ] } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), // 将css提取到单独的文件插件 new MiniCssExtractPlugin({ filename: "css/[name].css" }) ], mode: 'development' }
-
添加
postcss.config.js
文件并编辑module.exports = { plugins: [ // 添加前缀 require('autoprefixer')({ "overrideBrowserslist": [ "> 1%", "last 2 versions", "not ie <= 8", "ios >= 8", "android >= 4.0" ] }), // 压缩代码 require('cssnano')({ preset: "default" }) ] }
-
项目结构,编写代码
-
运行命令
npm run dev
-
运行结果
9. Eslint,es6转换es5
建议去官方文档(npm)查看相关包的使用,更新的太快了
下载包:
npm install eslint-loader eslint-friendly-formatter babel-loader @babel/preset-env -D
-
webpack.config.js
配置const { resolve } = require('path') module.exports = { entry: './src/index.js', watch: true, output: { // 要输出的文件名 filename: 'built.js', // 文件存放路径 path: resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, // 官方包的js不检查 enforce: 'pre', // 两个loader中优先检查 use: [ { loader: 'eslint-loader', options: { formatter: require('eslint-friendly-formatter') // 可以让eslint的错误信息出现在终端上 } } ] }, { test: /\.(js|jsx)$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', // 将高级js转换成浏览器能够识别的 options: { presets: [ ['@babel/preset-env'] // ['@babel/preset-env'] // 目的是告诉loader要以什么规则来转化成对应的js版本 ] } } ] } ] }, plugins: [ ], mode: 'development' }
-
添加
.eslintrc.js
module.exports = { root: true, env: { node: true, }, parserOptions: { parser: 'babel-eslint', ecmaVersion: 6, sourceType: "module" }, rules: { "semi": ["error", "always"], "quotes": ["error", "double"] }, };
-
入口文件
const userName = "chenjiang"; function sayName(name) { console.log(name); } sayName(userName);
-
编译后的文件
eval("var userName = \"chenjiang\";\n\nfunction sayName(name) {\n console.log(name);\n}\n\nsayName(userName);\n\n//# sourceURL=webpack://webpack_study/./src/index.js?");
10. 实时编译修改的文件并自动刷新页面(HMR)
前面用到了
--watch
, 这种只是实时打包
误区:
一开始以为webpack-dev-server能够自动打包, 后面发现只能编译, 且只能在浏览器中可以查看修改代码后的效果, 但是修改的代码并没有重新打包到dist目录下面, 编写完代码还需要打包命令HMR(hot module replacement热模块替换):一个模块发生变化,只会重新编译这一个模块(而不是编译所有模块),极大提升构建速度
使用方法:在
webpack.config.js
文件里的devServer
加上一个hot: true
属性注意:
- 样式文件:可以使用HMR功能:因为style-loader内部实现了
- js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码。HMR功能对js的处理,只能处理
非入口js文件
的其他文件(入口文件import很多模块,每次HMR都会重新引入这些模块,还是会刷新页面的)。- html文件: 默认不能使用HMR功能,开启
hot
过后同时会导致问题:html文件不能热更新了(修改HTML发现不能实时更新了),HTML(不用做HMR功能,因为只有一个HTML文件)
- 处理办法:将HTML作为入口文件
-
webpack.config.js
安装相关模块:
npm install webpack-dev-server --save-dev
const HtmlWebpackPlugin = require('html-webpack-plugin') const { resolve } = require('path') module.exports = { entry: ['./src/index.js', './src/index.html'], output: { // 要输出的文件名 filename: 'built.js', // 文件存放路径 path: resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', // 将css整合到HTML中的style中,因此不用 'css-loader', // 将css整合到js中 ] }, { // 必须要的 test: /\.html$/, loader: 'html-loader' }, ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), ], mode: 'development', devServer: { contentBase: resolve(__dirname, 'dist'), compress: true, port: 8080, open: true, hot: true } }
-
index.js
import "./css/aaa.css"; import "./css/bbb.css"; import sayName from './js/main'; const userName = "chenjiang"; sayName(userName) if (module.hot) { // 只有下面监听的文件,修改了代码才能热更新 module.hot.accept('./js/main', function () { // 会执行后面的回调函数 }) }
-
package.json
"scripts": { "start": "webpack --watch", // 打包 "dev": "webpack serve" // 实时编译 },
-
运行命令
npm run dev
11. source-map
参考文章: https://blog.csdn.net/liwusen/article/details/79414508, https://www.jianshu.com/p/f20d4ceb8827
我们在打包中,将开发环境中源代码经过压缩,去空格,babel编译转化,最终可以得到适用于生产环境的项目代码,这样处理后的项目代码和源代码之间差异性很大,会造成无法debug的问题。
举例来说,如果压缩等处理过的生产环境中的代码出现bug,调试的时候只能定位到压缩处理后的代码的位置,无法定位到开发环境中的源代码。
-
没有配置
source-map
之前:错误显示的就是打包过后的位置, 这样不利于开发人员排bug
-
配置
source-map
// resolve用来拼接绝对路径的方法 const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', watch: true, output: { // 要输出的文件名 filename: 'built.js', // 文件存放路径 path: resolve(__dirname, 'dist'), // chunkName: '' }, module: { rules: [] }, plugins: [ new HtmlWebpackPlugin({ // 默认生成空白的HTML文档, 因此需要一个HTML模板, 并且自动引入模板文件的js,css等资源文件 template: './src/index.html', }) ], mode: 'development', devServer: { contentBase: resolve(__dirname, 'dist'), compress: true, port: 8080, }, devtool: 'source-map' // *********************************************** }
SourceMap又分为多种:
编写
webpack.config.js
, 然后运行命令npx webpack
-
第一种:
source-map
: 会生成map格式的文件,里面包含映射关系的代码 => 外部 -
第二种:
inline-source-map
: 不会生成map格式的文件,包含映射关系的代码会放在打包后生成的代码中 => 内联 -
第三种:
inline-cheap-source-map
: cheap有两种作用:一是将错误只定位到行,不定位到列。二是映射业务代码,不映射loader和第三方库等。
会提升打包构建的速度。 => 内联 -
第四种:
inline-cheap-module-source-map
: module会映射loader和第三方库 => 内联 -
第五种:
eval-source-map
: 每一个文件的eval都生成对应的source-map,都在eval, 错误代码准确信息 和 源代码的错误位置 => 内联
内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
推荐方式: 开发环境:
devtool: 'cheap-module-eval-source-map'
, 生产环境:devtool: 'cheap-module-source-map',
-
12. babel缓存
- 开启babel缓存,在第二次打包时,打包构建速度更快
- babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率
- 提高服务器访问速度, 因为第二次是从内存读取, 而不是重新加载
-
webpack.config.js
打开缓存// resolve用来拼接绝对路径的方法 const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { entry: './src/index.js', output: { // 要输出的文件名 filename: 'built.js', // 文件存放路径 path: resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', options: { presets: [ ['@babel/preset-env', { targets: "defaults" }] // 目的是告诉loader要以什么规则来转化成对应的js版本 ], cacheDirectory: true // **************************开启缓存******************************* } } ] }, { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader' ] } ] }, plugins: [ new HtmlWebpackPlugin({ // 默认生成空白的HTML文档, 因此需要一个HTML模板, 并且自动引入模板文件的js,css等资源文件 template: './src/index.html', }), new MiniCssExtractPlugin({ filename: 'css/[name].css' }) ], mode: 'development', devServer: { contentBase: resolve(__dirname, 'dist'), compress: true, port: 8080, }, }
-
创建一个服务器
const express = require('express') const app = express() app.use(express.static('dist', { maxAge: 1000 * 60 })) app.listen(3000, () => { console.log('服务器启动中...'); })
-
访问:
localhost:3000
第一次访问:
第二次访问:
第一次访问的时候, 会加载相关js和css文件
第二次访问的话, 首先浏览器会去看看有没有相关文件的缓存, 如果有的话直接读取缓存, 不会重新加载, 这样大大提高了加载速度
出现问题
我修改了文件, 然后重新打包, 刷新页面, 发现页面并没有改变
原因: 由于加载的文件名没有改变, 在缓存时间内浏览器在缓存还可以找到, 就不会重新发送请求
解决办法: 每次打包给js和css等资源文件, 加上一个随机码, 每次访问页面, 浏览器看到请求的文件名不同, 就会重新加载, 第二次就不会加载, 直接读取缓存
第一种: 使用
hash
添加一个hash值(所有的js和css都是一样的hash值), 每次重新打包hash值都不一样, 那么浏览器查找不到对应的缓存, 就会重新加载
缺点: 如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件), 造成加载速度丢失
webpack.config.js
output: { // 要输出的文件名 filename: 'built.[hash:10].js', }, plugins: [ new MiniCssExtractPlugin({ filename: 'css/[name][hash:10].css' }) ],
第二种:
chunkhash
根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样
所有文件都在入口文件中引入, chunk入口文件, 那么里面的所有文件也就属于此chunk, js和css的hash值还是一样的, 因此修改一个文件, 其他缓存都会失效
webpack.config.js
output: { // 要输出的文件名 filename: 'built.[chunkhash:10].js', }, plugins: [ new MiniCssExtractPlugin({ filename: 'css/[name][chunkhash:10].css' }) ],
第三种:
contenthash
根据文件的内容生成hash值, 不同文件hash值一定不一样
webpack.config.js
output: { // 要输出的文件名 filename: 'built.[contenthash:10].js', }, plugins: [ new MiniCssExtractPlugin({ filename: 'css/[name][contenthash:10].css' }) ],
修改css文件过后: 内容修改了,就会重新生成hash值, 这样就避免了, 修改一个文件, 其他缓存都会失效
13. tree shaking
作用: 去除无用的代码, 减少代码体积
使用前提条件: 必须使用ES6模块化, 开启production环境
process.env.NODE_ENV = 'production'
使用方法: 在
package.json
文件中配置"sideEffects"
属性
package.json
文件
"sideEffects": false
/*
会出现的问题: 入口文件中的css文件, 无法打包, 因为js里面没有调用css文件的代码, 因此会被认为是无用代码
*/
// 处理方法
"sideEffects": ["*.css"]
14. code split
常规情况下,所有的文件都在入口文件引入,然后打包,但是最后只生成一个bundle文件,这样这个文件体积就会很大
我们就需要把入口文件里面所引入的文件,也单独打包出来(例如:入口文件我引入了jQuery,由于体积很大,我想把它单独打包)而不是一起整合到入口文件所打包的文件中
-
第一种方式
使用多入口文件, 这样就可以生成多个chunk
entry:{ index: './src/js/index.js', index2: './src/js/index2.js' }
-
第二种方式
webpack.config.js
文件中添加optimization
属性作用:
- 可以将引入的node_modules中的代码单独打包成一个bundle
- 如果有多个入口文件, 它就会自动分析有没有公共文件, 如果有的话就会打包成一个单独的bundle(文件共用, 提高性能)
// 一般很少用多入口文件 optimization:{ splitChunks:{ chunks: 'all' } }
-
第三种方式(常用)
单入口文件 +
optimization
+ js代码
webpack.config.js文件optimization: { splitChunks: { chunks: 'all' } }
15. 懒加载和预加载
懒加载: 有些文件里面存放的是功能函数,只有等到我需要用到这个函数的时候再加载,而不是一开始将所有的文件都一起加载进来。
懒加载使用方法:
optimization
+ js代码 (为什么要使用代码分隔:个人理解,因为后面要加载对应的js文件,因此要单独拿出来,才能按文件加载)预加载:
webpackPerfetch
会在使用之前,提前加载js文件,等其他主要资源加载完毕,浏览器空闲下来,再加载
-
index.js入口文件
let oBtn = document.querySelector("#btn"); oBtn.addEventListener("click", function() { import( /* webpackChunkName: 'aJS', webpackPerfetch: true */ './js/a') .then(({ add }) => { console.log(add(1, 2)); }) .catch(err => { console.log('文件加载失败'); }) })