第webpack 简介
webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。
webpack 看来, 前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。
案例地址: https://github.com/pengjunshan/WebPJS/StudyWebpack
其它Web文章
CSS浮动的使用和解决浮动的五种方法
CSS定位relative、absolute、fixed使用总结
原生开发WebApi知识点总结
开发中常用jQuery知识点总结
C3动画+H5+Flex布局使用总结
ES6常用知识总结
Vue学习知识总结
待续......
本编文章会讲到的知识点
- webpack初体验
- 常用命令
- HelloWebpack
- webpack开发环境配置
- 打包html资源
- 单页面和多页面配置
- 打包css资源
- 打包图片资源
- 打包其它资源
- devServer自动化
- 文件归类配置
- webpack生产环境配置
- 提取css样式文件
- css兼容性处理
- 压缩css
- js语法检查
- js兼容性处理
- js和html压缩
- 生产环境配置
- webpack优化环境配置
- HMR
- source-map
- oneOf
- 缓存
- tree shaking
- code split
- 懒加载
- PWA
- 多进程打包
- externals
- dll
- optimization
- 常用辅助工具
- resolve
- watch监控
- 清除dist文件
- copy文件到dist
- BannerPlugin声明
- 定义全局变量
- webpack-merge
webpack初体验
常用命令
了解yarn和npm命令,至于yarn和npm的区别我就不多说.
npm | yarn | 功能 |
---|---|---|
npm i | yarn | 构建项目 |
npm init -y | yarn init -y | 初始化项目 |
npm i vue -s | yarn add vue | 局部安装(会打包到代码中) |
npm i vue -d | yarn add vue -d | 局部安装(不会打包到代码中) |
npm i vue -g | yarn add vue -g | 全局安装依赖包 |
- npm i xx -S和yarn add xx
会在package.json的dependencies属性下添加xx依赖包,生产环境需要用到的依赖包,比如vue、jquery项目运行时需要用的库。
- npm i xx -D和yarn add xx -D
会在package.json的devDependencies属性下添加xx依赖包,生产环境不需要用到的依赖包,比如css-loader、less-loader转换css的依赖包。
- npm i xx -g和yarn add xx -g
安装模块到全局,不会在项目node_modules目录中保存模块包。不会将模块依赖写入devDependencies或dependencies 节点。
比如用npm安装yarn: npm install yarn -g
HelloWebpack
1.新建一个文件夹 初始化项目,会生成一个package.json文件
yarn init -y
或者npm init -y
2.安装webpack webpack-cli依赖包
yarn add webpack webpack-cli -D
或者npm i webpack webpack-cli -D
package.json下会生成devDependencies中会有webpack、webpack-cli
{
"name": "StudyWebpack",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11"
}
}
3.项目中新建src文件夹,src文件夹下新建index.js
4.项目中新建webpack.config.js文件
5.在webpack.config.js中写配置项
module.exports = {
mode:'development',//开发环境 development:开发环境 production:生成环境
entry:'./src/index.js',//入口文件
output:{//出口配置
filename:'index.js',//出口文件名
path:__dirname+'/dist'//出口路径
}
}
6.在项目下打开命令行窗口,运行npx webpack命令,webpack项目会自动先找到webpack.config配置项,然后根据配置信息进行打包,成功后项目中会多个dist文件,dist就是打包输出的结果。
7.注意:只要修改了webpack.config.js文件就要重新
webpack开发环境配置
打包html资源
1.安装 html-webpack-plugin
yarn add html-webpack-plugin -D
或者npm i html-webpack-plugin -D
2.在webpack.config.js中引入html-webpack-plugin插件并配置使用。详情看代码注释!
/*
插件的使用步骤:
plugins: 1. 下载 2. 引入 3. 使用
*/
//引入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//模式
mode:'development',
//入口
entry:'./src/index.js',
//出口
output:{
filename:'bundle.js',//文件名
path:__dirname+'/dist'//出口路径
},
//配置插件
plugins:[
// 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
// 需求:需要有结构的HTML文件
new HtmlWebpackPlugin({
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
template:'./src/index.html'
})
]
}
3.运行npx webpack 打包项目,dist文件下会生成index.html文件,并且index.html中自动引入了bundle.js文件
单页面和多页面配置
entry: 入口起点
方式一:单入口 string -->'./src/index.js'
打包形成一个chunk。 输出一个bundle文件。此时chunk的名称默认是 main。多入口 array -->['./src/index.js','./src/add.js']
所有入口文件最终只会形成一个chunk, 输出出去只有一个bundle文件。方式三:多入口 object{index:'./src/index.js', add:'./src/add.js'}
有几个入口文件就形成几个chunk,输出几个bundle文件,此时chunk的名称是 key。
module.exports = {
mode: 'development',
// entry:'./src/index.js',方式一
// entry:['./src/index.js','./src/add.js'],方式二
entry: {//方式三
index: './src/index.js',
add: './src/add.js',
home:'./src/home.js'
},
//出口
output: {
//文件名 [name]根据入口的名称定义
filename: 'js/[name].js',
//输出文件目录(将来所有资源输出的公共目录)
path: __dirname + '/dist',
// 所有资源引入公共路径前缀
publicPath: '/',
// 非入口chunk的名称
chunkFilename: 'js/[name]_chunk.js',
// library: '[name]', // 整个库向外暴露的变量名
// libraryTarget: 'window' // 变量名添加到哪个上 browser
// libraryTarget: 'global' // 变量名添加到哪个上 node
// libraryTarget: 'commonjs'
},
plugins: [
//多出口 一般和多入口对应
new HtmlWebpackPlugin({
template: './src/index.html',
filename:'index.html',
//只引入index.js,不指定的话会引入index、home.js
chunks:['index']
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename:'home.html',
chunks:['home']
}),
]
}
打包css资源
1.安装css-loader style-loader less-loader less,我这里只介绍css和less其它样式用同样的配置。
yarn add css-loader style-loader less-loader less -D
2.配置webpack.config.js,在module中配置css-loader和lessloader。详情看代码注释
//引入插件
const HtmlWbpackPlugin = require('html-webpack-plugin')
module.exports = {
//模式
mode:'development',//开发环境 development:开发环境 production:生成环境
//入口
entry:'./src/index.js',
//出口
output:{
filename:'bundle.js',//出口文件名
path:__dirname+'/dist'//出口文件路径
},
//插件配置
plugins:[
new HtmlWbpackPlugin({
template:'./src/index.html',//配置一个模板html
name:'index.html'//生成的html名称
})
],
//loader配置
module:{
//rules是个数组,因为不同的配置需要不同的loader处理
rules:[
{
//匹配以.css结尾的文件
test:/\.css$/,
// use数组中loader执行顺序:从右到左,从下到上 依次执行
use:[
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
},
{
//匹配以.less结尾的文件
test:/\.less$/,
use:[
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader',
// 将less文件编译成css文件
'less-loader'
]
}
]
}
}
打包图片资源
1.安装loader,html-loader url-loader file-loader
yarn add file-loader url-loader html-loader -d
2.配置webpack.config,详情看代码注释。
解决使用html-loader处理html中引入图片失效,解决方法在url-loader中的options对象中中添加esModule:false属性。
const HtmlWebpckPlugin = require('html-webpack-plugin')
module.exports = {
mode:'development',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:__dirname+'/dist'
},
plugins:[
new HtmlWebpckPlugin({
template:'./src/index.html',
name:'idnex.html'
})
],
module:{
rules:[
{
test:/\.less$/,
use:[
'style-loader',
'css-loader',
'less-loader'
]
},
{
//匹配图片结尾的文件,可手动添加
test:/\.(png|jpg|jpeg|gif)/,
// 使用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位
// [ext]取文件原来扩展名
name: '[hash:10].[ext]'
}
},
{
//匹配.html结尾的文件
test:/\.html/,
// 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
loader:'html-loader'
}
]
}
}
打包其它资源
1.使用exclude属性,排除法
2.配置webpack.config,详情看代码注释
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bunder.js',
path: __dirname + '/dist'
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
name: 'index.html'
})
],
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
//处理其它资源
{
//excude排除法 后期手动添加
exclude: /\.(css|js|html|less|png|jpg|jpeg|gif)$/,
//使用file-loader
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
]
}
}
devServer自动化
开发服务器 devServer后,只会在内存中编译打包,不会有任何输出;自动编译,自动打开浏览器,修改代码后自动刷新浏览器;
1.安装webpack-dev-server
yarn add webpack-dev-server -D
方法一:配置webpack.config,详细配置请看代码注释
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode:'development',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:__dirname+'/dist'
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html',
})
],
// 开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
// 特点:只会在内存中编译打包,不会有任何输出
// 启动devServer指令为:npx webpack-dev-server
devServer: {
// 项目构建后路径
contentBase:__dirname+'/dist',
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true
}
}
方法二:在wepack.json中配置scripts
{
"name": "StudyWebpack",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "webpack",//打包
"dev": "webpack-dev-server --open --port 3000 --host"//开发服务器 devServer
}
文件归类配置
当src下的文件很多时显得很乱,应当给相应的文件归类;
- outputPath属性为loader处理后的文件增加文件夹归类
- output输出对象中 filename:'js/bundle.js',增加js文件夹
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// 模式
mode:'development',
// 入口
entry:'./src/js/index.js',
// 出口
output:{
filename:'js/bundle.js',//输出路径增加js文件夹
path:__dirname+'/dist'
},
//devServer自动化
devServer:{
contentBase:__dirname+'/dist',
compress:true,
port:3000,
open:true
},
// 插件配置
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
// loader配置
module:{
rules:[
{ // 处理css
test:/\.css$/,
use:[
'style-loader',
'css-loader'
]
},
{ //处理less
test:/\.less$/,
use:[
'style-loader',
'css-loader',
'less-loader'
]
},
{ //处理图片
test:/\.(png|jpg|jpeg|gif)/,
loader:'url-loader',
options:{
limit: 8*1024,
name:'[hash:10].[ext]',
exModule:false,
outputPath:'imgs'//图片输出增加imgs文件夹
}
},
{ //处理html中图片
test:/\.html$/,
loader:'html-loader'
},
{ //处理其它文件
exclude:/\.(css|html|js|less|png|jpg|jpeg|gif)/,
loader:'file-loader',
options:{
name:'[hash:10].[ext]',
outputPath:'media'//其它文件增加输出文件夹
}
}
]
}
}
webpack生产环境配置
提取css样式文件
1.安装mini-css-extract-plugin插件
yarn add mini-css-extract-plugin -D
2.配置webpack.config,详情看代码注释
const HtmlWebpackPlugin = require('html-webpack-plugin')
//1.引入mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
mode:'development',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:__dirname+'/dist'
},
module:{
rules:[
{
test:/\.css$/,
use:[
// 'style-loader',
//3. 这个loader取代style-loader。作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test:/\.less$/,
use:[
// 'style-loader',
//3. 这个loader取代style-loader。作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
//2.配置插件
new MiniCssExtractPlugin({
//对输出的css文件进行文件夹配置和重命名
filename:'css/bundle.css'
})
]
}
css兼容性处理
1.安装postcss-loader postcss-preset-env
yarn add postcss-loader postcss-preset-env -D
2.package.json中配置browserslist
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
3.配置webpack.config,详情看代码注解
const HtmlWebpackPlugin = require('html-webpack-plugin')
//1.引入mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 设置nodejs环境变量 默认是production环境
// process.env.NODE_ENV = 'development';
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 'style-loader',
//3. 这个loader取代style-loader。作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
'css-loader',
//帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
{
// 使用loader的默认配置
// 'postcss-loader',
// 修改loader的配置
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss 的插件
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
//2.配置插件
new MiniCssExtractPlugin({
//对输出的css文件进行文件夹配置和重命名
filename: 'css/bundle.css'
})
]
}
压缩css
1.安装optimize-css-assets-webpack-plugin插件
yarn add optimize-css-assets-webpack-plugin -D
2.配置webpack.config,详情看代码注释
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
//1.引入optimize-css-assets-webpack-plugin
const OptimizeCssAssetsWebapckPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/bundle.css'
}),
//2.配置插件optimize-css-assets-webpack-plugin
new OptimizeCssAssetsWebapckPlugin()
]
}
js语法检查
1.安装 eslint,eslint-loader,eslint-config-airbnb-base,eslint-plugin-import
yarn add eslint eslint-loader eslint-config-airbnb-base eslint-plugin-import
2.package.json中配置eslintConfig
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
}
3.配置webapck.config,详情解释看代码注释
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode:'development',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:__dirname+'/dist'
},
module:{
rules:[
{
// 匹配以.js结尾的文件
test:/\.js$/,
// 排除node_modules下的文件,只检查自己写的代码,不检查第三方的代码
exclude:/node_modules/,
loader:'eslint-loader',
options:{
//自动修复eslint错误
fix:true
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
}
js兼容性处理
1.安装babel-loader @babel/core @babel/preset-env core-js
yarn add babel-loader @babel/core @babel/preset-env core-js -D
2.配置webpack.config,详情解释看代码注释
module: {
rules: [
/*
js兼容性处理:babel-loader @babel/core
1. 基本js兼容性处理 --> @babel/preset-env
问题:只能转换基本语法,如promise高级语法不能转换
2. 全部js兼容性处理 --> @babel/polyfill
问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了~
3. 需要做兼容性处理的就做:按需加载 --> core-js,就不需要@babel/polyfill包了
*/
{
// 匹配以.js结尾的文件
test: /\.js$/,
// 排除node_modules下的文件,只检查自己写的代码,不检查第三方的代码
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 预设:指示babel做怎么样的兼容性处理
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
}
]
}
js和html压缩
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
//生产环境下js代码自动压缩
mode:'production',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:__dirname+'/dist'
},
module:{
rules:[
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩html代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
})
]
}
生产环境配置
css和less有公共的loader代码,可以抽离公共loader代码,以对象扩展的方式引入;正常来讲,一个文件只能被一个loader处理,当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:先执行eslint 在执行babel;
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 抽离css插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 压缩css插件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
},
module: {
rules: [
{
// 处理css
test: /\.css$/,
use: [...commonCssLoader]
},
{
//处理less
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {version: 3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename: 'css/bundle.css'
}),
new OptimizeCssAssetsWebpackPlugin()
]
}
webpack优化环境配置
HMR
作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块) 极大提升构建速度;
样式文件:可以使用HMR功能:因为style-loader内部实现了;
js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码; 注意:HMR功能对js的处理,只能处理非入口js文件的其他文件;
html文件: 默认不能使用HMR功能.同时会导致问题:html文件不能热更新了~ (不用做HMR功能);解决:修改entry入口,将html文件引入;
devServer: {
contentBase: __dirname+'/dist',
compress: true,
port: 3000,
open: true,
// 模块热替换
// hot: true
}
source-map
source-map: 一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
source-map:外部
错误代码准确信息 和 源代码的错误位置
inline-source-map:内联
只生成一个内联source-map,错误代码准确信息 和 源代码的错误位置
hidden-source-map:外部
错误代码错误原因,但是没有错误位置,不能追踪源代码错误,只能提示到构建后代码的错误位置
eval-source-map:内联
每一个文件都生成对应的source-map,都在eval, 错误代码准确信息 和 源代码的错误位置
nosources-source-map:外部
错误代码准确信息, 但是没有任何源代码信息
cheap-source-map:外部
错误代码准确信息 和 源代码的错误位置 ,只能精确的行
cheap-module-source-map:外部
错误代码准确信息 和 源代码的错误位置 ,module会将loader的source map加入
内联 和 外部的区别:
- 外部生成了文件,内联没有
- 内联构建速度更快
开发环境:速度快,调试更友好
速度快(eval>inline>cheap>...)
eval-cheap-souce-map
eval-source-map
调试更友好
souce-map
cheap-module-souce-map
cheap-souce-map
综合推荐:eval-source-map / eval-cheap-module-souce-map
生产环境:源代码要不要隐藏? 调试要不要更友好
内联会让代码体积变大,所以在生产环境不用内联
综合推荐:source-map / cheap-module-souce-map
// 开发模式
mode: 'development',
devtool:'eval-source-map'
//生产模式
mode: 'production',
devtool:'source-map'
oneOf
在不使用oneOf之前,一个文件被一个loader匹配到后还会继续向下匹配其它匹配不了的loader,这样性能不好,使用oneOf后当一个文件被一个loader匹配到后就不会向下继续匹配了;但是使用oneOf只会匹配一个loader,所以如果设置了一个文件两个loader的话需要分开写,不能写在同一个oneOf里面。
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只会匹配一个
// 注意:不能有两个配置处理同一种类型文件
oneOf: [
{
// 处理css
test: /\.css$/,
// 配置多个loader使用use
use: [...commonCssLoader]
},
{
//处理less
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
{
test: /\.js$/,
exclude: /node_modules/,
// 配置单个loader使用loader
loader: 'babel-loader',
// 排除node_modules下的js
exclude: /node_modules/,
// 只匹配src下的js
include: __dirname + '/src',
// 优先执行
enforce: 'pre',
// 延后执行
enforce: 'post',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
}
]
}
缓存
当已经加载了js或css等其它后,再次使用的时候不需要再次进行请求了,而是使用缓存后的文件;
hash: 每次wepack构建时会生成一个唯一的hash值。
1.问题: 因为js和css同时使用一个hash值。
2.如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)
chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样。
1.问题: js和css的hash值还是一样的。
2.因为css是在js中被引入的,所以同属于一个chunk。
contenthash:根据文件的内容生成hash值。不同文件hash值一定不一样。
1.让代码上线运行缓存更好使用
/*
缓存:
babel缓存
cacheDirectory: true
--> 让第二次打包构建速度更快
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory:true
}
}
tree shaking
tree shaking:去除无用代码
前提:1. 必须使用ES6模块化 2. 开启production环境
作用: 减少代码体积
sideEffects配置
"sideEffects": false :所有代码都都可以进行tree shaking
副作用:可能会把css / @babel/polyfill 文件干掉;
"sideEffects": [".css", ".less"]跳过css、less文件(如果压过没有使用css也会打包进去)
code split
[name]:取入口文件的名称;
optimization:
- 可以将node_modules中代码单独打包一个chunk最终输出
- 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
懒加载
当一个index.js中引入了其它js文件,进入index.js时不希望立马加载其它js,用到其它js时再加载;
//当点击按钮时再加载utils.js文件
document.querySelector('#btn').onclick = function(){
// 懒加载~:当文件需要使用时才加载~
// 预加载 prefetch:会在使用之前,提前加载js文件 webpackPrefetch: true
// 正常加载可以认为是并行加载(同一时间加载多个文件)
// 预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
// 慎用预加载,兼容性问题,移动端和低版本浏览器不支持
import(/* webpackChunkName: 'test' */'./utils').then(({getName})=>{
console.log(getName())
})
}
PWA
1.安装workbox-webpack-plugin
yarn add workbox-webpack-plugin -D
2.plugins数组中加载插件
plugins: [
...
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 帮助serviceworker快速启动
2. 删除旧的 serviceworker
生成一个 serviceworker 配置文件~
*/
clientsClaim: true,
skipWaiting: true
})
]
/*
1. eslint不认识 window、navigator全局变量
解决:需要修改package.json中eslintConfig配置
"env": {
"browser": true // 支持浏览器端全局变量
}
2. sw代码必须运行在服务器上
--> nodejs
-->
npm i serve -g
serve -s dist 启动服务器,将dist目录下所有资源作为静态资源暴露出去
*/
// 注册serviceWorker
// 处理兼容性问题
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then(() => {
console.log('sw注册成功了~');
})
.catch(() => {
console.log('sw注册失败了~');
});
});
}
多进程打包
webpack是单线程模型的,也就是说Webpack一个时刻只能处理一个任务,不能同时处理多个任务。使用thread-loader进行多进程打包。
1.安装thread-loader
注意:把这个 thread-loader 放置在其他 loader 之前,options中放一些属性值;进程启动大概为600ms,进程通信也有开销;只有工作消耗时间比较长,才需要多进程打包;
yarn add thread-loader -D
2.配置js loader
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader:'thread-loader',
options:{
workers:2//设置进程数量
}
},
{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
]
}
}
]
}
externals
当html中引入了cdn第三方库,js中也Import导入了同个第三方库,我们就可以使用externals来配置打包;
//html中引入jquery的cdn
//js中导入了jquery
import $ from 'jquery'
//webpack.config配置移除jquery打包进去
// 移除某些包被打包进来
externals:{
jquery:'jQuery'
}
dll
使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包,然后再主项目中进行打包时直接引用就可以了,从而加快了打包速度。
1.新建webpack.dll.js文件
2.配置webpack.dll.js
const webpack = require('webpack')
module.exports = {
//需要打包的第三方库
entry:{
jquery:['jquery'],
// vue:['vue']
},
output:{
filename:'[name].js',
path:__dirname+'/dll',
library:'[name]_[hash:10]'// 打包的库里面向外暴露出去的内容叫什么名字
},
plugins:[
// 打包生成一个 manifest.json --> 提供和jquery映射
new webpack.DllPlugin({
name:'[name]_[hash:10]',//映射库暴露出的名称
path:__dirname+'/dll/manifest.json'//文件地址
})
],
mode: 'production'
}
3.配置好webpack.dll.js后运行webpack --config webpack.dll.js命令行,项目下会生成dll文件夹,dll文件夹下会有第三方库的js和manifest.json文件;
4.安装add-asset-html-webpack-plugin插件
yarn add add-asset-html-webpack-plugin -D
5.配置webpack.config
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
module.exports = {
mode:'production',//开发环境 development:开发环境 production:生成环境
plugins:[
// 告诉webpack哪些库不参与打包,同时使用时的名称也得变~
new webpack.DllReferencePlugin({
manifest:__dirname+'/dll/manifest.json'
}),
// 将某个文件打包输出去,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath:__dirname+'/dll/jquery.js'
})
],
}
optimization
- 安装 terser-webpack-plugin插件
const TerserWebpackPlugin = require('terser-webpack-plugin')
optimization: {
splitChunks: {
chunks: 'all'
// 默认值,可以不写~
/* minSize: 30 * 1024, // 分割的chunk最小为30kb
maxSiza: 0, // 最大没有限制
minChunks: 1, // 要提取的chunk最少被引用1次
maxAsyncRequests: 5, // 按需加载时并行加载的文件的最大数量
maxInitialRequests: 3, // 入口js文件最大并行请求数量
automaticNameDelimiter: '~', // 名称连接符
name: true, // 可以使用命名规则
cacheGroups: {
// 分割chunk的组
// node_modules文件会被打包到 vendors 组的chunk中。--> vendors~xxx.js
// 满足上面的公共规则,如:大小超过30kb,至少被引用一次。
vendors: {
test: /[\\/]node_modules[\\/]/,
// 优先级
priority: -10
},
default: {
// 要提取的chunk最少被引用2次
minChunks: 2,
// 优先级
priority: -20,
// 如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
reuseExistingChunk: true
}
}*/
},
// 将当前模块的记录其他模块的hash单独打包为一个文件 runtime
// 解决:修改a文件导致b文件的contenthash变化
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
minimizer: [
// 配置生产环境的压缩方案:js和css
new TerserWebpackPlugin({
// 开启缓存
cache: true,
// 开启多进程打包
parallel: true,
// 启动source-map
sourceMap: true
})
]
}
常用辅助工具
resolve
resolve: {
// 配置解析模块路径别名: 优点简写路径 缺点路径没有提示
alias: {
$css: __dirname + '/src/css'
},
// 配置省略文件路径的后缀名只会匹配到一个, 一般js和css文件名相同,所以不建议匹配css文
extensions:['.js', '.json', '.jsx', '.css']
}
import {addNum} from './add'//省略的后缀
watch监控
//自带功能 不需要安装
//监控 实时打包
watch:true,
//监控的配置项
watchOptions:{
poll:1000,//每秒询问1000次
aggregateTimeout:500,//防抖 停留500毫秒后再打包
ignored:/node_modules/ //不需要监控的文件
}
清除dist文件
- 每次打包先清除dist目录下的文件
- 安装clean-webpack-plugin -D
//清除文件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
plugins:[
...
new CleanWebpackPlugin()
]
copy文件到dist
- 打包时可以把一些文件夹的内容拷贝到dist文件夹
- 安装 copy-webpack-plugin -D
//copy文件插件
const CopyWebpackPlugin = require('copy-webpack-plugin')
plugins:[
...
new CopyWebpackPlugin([
//把doc文件复制到dist文件夹中
{from:'./doc',to:'./'}
])
]
BannerPlugin声明
- webpack自带的插件
- 在打包后的Js文件头加上注释声明
//webpack
const webpack = require('webpack')
plugins:[
...
new webpack.BannerPlugin('杭州柯林电气股份有限公司版权所有')
]
定义全局变量
//使用webpack自带插件DefinePlugin
new webpack.DefinePlugin({
DEV:'false',
FLAGE:JSON.stringify('pjs')//如果想存字符串类型 需要使用JSON.stringify()
})
if(DEV){
console.log("正式环境")
}else{
console.log("测试环境")
}
webpack-merge
- 合并配置文件
- 分别创建开发和生产两个文件
- 安装 webpack-merge -D
//webpack.pro.js
let {smart} = require('webpack-merge')
let base = require('./webpack.config.js')
module.exports = smart(base,{
mode:'production'
})
//webpack.dev.js
let {smart} = require('webpack-merge')
let base = require('./webpack.config.js')
module.exports = smart(base,{
mode:'development'
})