Table of Contents generated with DocToc
- 模块打包工具
-
全局安装:不推荐。
-
局部安装:在项目目录中安装
npm i webpack-cli webpack -D
。 -
查看版本:
webpack -v
无法起作用,需要npx webpack -v
。 -
安装特定webpack版本:
npm i webpack-cli webpack@version -D
。 -
webpack-cli作用是在命令行中使用webpack。
-
可以直接使用webpack原始的默认配置文件进行打包
npx webpack entry.js
-
自定义编写
webpack.config.js
默认配置文件进行打包
// 引入path生成路径
const path = require('path')
// CommonJS
module.exports = {
// entry 打包入口文件
entry: './index.js',
// output 输出打包文件
output: {
// 输出文件名
filename: 'bundle.js',
// 输出文件夹名
path: path.resolve(__dirname, 'bundle')
}
}
-
默认文件名必须是
webpack.config.js
,否则需要使用选项--config 配置文件名
进行打包 -
结构优化,把源文件放到src中
-
使用
npm scripts
进行配置webpack命令,代替npx webpack
- Hash:本次打包对应的唯一hash值
- Version:webpack打包版本
- Time:打包耗时
- Asset:打包文件
- Size:打包文件大小
- Chunks:打包文件对应ID值
- Chunk Names:打包文件对应名字
- 如果没有配置
mode
选项则会出现警告,默认是production
,打包的文件会被压缩。
- 模块的打包方案,识别除js文件外的文件模块。
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
options: {
// 占位符[ext] [name] [hash]
name: '[name]_[hash].[ext]',
outputPath: 'images/'
}
}
}]
},
-
url-loader
可以实现file-loader
所有的功能,但会把图片转化为base64
字符串。优点:减少一次HTTP请求,缺点:如果图片大,那么js文件就会大,加载js的时间就会变长,页面加载慢。 -
url-loader
最佳实践:limit
选项进行配置,当大于limit则单独成文件,否则转换成base64字符串。
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
// 占位符[ext] [name] [hash]
name: '[path][name][hash].[ext]',
// 发布目录,在html文件中的src属性中添加,类似CDN
// publicPath: 'https://abc.com/img',
// 配置自定义文件的上下文,默认为 webpack.config.js
// context: '../',
outputPath: 'images',
limit: 10240
}
}
}]
},
-
style-loader css-loader
,style-loader负载挂载,css-loader负责分析css文件的关系。 -
让less或者其他预处理文件加载less-loader和postcss-loader,防止跳过了这两个loader
options: {
importLoaders: 2,
modules: true
}
- 如果需要使用css预处理语言,比如less,则需要它的loader
less-loader
,同时需要css loader。出现多个loader时,执行顺序是从下到上,从右到左。
- 使用
postcss-loader
,需要新建postcss.config.js
,并在其添加插件autoprefixer
// postcss.config.js
const autoprefixer = require('autoprefixer')
module.exports = {
plugins: [
autoprefixer
]
}
// webpack.config.js
{
test: /\.less$/,
use: ['style-loader',
'css-loader',
'less-loader',
'postcss-loader'
]
}
-
css-loader中有一个modules选项,使其为true,导入样式表为style,并将类修改为
style.class
,其中class为样式表中的类。 -
使用模块化CSS会影响CSS中的类名
import avatar from './avatar.jpg';
import style from './layout.less';
let img = new Image();
img.src = avatar;
img.classList.add(style.avatar);
- 下载好字体文件,声明好字体,在
webpack.config.js
中使用file-loader
进行打包。
-
plugin可以在webpack运行到某个时刻的时候,做一些事情
-
html-webpack-plugin
,需要先引用。自动生成html文件,并把打包生成的js自动引入到html文件中。可以使用template
选项做出一个HTML模板,插件会根据模板生成html -
clean-webpack-plugin
,清空上一次打包好的文件夹。
plugins: [new HtmlWebpackPlugin({
// 生成html的模板
template: 'src/index.html'
}), new CleanWebpackPlugin()],
- 可以设置多个入口文件和打包文件
- dist目录下main.js代码出错,sourceMap它是一个映射关系,他知道dist目录下文件出错的行数对应这src目录下的index.js文件的行数。它的作用就是让我们知道src源文件的出错行数。
// source-map,生成一个map映射文件
devtool: 'source-map',
// inline,map映射文件打包到了main.js中
devtool: 'inline-source-map',
// cheap,只需要告诉第几行就好,不需要告诉更详细的的信息
devtool: 'cheap-inline-source-map',
// module,不单告诉打包的src文件错误,也告诉其他第三方库的错误
devtool: 'cheap-module-inline-source-map',
// eval,执行效率最快,但提示的内容可能不全
devtool: 'eval',
// 开发环境推荐
devtool: 'cheap-module-eval-source-map',
// 生产环境推荐
devtool: 'cheap-module-source-map',
-
webpack监听文件:
webpack --watch
-
webpackDevServer:webpack没有内置了devServer,需要下载
// webpack.config.js
devServer: {
contentBase: './dist',
// 浏览器自动打开页面
open: true
},
// package.json
"scripts": {
"start": "webpack-dev-server"
}
- 自己写一个服务器,因为webpackDevServer已经很成熟了,不推荐自己写
- 不重新加载整个页面,只更新部分修改了的内容
// webpack.config.js
devServer: {
contentBase: './dist',
open: true,
hot: true,
// 当HMR失效的时候也不重新加载整个页面
hotOnly: true
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(),
new webpack.HotModuleReplacementPlugin()
],
-
不仅进行语法转换,还要进行API进行转换
-
为了不让webpack变得更复杂,可以新建
.babelrc
文件,写babel的配置选项。
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
// babelrc
{
"presets": [["@babel/preset-env", {
// 并只包含所需的polyfills
"useBuiltIns": "usage",
"corejs": 2,
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
}]]
}
-
减少不需要的代码,只加载那些真正用到的代码.
-
tree shaking
只支持ES Module(静态引入) -
在package.json文件中写入选项
sideEffects
,让那些不需要用到tree shaking功能的模块能正常加载 -
在生产模式下,不需要设置tree shaking,webpack已经为我们做好了。但package.json中还是需要写入
sideEffects
// webpack.config.js,如果是生产环境下,则不需要用到
optimization: {
usedExports: true
},
// package.json
"sideEffects": [
"*.css"
],
- SourceMap更小
- 压缩代码
- 写入不同的config,新建build目录,作为webpack构建的配置文件夹,需要对package.json进行修改config文件的目录。
// webpack.dev.js
const webpack = require('webpack')
const merge = require('webpack-merge')
const commonConfig = require('./webpack.common.js')
const devConfig = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: './dist',
open: true,
hot: true,
// hotOnly: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
optimization: {
usedExports: true
}
}
module.exports = merge(commonConfig, devConfig)
// webpack.prod.js
const merge = require('webpack-merge')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const commonConfig = require('./webpack.common.js')
const prodConfig = {
mode: 'production',
devtool: 'cheap-module-source-map',
plugins: [
new CleanWebpackPlugin(),
],
}
module.exports = merge(commonConfig, prodConfig)
// webpack.common.js,存放开发模式和生产模式的共同配置
- 对公共代码进行代码拆分,如果不使用代码拆分,当页面逻辑发生变化时,又要重新加载公共代码。当使用了代码拆分,只要加载变化的代码文件即可。
// index.js
import _ from 'lodash';
// 业务逻辑
// config
optimization: {
splitChunks: {
chunks: 'all'
}
},
optimization: {
splitChunks: {
chunks: 'all',
// 30kb
minSize: 30000,
minChunk: 1,
// 缓存组,同步代码的时候会生效,分割代码会放到一起
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
// 值越大就放到改组
priority: -10,
},
default: {
priority: -20,
// 检测模块是否已经被打包过了
reuseExistingChunk: true
}
}
}
},
- 事实上,同步加载的代码优化作用并不大,只有使用懒加载才能做到真正的性能优化。
-
需要配合异步加载模块使用,同步加载模块无法实现
-
实际上并不是webpack的内容,而是ES Module的一种模块懒加载方案
-
需要用到
@babel/plugin-syntax-dynamic-import
模块
async function getComponent() {
const { default: _ } = await import(/* webpackChunkName: "lodash" */'lodash');
const element = document.createElement('div');
element.innerHTML = _.join(['Lazy', 'Loading'], '--');
return element;
}
docuemnt.addEventListener('click', () => {
getComponent().then(element => {
document.body.appendChild(element)
})
})
- 每一个文件就是一个chunk
-
prefetch,页面加载完毕后,再去加载那些交互性的代码(也就是那些对页面加载没影响的代码)。
-
配合懒加载(异步加载),可以提高代码使用率。
-
前端性能,多考虑代码使用率
/* webpackPrefetch: true */
- 主要用于生产环境下进行CSS代码分离,需要下载插件
mini-css-extract-plugin
- 压缩CSS:
optimize-css-assets-webpack-plugin
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
// 将style-loader换成MiniCssExtractPlugin.loader
rules: [{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader']
}, {
test: /\.less$/,
use: [MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: true
}
},
'less-loader',
'postcss-loader'
]
}]
-
performance: false
,设置性能问题不需要警告。 -
用户通过普通刷新(F5,不是强制刷新)页面,但文件名还是不变,那么请求文件就不会使用新的文件,只会使用缓存文件。
-
[contenthash]
根据内容而生成的hash值,如果content不变,则hash不变。
// prod config
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js'
}
-
解决webpack打包过程的一些兼容性问题,类似babel-polyfill的作用。
-
需要使用到webpack.ProvidePlugin,自带的插件
- 只是一种打包方式。
// common config
module.exports = (env) => {
if (env && env.production) {
return merge(commonConfig, prodConfig);
} else {
return merge(commonConfig, devConfig);
}
}
// package.json
"build": "webapck --env.production --config ./build/webpack.common.js"
- 应用场景:开发函数库,或者组件库的时候使用。
- PWA,单页面应用:整个应用只有一个HTML文件
- 升级相关技术版本
- 原理:循环多个HtmlWebpackPlugin插件
new HtmlWebpackPlugin({
template: 'src/index.html'
filename: '[name].html'
})
{
test: /\.(html)$/,
use: {
loader: 'html-loader',
options: {
attrs: [':data-src', 'img:src']
}
}
}