webpack 懒加载和预加载配置:
// webpack.config.js:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { resolve } = require('path');
const path = require('path'); // 引入 node的核心模块 path,来处理路径
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin');
// 设置 nodejs的环境变量: 决定使用 browserslist的哪个环境
// process.env.NODE_ENV = 'development';
/**
* 缓存:
* 1.babel缓存:
* 设置选项 cacheDirectory: true;
* 作用: 让第二次打包构建速度更快
* 2.文件资源缓存:
* hash: 每次 webpack构建时会生成一个唯一的 hash值。
* 问题: 因为 js和 css同时使用一个 hash值,如果重新打包,会导致所有缓存失效(可能我却只改动一个文件)
* chunkhash: 根据 chunk生成的 hash值。如果打包来源于同一个 chunk,那么 hash值就一样。
* 问题: js和 css的 hash值还是一样的,因为 css是在 js中被引入的,所以同属于一个 chunk
* contenthash: 根据文件的内容生成 hash值,不同文件 hash值一定不一样。
* 作用: 让代码上线运行缓存更好使用
*/
/**
* tree-shaking: 去除无用的代码
* 前提: 1.必须使用 es6模块化; 2.开启 production环境
* 作用: 减少代码体积
* 在 package.json中配置:
* "sideEffects": false, 所有代码都没有副作用(都可以进行 tree-shaking)
* 问题: 可能会把 css / @babel/polyfill (副作用)文件干掉
* "sideEffects": ["*.css", ".less"], 不对 .css, .less文件进行 tree-shaking
*/
/**
* code split(代码分割):
* 总共有三种方式:
* 1.entry配置多入口(多页面应用),每个入口文件打包成为一个 chunk,所以会有多个 js文件输出;
* 2.配置 optimization选项, 将 node_modules中代码单独打包成一个 chunk最终输出;
* 3.在需要引入 js模块文件的文件中使用 import动态导入:
* // 通过 js代码, 让某个文件被单独打包成一个 chunk
* // import动态导入语法(es11): 能将某个文件单独打包
* import('./other').then(({ count }) => {
* // 文件加载成功
* console.log(count);
* }
* ).catch(() => {
* console.log('文件加载失败');
* }
* )
* 作用: 可以拆分为多个 js文件,从而实现多文件并行加载,速度更快
*/
/**
* 懒加载和预加载(js文件):
* 懒加载: 可以理解为延迟加载,触发某些条件的时候才能加载,而不是一开始就加载
* 1.当文件需要时才加载
* document.getElementById('btn').onclick = function() {
* import('./lazy').then(({ lazyVal }) => {
* console.log('点击了');
* console.log(lazyVal);
* });
* }
* 预加载 prefetch: 会在使用之前,提前加载 js文件
* 1.预加载会等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
* 缺点: 预加载兼容性非常差,只能在PC端高版本浏览器中使用,在移动端或ie浏览器中有相当大兼容性问题,故慎用
* document.getElementById('btn').onclick = function() {
* import('./lazy').then(({ lazyVal }) => {
* console.log('点击了');
* console.log(lazyVal);
* });
* }
* 正常加载:
* 1.可以认为是并行加载(同一时间加载多个文件),文件越多加载越慢,而且按照引入的顺序进行加载
*/
// 复用 loader
const commonCssLoader = [
// MiniCssExtractPlugin.loader,这个 loader取代 style-loader,提取 js中的 css成单独文件
MiniCssExtractPlugin.loader,
'css-loader',
// css兼容性处理
{
loader: 'postcss-loader',
options: {
postcssOptions: {
ident: 'postcss',
plugins: [
// postcss的插件
// require('postcss-preset-env')(),这种写法也行
'postcss-preset-env'
]
}
}
}
]
// # webpack性能优化: 1.开发环境性能优化; 2.生产环境性能优化。
// # 开发环境性能优化: 1.优化打包构建速度; 2.优化代码调试。
// # 生产环境性能优化: 1.优化打包构建速度; 2.优化代码运行的性能。
/**
* HMR: hot module replacement 热模块替换/模块热替换
* 作用: 一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度。
* 样式文件: 可以使用 HMR功能,因为 style-loader内部实现了(webpack5以下版本,webpack5+默认开启 HMR)
* js文件: 默认不能使用 HMR,需要修改 js代码,添加支持 HMR功能的代码(webpack5以下版本,webpack5+默认开启 HMR)
* 注意: HMR功能对 js的处理,只能处理非入口 js文件的其他文件
* if(module.hot) {
* // 一旦 module.hot为 true,说明开启了 HMR功能, 让HMR功能代码生效
* module.hot.accept('./xxx.js', function(){
* // 方法会监听 xxx.js文件的变化,一旦发生变化,其他模块不会重新打包构建
* // 会执行后面的回调函数(相关操作)
* xxx();
* })
* }
* html文件: 默认不能使用 HMR功能,同时会导致问题,html文件不能热更新了(webpack5以下版本,webpack5+默认开启 HMR)
* 解决: 修改 entry入口,将html文件引入
*/
/**
* 作用: 指示 webpack所做的事情(当你运行 webpack的命令时,会加载里面的配置);
* 所有构建工具都是基于 nodejs平台运行的,故模块化规范采用 commonjs。
* loader: 1.下载;2.使用(配置loader); plugins: 1.下载;2.引入;3.使用。
* 运行项目指令: 1.npx webpack 或 npm run test 会将打包结果输出;
* 2.npx webpack serve 只会在内存中编译打包,没有输出。
*/
module.exports = {
context: path.resolve(__dirname, './'),
// 必填,webpack执行构建入口起点(打包入口文件路径)
// entry: './src/index.js',
// webpack执行构建入口起点,同时引入 html文件,这样修改 html文件,
// 该 html文件才会热更新(webpack5以下版本,webpack5+不需要这样配置,上面那种entry配置即可)
entry: ['./src/index.js', './example/index.html'],
// 多入口(多页面应用)
// entry: {
// index: './src/index.js',
// other: './src/other.js'
// },
// 输出
output: {
// 将所有依赖的模块合并输出到 built.js(输出文件名)
filename: 'js/built.[contenthash:10].js',
// path 打包出口路径(输出文件的存放路径,必须是绝对路径)
// __dirname nodejs的变量,代表当前文件的目录绝对路径
path: path.resolve(__dirname, './dist'),
},
// loader的配置
module: {
rules: [
/**
* 语法检查: eslint-loader eslint
* 注意: 只检查自己写的源代码,第三方的库是不用检查的
* 设置检查规则: package.json中 eslintConfig中设置~
* "eslintConfig": {
* "extends": "airbnb-base"
* }
* airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint
* npm install -D eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import
* 正常来讲,一个文件只能被一个 loader处理,当一个文件要被多个 loader处理,那么一定要指定 loader执
* 行的先后顺序: 先执行 eslint,再执行 babel
*/
// {
// test: /\.js$/,
// exclude: /node_modules/,
// // 优先执行
// enforce: 'pre',
// loader: 'eslint-loader',
// options: {
// // 自动修复 eslint的错误
// fix: true
// }
// },
{
// 以下 loader只会匹配一个,提升构建速度(同一个文件不会被多个 loader过一遍, 如果匹配一个,后面的 loader就会被忽略)
// 注意: 不能有两个配置处理同一种类型文件,如果确实有这种情况,可只保留一个,
// 其他的 loader提取到外面 rules中,如上面的 eslint-loader
oneOf: [
// 详细 loader配置
{
// 匹配哪些文件
test: /\.css$/,
// 使用哪些 loader进行处理
use: [
// use数组中loader执行顺序: 从右到左,从下到上(即倒序)依次执行
// 创建 style标签,将 js中的样式资源插入进行,添加到 html文件的 head中生效
// 'style-loader',
...commonCssLoader
]
},
{
// 处理 stylus资源
test: /\.stylus$/,
// 使用多个 loader的时候用 use
use: [
// 'style-loader',
...commonCssLoader,
// 将 stylus文件编译成 css文件
'stylus-loader'
]
},
// webpack 5默认会打包图片资源,添加下面配置反而无法显示,webpack5+中已经废弃 url-loader
// {
// // 处理图片资源
// test: /\.(jpg|png|gif)$/,
// // 使用一个 loader
// // 下载 url-loader file-loader(file-loader依赖 url-loader)
// loader: 'url-loader',
// options: {
// // 图片大小小于 8kb,就会被 base64处理
// // 优点: 减少请求数量(减轻服务器压力)
// // 缺点: 图片体积会更大(文件请求速度更慢)
// limit: 8 * 1024,
// // 问题: 因为 url-loader 默认使用 es6模块化解析,而 html-loader 引入图片是 commonjs,解析时
// // 会出现问题 [object Module]
// // 解决: 关闭 url-loader的 es6模块化,使用 commonjs解析
// esModule: false,
// // 默认文件名是一段哈希值+文件名的后缀
// // 给图片进行重命名
// // [hash:10]取图片的 hash的前 10位
// // [name]取文件原始名
// // [ext]取文件原来拓展名
// name: '[hash:10].[ext]'
// }
// },
// 处理图片资源(webpack5+)
{
test: /\.(jpg|png|gif)$/,
// 类型为资源模块类型, assets-module(webpack5+)
type: 'asset',
// 解析
parser: {
// 转base64的条件
dataUrlCondition: {
maxSize: 25 * 1024, // 25kb
}
},
generator: {
filename: 'img/[name]_[hash:8][ext]',
// 打包后对资源的引入, 已经有文件目录 img了
publicPath:'./'
}
},
{
// 处理 html中 img资源
test: /\.html$/,
// 处理 html文件的 img图片(负责引入 img,从而能被 url-loader进行处理)
loader: 'html-loader',
},
// 打包其他资源(除了 html/js/css资源以外的资源)
{
// 排除 css/less/js/html资源
exclude: /\.(jpg|css|less|stylus|js|json|html)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
// 输出到指定的目录
outputPath: 'media',
}
},
/**
* js兼容性处理: babel-loader @babel/core @babel/preset-env
* npm install -D babel-loader @babel/core @babel/preset-env
* 1.基本兼容性处理: @babel/preset-env;
* 问题: 只能转换基本语法,如 promise不能转换
* 2.全部 js兼容性处理: @babel/polyfill(babel 7.4.0开始,这个包已经被废弃);
* npm install -D @babel/polyfill
* 源代码中引入即可, import '@babel/polyfill'
* 问题: 我只要解决部分兼容性问题,但是它会将所有兼容性代码全部引入,导致编译后代码体积太大了
* 3.需要做兼容性处理的就做: 按需加载, core-js
* npm i -D core-js
* 注意: 使用这种方式时, 第2种方式不能再使用
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
/**
* 对应上面第1种方式
*/
// 预设: 指示 babel做怎样的兼容性处理
// presets: ['@babel/preset-env']
/**
* 对应上面第3种方式
*/
// 预设: 指示 babel做怎样的兼容性处理
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定 core-js版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
// 兼容版本为 60及以上
chrome: '60',
firefox: '50',
ie: '9',
safari: '10',
edge: '17',
}
}
]
],
// 开启 babel缓存
// 第二次构建的时候,会读取之前的缓存,从而构建速度更快
cacheDirectory: true
}
}
]
}
]
},
// 模式
// 生产环境下会自动压缩 js代码
mode: 'production', // 生产模式
// mode: 'development', // 开发模式
// 开发服务器 devServer: 用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
// 特点: 只会在内存中编译打包,不会有任何输出
// 安装 webpack-dev-server: npm install -D webpack-dev-server
// 启动 devServer命令为: npx webpack serve(webpack5以下版本,启动指令为 npx webpack-dev-server)
devServer: {
// 项目构建后路径(webpack5+ 不支持,已被弃用)
// contentBase: resolve(__dirname, 'dist'),
// 项目构建后路径(webpack5+)
static: resolve(__dirname, 'dist'),
// 启动 gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true,
// 开启 HMR功能(webpack5以下版本支持,webpack5+设置这个选项值无效,webpack5+默认热更新)
// hot: true,
// 监听 index.html文件变化(webpack5+ 中新增的配置选项,
// 如果不添加就无法监听 index.html文件变化,webpack5以下版本不用添加配置就能监听)
watchFiles: ['./example/index.html']
},
// plugins的配置
plugins: [
// html-webpack-plugin
// 功能: 默认会创建一个空的 html,自动引入输出的所有资源(js/css)
// 需求: 需要有结构的html文件
new HtmlWebpackPlugin({
// 将'./example/index.html'文件作为模板,并自动引入打包输出的所有资源(js/css)
template: './example/index.html',
// 压缩 html代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
}),
new MiniCssExtractPlugin({
// 对输出的 css文件进行重命名
filename: 'css/built.[contenthash:10].css',
}),
// 压缩 css(webpack5以前版本,目前webpack5+仍支持,之后会废弃)
// new OptimizeCssAssetsWebpackPlugin()
// 压缩 css(webpack5+)
new CssMinimizerWebpackPlugin()
],
// 构建目标,默认为 'web',编译为 web环境来加载 chunk
// target有想、两个选项值, 'web'与'node'
target: 'web',
/**
* source-map: 是一种提供源代码到构建后代码映射的技术(如果构建后代码出错了,通
* 过映射可以追踪源代码错误)
* 通常可以[inline- | hidden- | eval-][nosources-][cheap-[module-]]source-map的方式组合
* source-map: 外部 source-map
* 1.追踪到错误代码的准确信息和源代码的错误位置
* inline-source-map: 内联 source-map
* 1.只生成一个内联 source-map; 2.错误代码的准确信息和源代码的错误位置
* hidden-source-map: 外部 source-map
* 1.只隐藏源代码,不隐藏构建后代码; 2.追踪到错误代码错误,但是没有错误位置; 3.不能追踪源代码错误,只能提示到构建后代码的错误位置
* eval-source-map: 内联 source-map
* 1.每一个文件都生成对应的 source-map,都在 eval函数中; 2.追踪到错误代码的准确信息和源代码的错误位置
* nosources-source-map: 外部 source-map
* 1.代码全部隐藏(包括源代码和构建后代码); 2.追踪到错误代码准确信息,但是没有任何源代码信息;
* cheap-source-map: 外部 source-map
* 1.追踪到错误代码的准确信息和源代码的错误位置; 2.只能精确到行,不能精确到某一条语句
* cheap-module-source-map: 外部 source-map
* 1.追踪到错误代码的准确信息和源代码的错误位置
* 内联 source-map与 外部 source-map区别: 1.外部 source-map生成了单独的文件,内联没有; 2.内联构建速度更快
* 开发环境: 一般需要速速快,调试更友好的这种配置
* 速度快(eval > inline > cheap > ...): eval-cheap-source-map, eval-source-map
* 调试更友好: source-map, cheap-module-source-map, cheap-source-map
* 故综合考虑的配置一般为: eval-source-map(vue,react脚手架默认 source-map) / eval-cheap-module-source-map
* 生产环境: 一般需要考虑源代码要不要隐藏,调试要不要更友好(内联会让代码体积变大,所以在生产环境一般不用内联)
* 源代码隐藏: nosources-source-map(全部隐藏), hidden-source-map(只隐藏源代码,会提示构建后代码错误)
* 调试友好: source-map, cheap-source-map, cheap-module-source-map, hidden-source-map, nosources-source-map
* 故综合考虑的配置一般为: source-map / cheap-module-source-map
*/
devtool: 'source-map',
/**
* 1.可以将 node_modules中代码单独打包一个 chunk最终输出;
* 2.如果是多入口,自动分析多入口 chunk中, 有没有公共的文件,如果有会打包成单独一个 chunk,而不会在引用它的文件中重复打包多次。
*/
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
/**
- 使用 dll技术,对某些库(第三方库: jquery、react、vue)进行单独打包
- 打包指令: npx webpack --config webpack.dll.js */