webpack是一个模块打包工具(构建工具)。主要目标是将JavaScript文件打包在一起,打包后的文件用于在浏览器中使用,但它也能胜任转换(transform)、打包(bundle)或包裹(package)任何资源(resource or asset)
webpack的原理和概念:
- 树结构:在入口文件中引入所有资源,形成所有依赖关系树状图
- 模块:模块就是模块可以是ES6模块亦可以是commonJS或者AMD模块,对于webpack就是所有资源(css,img…)
- chunk:打包过程中被操作的模块文件叫做chunk,例如异步加载一个模块就是一个chunk
- bundel:bundel是最后打包后的文件,最终文件可以和chunk一模一样,但是大部分情况下它是多个chunk的集合
- 为了优化,最后产生的bundle的数量可能不等于chunk的数量,因为有可能多个chunk被组合到了一个Bundle中
webpack.config.js中的常见配置:
- entry:入口(entry)指示webpack以哪个文件作为入口起点开始打包,分析构建内部依赖图
- output:输出(output)指示webpack打包后的资源bundles输出到哪里,以及如何命名
- loader:让webpack能够去处理那些非JavaScript资源css、img等,将它们处理成为webpack能够识别的资源,可以理解成一个翻译过程(webpack自身只能理解js和json)
- plugins:插件(plugins)可用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。
- mode:模式(mode)指示webpack使用相应模式的配置;包括开发模式(development):配置比较简单,可以让代码本地调试运行的环境;生产模式(production):会自动压缩JS代码,代码需要不断优化达到性能最好。能让代码优化上线运行的环境。都会自动启用一些插件,生产模式使用插件更多。
//引入resolve,要在output中使用
const { resolve } = require('path')
module.exports = {
//entry入口
entry: './src/index.js',
//output输出到哪
output: {
filename: 'build.js',
// __dirname表示项目根目录
path: resolve(__dirname,'build')
},
//loader可以让webpack(只可识别js,json文件)处理非js文件,例如css,img,less等文件
module: {
rules: [
]
},
//plugins插件
plugins: [
],
mode: 'development'
}
配置详情:
entry:
(1). 单入口,如果只有一个入口,使用字符串,指定一个入口文件。
(2). 多入口,在使用Array的情况下,所有入口文件会形成一个chunk,名称默认,输出也只有一个bundle
(3). 多入口,在使用Object的情况下,存在几个入口文件就会生成几个chunk,并输出几个bundle,其中chunk的名称就是key,即在output中如初的文件名为entry中对象的名称,此时output中的filename属性需要改为filename: '[name].js’
(4). 特殊用法,
//特殊用法
entry: {
onea: ['./src/main.js','./src/index.js'],
twob: './src/index.js'
},
output: {
//[name].js表示默认名称
filename: '[name].js',
path: resolve(__dirname,'build')
}
HTML资源打包:
使用html-webpack-plugin
插件:
使用npm i html-webpack-plugin -D
下载安装插件
//引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
//使用插件
plugins: [
//使用插件
//默认会创建一个空的html文件,目的就是自动引入打包的资源(js/css)
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'demo.html',
//压缩html代码
minify: {
//移除空格
collapseWhitespace: true,
//移除注释
removeComments: true
}
})
],
}
html-webpack-plugin
插件生成的内存中的页面已帮我们创建并正确引用了打包编译生成的资源(JS/CSS)
打包多html
多个html需要多个entry,每个html一个entry,同时需要新建多个HtmlWebpackPlugin
module.exports = {
entry: {
//将jquery.js和common.js合并并压缩为vendor.js
vendor: ['./src/js/jquery.js','./src/js/common.js'],
index: './src/js/index.js',
cart: './src/js/cart.js'
},
//output输出到哪
output: {
//[name].js表示默认文件名
filename: '[name].js',
// __dirname表示项目根目录
path: resolve(__dirname,'build')
},
//loader可以让webpack(只可识别js,json文件)处理非js文件,例如css,img,less等文件
module: {
rules: [
]
},
//plugins插件
plugins: [
//使用插件,有几个html文件需要压缩,就要添加几个实例
//默认会创建一个空的html文件,目的就是自动引入打包的资源(js/css)
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
//定义该html要引入的js文件,不配置默认将所有压缩的js文件全部添加
chunks: ['index','vendor'],
//压缩html代码
minify: {
//移除空格
collapseWhitespace: true,
//移除注释
removeComments: true
}
}),
new HtmlWebpackPlugin({
template: './src/cart.html',
filename: 'cart.html',
//定义该html文件要引入的js文件,不配置默认将所有压缩的js文件全部添加
chunks: ['cart','vendor'],
//压缩html代码
minify: {
//移除空格
collapseWhitespace: true,
//移除注释
removeComments: true
}
})
],
mode: 'development'
}
CSS资源打包
需要使用npm下载css-loader
和style-loader
两个包来帮助我们完成打包
- css-loader:处理css中的
@import
和url
这样的外部资源 - style-loader:把样式插入到DOM中,方法是在head中插入一个style标签,并把样式写入到这个标签的
innerHTML
中
//应用html插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
//entry单入口
entry: './src/index.js',
//output输出到哪
output: {
//[name].js表示默认文件名
filename: '[name].js',
// __dirname表示项目根目录
path: resolve(__dirname,'build')
},
//loader可以让webpack(只可识别js,json文件)处理非js文件,例如css,img,less等文件
module: {
rules: [
//执行顺序从右到左,从下到上
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
},
//plugins插件
plugins: [
//使用插件,有几个html文件需要压缩,就要添加几个实例
//默认会创建一个空的html文件,目的就是自动引入打包的资源(js/css)
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
})
],
mode: 'development'
}
Less和Sass资源打包
Less需要使用npm下载less包和less-loader(将less转换为css)
Sass需要使用npm下载node-sass和sass-loader
//less配置,sass类似,将test正则换位/\.scss$/,less-loader换成sass-loader即可
module: {
rules: [
//执行顺序从右到左,从下到上
{
test: /\.css|less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
}
]
},
提取CSS为单独文件
CSS内容是打包在js文件中的,可以使用mini-css-extract-plugin
插件提取成单独的CSS文件(多个css/less/sass文件会合并到一个css文件中)。需要在webpack.config.js
中引入插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module: {
rules: [
//执行顺序从右到左,从下到上
// {
// test: /\.css|less$/,
// use: [
// 'style-loader',
// 'css-loader',
// 'less-loader'
// ]
// }
{
test: /\.css|less$/,
use: [
//使用插件的loader替换原本的style-loader
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
]
},
//plugins插件
plugins: [
//使用插件,有几个html文件需要压缩,就要添加几个实例
//默认会创建一个空的html文件,目的就是自动引入打包的资源(js/css)
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
}),
new MiniCssExtractPlugin({
//用于指定生成css文件名称,默认为main.css
filename: 'demo.css'
})
],
处理CSS兼容性
需要使用postcss处理,npm下载postcss-loader
和postcss-preset-env
两个包
//1.在webpack.config.js中
module: {
rules: [
//执行顺序从右到左,从下到上
{
test: /\.css|less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
//使用postcss-loader
'postcss-loader'
]
}
]
},
//2.新建postcss.config.js文件,在postcss.config.js中引入postcss-preset-env
module.exports = {
plugins: [
require('postcss-preset-env')()
]
}
//3.在package.json中添加浏览器支持
"browserslist": [
"> 0.2%",
"last 2 versions",
"not dead"
]
压缩CSS
使用optimize-css-assets-webpack-plugin
插件压缩CSS内容
- 引入插件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
- 使用插件
plugins:[new OptimizeCssAssetsWebpackPlugin()]
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
//plugins插件
plugins: [
//使用插件,有几个html文件需要压缩,就要添加几个实例
//默认会创建一个空的html文件,目的就是自动引入打包的资源(js/css)
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
}),
new MiniCssExtractPlugin({
filename: 'demo.css'
}),
new OptimizeCssAssetsWebpackPlugin()
],
打包图片资源
需要下载url-loader
和file-loader
两个包,依赖关系(url-loader依赖file-loader)
1.打包css中引用的图片
{
test: /\.(png|jpg|jpeg|gif)$/,
loader: 'url-loader',
options: {
//公共地址,会拼接在css图片地址之前
publicPath: './img/',
//输出目录
outputPath: 'img/',
//设置小于8kb时会将图片转换为base64格式
limit: 1024 * 8,
//[name]原名,[hash]hash名(:10表示保留前十位),同时设置会同时打包生成原名和hash名
name: '[hash:10][name].[ext]'
}
}
2.打包html中src引入的图片
需要npm下载html-loader包
//处理html中引入的图片
{
test: /\.html$/,
//专门处理html中src引入的图片
loader: 'html-loader',
//不添加无法正常加载打包后的文件
options: {esModule: false}
}
打包其他资源字体图标
//处理icon
{
//排除下列类型的文件
exclude: /\.(js|json|html|css|less|sass|png|gif|jpg|jepg)$/,
loader: 'file-loader',
options: {
publicPath: './font',
outputPath: 'font/',
name: '[name][hash:8].[ext]'
}
}
控制JS语法规范
使用eslint来控制代码风格一致性,语法检查使用eslint-loader
,并基于eslint
包,只用来检查自己写的js语法
需要npm下载eslint-loader
、eslint
、eslint-config-airbnb-base
、eslint-plugin-import
几个包
{
//只检查js语法
test: /\.js$/,
//只检查自己写的js语法,不检查第三方库的代码
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
//将检查出的部分错误进行自动修复
fix: true
}
}
可以在js文件中使用//eslint-disable-next-line
表示eslint检查时会跳过下一行
开发服务器devServer配置
devServer
给我们提供了开发过程中的服务器,是一个使用了express的http的服务器,其主要作用是为了监听资源文件的改变,该http
服务器和client
使用了websocket通信协议,只要资源文件发生改变,webpack-dev-server
就会实时进行编译
只会在内存中编译,不会有任何输出,需要下载webpack-dev-serve
包
webpack-dev-server
不会读取webpack.config.js
中配置的output
启动devServer
指令伪:npx webpack serve
本目录执行
webpack5
无法刷新,需要添加配置target: 'webpack'
当提示端口占用是可以通过webpack serve --port 端口号
来重新指定运行端口并运行,但是只能更改本次执行的端口,因此每次执行都需要指定端口号,否则服务会运行在8080端口如果要更换默认运行端口就需要在webpack.config.js
中添加如下配置
devServer: {
//本机ip
host:'127.0.0.1',
//指定默认运行端口
port:3030
},
HMR模块热替换
webpack
中只要一个js文件发生改变,所有相关js都会被重新打包。
模块热替换(Hot Module Replacement即HMR),其允许在运行时更新各种模块而无需进行完全刷新。启用该功能需要修改webpack.config.js
的配置,使用webpack
内置的HMR插件即可,在devServer中使用hot参数。
//启用热更新
devServer: {
host:'127.0.0.1',
port:3030,
open: true,
//启用热更新
hot: true
},
tip:
- 开启热更新后如果需要热更新html需要在入口文件添加html文件
- 如果需要更新css文件,则不能使用
MiniCssExtractPlugin.loader
而要使用style-loader
- 如果只需要监听指定js的变化,可以在如果js中添加监听事件
//如果js中
// 表示仅监听print.js的变化
if (module.hot) {
module.hot.accept('./print.js', () => {
console.log('文件内容有改变');
});
}
去除代码中的死代码
1.去除没有用到的JS代码:
- Webpack通过
tree-shaking
去掉了实际上并没有使用的js代码来减少包的大小 - 必须使用es6模块化,开启production环境
2.去除没有用到的CSS代码:
使用purgecss-webpack-plugin
去除无用css
const { resolve, join } = require('path')
const PurgecssPlugin = require('purgecss-webpack-plugin')
const glob = require('glob')
const PATHS = {src: join(__dirname,'src')}
//plugins插件
plugins: [
//使用插件,有几个html文件需要压缩,就要添加几个实例
//默认会创建一个空的html文件,目的就是自动引入打包的资源(js/css)
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
}),
new MiniCssExtractPlugin({
filename: 'demo.css'
}),
//使用压缩CSS插件
new OptimizeCssAssetsWebpackPlugin(),
//启用去除css死代码的插件
new PurgecssPlugin({
paths: global.SyncManager(`${PATHS.src}/**/*`,{nodir: true})
})
],