webpack5
简册webpack
的作用html
总会执行第一个script
标签里的js
代码,之后再执行引入的各种js
文件。script
标签,变成了多入口。webpack
就是指定一个或多个入口文件,然后进行代码处理,将引入的其他js,css
等等代码,资源打包成一捆一捆(bundle)的文件流(chunk),然后输出到指定的文件夹和文件名称。达到代码的兼容,压缩,转义处理等等功能。
webpack
的核心入口起点:entry
配置示例:webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js', // 默认为'./src/index.js'
};
输出指定:output
path
:必须使用绝对路基,所以需要引入nodejs
核心模块path
filename
:自定义。配置示例:webpack.config.js
const path = require('path')
module.exports = {
entry: './src/app.js'
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'build.js'
}
}
代码翻译:loader
webpack
是一个javascript
和json
代码的开箱即用软件,无法直接识别其他格式的文件和代码。loader
将其他代码进行翻译loader
会自动识别require()/import
引入的文件名后缀,只有导入的文件会触发转译loader
翻译对应的软件loader
翻译全部的代码,毕竟有英语翻译,也有俄语翻译。loader
是需要下载后才能使用的,但不需要引入到webpack.config.js
简单配置示例:webpack.config.js
module.exports = {
module: {
// 配置翻译txt代码
rules: [{ test: /\.txt$/, use: 'raw-loader' }]
}
}
插件:plugin
loader
)只能翻译代码,但不能压缩,优化,管理,注入环境变量等等,更强的功能需要插件loader
)下载后可以直接使用,不需要引入配置简单示例:webpack.config.js
const HtmlWebpackPlugin = require('html-wbpack-plugin') // 通过npm安装
module.exports = {
plugins: [
// 指定html文件为打包后dist文件内的的模板,没有其他配置就是复制
// template, 模板的意思
new HtmlWebpackPlugin({ template: './src/public/index.html' })
]
}
模式:mode
配置简单示例:webpack.config.js
module.exports = {
mode: 'production', // 配置为生产模式
// mode: 'development' // 开发模式
}
浏览器兼容性
环境
单入口单文件写法:如下webpack.config.js
// 写法一
module.exports = {
entry: './src/index.js'
}
// 写法二
module.exports = {
entry: {
main: './src/index.js'
}
}
单入口多文件写法:一个html
引入多个js
文件,最后打包为一个文件
如下webpack.config.js
module.exports = {
entry: ['./src/index1.js', './src/index2.js']
output: {
filename: 'bundle.js',
},
}
分离第三方库:将第三方相互独立的库放在一个js
文件内进行构建,使用vendors
关键字
如下webpack.config.js
module.export = {
entry: {
main: './src/index.js',
vendors: './src/vendors.js' // 指定的关键字,第三方库的入口
}
}
多入口文件写法:多个入口文件,会打包成两个文件
如下:webpack.config.js
module.export = {
entry: {
a1: './src/indexA1.js',
b1: './src/indexB1.js'
},
output: {
path: './build/js'
filename: '[name].[contenthash].js'
}
}
多文件依赖关系:多个文件打包的先后依赖关系,如b文件需要a文件先引入。
如下:webpack.config.js
module.export = {
entry: {
a2: 'dependingfile.js',
b2: {
dependOn: 'a2', // 在a2后执行
filename: 'bName', // 导出的名字,重命名为bName
import: './src/app.js',
},
c2: ['./src/c1.js', './src/c2.js']
},
}
其他:略(不知道咋用,不知道用哪里就不写了)
配置如下:webpack.config.js
// 不管单文件还是多文件,还是其他优化。这一个是万精油。
module.export = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
}
}
跳转链接如下
转译css
等,转译ts
,转译图片,转译其他,处理js
,css
兼容
跳转链接如下
处理html
,css
单独提取,css
压缩
npm init
创建packjson
插件管理文件npm i webpack webpack-cli -g
全局安装一次npm i webpack webpack-cli -D
开发环境安装webpackwebpack.config.js
文件夹此时已经完成起步工作
webpack ./src/index.js -o ./build/js --mode=development
webpack ./src/index.js -o ./build/js --mode=production
webpack
默认只能编译js/json
文件webpack.config.js
文件后,使用:webpack
命令就可以构建css
等css
使用loader
:style-loader
,css-loader
less
使用loader
:style-loader
,css-loader
,less-loader
scss
使用loader
:style-loader
,css-loader
,sass-loader
配置如下webpack.config.js
const commonCssLoader = ['style-loader', 'css-loader']
module.exports = {
/* ... */
module: { // 配置loader的地方
rules: [ // 这个属性里面进行配置
{
test: /\.css$/, // 匹配.css文件
use: [ // 使用那些loader,执行顺序,从下向上,依次执行
'style-loader', // 创建style标签,将js中的样式资源插入到标签,并添加到head中生效
'css-loader' // 将css文件变成commonjs模块加载到js中,里面的内容是样子字符串
]
},
{
test: /\.less$/, // 匹配.less文件
use: [
...commonCssLoader, // 也可以这样引入loader
'less-loader' // 将less转为css文件,scss使用scss-loader
]
},
{
test: /\.s[ac]ss$/i, // 匹配.scss文件
use: [
...commonCssLoader,
'sass-loader' // 将s[ac]ss转为css文件,scss使用scss-loader
]
}
]
}
}
ts
loader
:ts-loader
配置如下:webpack.config.js
module.exports = {
/* ... */
module: {
rules: [
// ts-loader 将ts转js
{ test: /\.tsx?$/, loader: "ts-loader" }
]
}
}
loader
:url-loader
,img-loader
,html-loader
配置如下:webpack.config.js
module.exports = {
/* ... */
module: {
rules: [
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'url-loader',
// 只使用一个loader,可以直接写loader: 使用loader名称
// 下载url-loader, file-loader
options: { // loader的配置
limit: 8 * 1024, // 小于8kb的图片会整合为大图片。减少图片流
esModule: false, // 不用es6引入
name: '[hash].[ext]' // 对图片进行重命名
},
},
{
// 图片压缩
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
}
}
]
type: 'javascript/auto' // 不加weboack5会报错
},
{
test: /\.html$/,
loader: 'html-loader', // 处理html引入的图片,如img的src引入的资源
}
]
}
}
loader
:file-loader
txt
使用loader
:raw-loader
配置如下:webpack.config.js
module.exports = {
/* ... */
module: {
rules: [
// 添加loader配置
{
// 打包其他资源(处理html,js,css资源以外的资源)
// 排除html,js,css等文件以外的资源
exclude: /\.(css|js|html|json|png|jpg|gif)$/,
loader: 'file-loader',
options: {
name: '[hash].[ext]' // 不建议[hash:10],取10位hash,还是会冲突的
outputPath: 'media', // 其他资源输出路径
}
},
{ test: /\.txt$/, use: 'raw-loader' }
]
}
}
js
作用:检测代码书写规范,逻辑规范。
不在webpack.config.js
里面添加,加快打包速度(添加总报错, 无法处理)
下载四个插件,npm i -D
eslint
eslint-config-airbnb-base
eslint-import-resolver-webpack
eslint-plugin-import
pageage.json
同级创建两个文件
.eslintignore
node_modules/
**/*.spec.*
**/style/
*.html
/components/test/*
es/
lib/
_site/
dist/
.eslintrc
{
"extends": "airbnb-base",
"settings": {
"import/resolver": {
"webpack": {
"config": "webpack.config.js"
}
}
},
"rules": {
"linebreak-style": ["off", "windows"] // 不考虑换行符
// 后续添加需要的配置
}
}
此时重新打开编译器,就可以看的代码检查功能的出现了
es6
及其以上的代码转译为es5
等等loader
: babel-loader
@babel/preset-env
,@babel/core
,core-js
npmjs
地址:https://www.npmjs.com/package/babel-loader配置如下:webpack.config.js
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }
]
}
创建babel
配置:babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // 按需加载
corejs: { version: 3 }, // core-js版本号, 最新版本为3
targets: {
chrome: 60, // 兼容到谷歌60版本
firefox: 60 // 兼容到火狐60版本
}
}
]
],
plugins: [
[ '@babel/plugin-proposal-optional-chaining' ] // 解析 可选链式语法
]
}
webpack
生产模式会对js
自动进行压缩
开发模式不能压缩,需要进行代码调试
html
html-webpack-plugin
配置如下:webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
/* ... */
plugins: [
// 使用html-webpack-plugin插件
// 创建一个html文件,自动引入打包后输出的所有资源(js/css)
// 使用./src/index.html为模板,并自动引入。
// 如果没有压缩等替他配置,就是复制了模板,引入打包后资源
new HtmlWebpackPlugin({
template: './src/index.html',
hash: true,
filename: 'index.html',
minify: { // 压缩html, 一般仅在生成环境配置
collapseWhitespace: true, // 移除空格
removeComments: true // 移除注释
}
})
],
}
css
css
样式单独提出到css文件mini-css-extract-plugin
loader
替换style-loader
配置如下:webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
/* ...... */
module: {
/* ... */
rules: [
{
test: /\.css$/,
use: [
// 创建style标签,将js中的样式资源插入到标签,并添加到head中生效
// 'style-loader',
// 使用mini-css-extract-plugin插件的loader替代style-loader
MiniCssExtractPlugin.loader,
'css-loader' // 解析css的loader
]
}
]
},
plugins: [
/* ... */
new MiniCssExtractPlugin({
filename: 'css/build.[hash].css' // 对提取的css进行单独命名, 不推荐使用[hash:10]
})
]
postcss-loader
,postcss-preset-env
package.json
里面配置browserslist
,和scripts
同级属性process.env.NODE_ENV
配置如下:webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
process.env.NODE_ENV = 'development' // 修改环境变量
// 或者通过插件cross-env进行修改,如, 在package.json里面
/*
"scripts": {
"dev": "cross-env NODE_ENV='development' webpack",
},
*/
/* ...... */
module: {
rules: [
{
test: /\.css$/,
use: [
// 'style-loader', // 创建style标签,将js中的样式资源插入到标签,并添加到head中生效
MiniCssExtractPlugin.loader, // 使用插件的loader
'css-loader', // 解析css的loader
/*
postcss-loader, postcss-preset-env 处理css兼容问题
帮助postcss去package.json中找browserlist里面的配置,通过配置加载知道的css兼容样式
默认会直接使用production里面的配置,通过环境变了process.env.NODE_ENV进行切换
process.env.NODE_ENV = "development"执行development里面的配置
*/
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-preset-env')(),
]
}
}
}
]
}
]
},
"browserslist": {
"development": [
"last 1 chrome version", // 兼容到上一个版本的谷歌浏览器
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">1%", // 兼容是市面上99%的浏览器
"not dead", // 不兼容没有维护死掉的,如ie10
"last 2 versions", // 兼容到上两个版本
"not ie <= 8"
]
}
optimize-css-assets-webpack-plugin
配置如下:webpack.config.js
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
/* ... */
plugins: [
/* ... */
new MiniCssExtractPlugin({ filename: 'css/build.css' }), // 对提取的css进行单独命名
new OptimizeCssAssetsWebpackPlugin() // 使用这个插件,就可以压缩提取后的css文件
]
就是mode: 'production'
build
output
添加clean: true
就好了
clean-webpack-plugin
import { CleanWebpackPlugin } from 'clean-webpack-plugin'
new CleanWebpackPlugin()
就好了上面介绍:
css
:less/scss
转译,css
转译,css
兼容,css
压缩,css
单独提取js
:js
的规范,js
兼容,ts
转译html
:html
模板复制,html
压缩,html
内图片处理html
内图片处理devserve
配置mode
配置简单配置示例:webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin') // 打包html
const miniCssExtractPlugin = require('mini-css-extract-plugin') // 分离样式
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 压缩css
const { CleanWebpackPlugin } = require('clean-webpack-plugin') // 清除dist
process.env.NODE_ENV = 'production'
const cssLoaders = [
miniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-preset-env')(),
]
}
}
}
]
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: resolve(__dirname, 'dist'),
clean: true,
},
module: {
rules: [
{ test: /\.css$/, use: cssLoaders },
{ test: /\.less$/, use: [...cssLoaders, 'less-loader'] },
{ test: /\.s[ac]ss$/, use: [...cssLoaders, 'sass-loader'] },
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'url-loader',
options: { // loader的配置
limit: 8 * 1024,
esModule: false,
name: '[hash].[ext]'
},
},
{
loader: 'image-webpack-loader',
options: { bypassOnDebug: true }
}
],
type: 'javascript/auto'
},
{ test: /\.html$/, loader: 'html-loader' },
{ test: /\.txt$/, use: 'raw-loader' },
{
exclude: /\.(css|less|s[ac]ss|js|ts|json|html|htm|png|jpg|jpeg|gif|txt)$/,
loader: 'file-loader',
options: {
name: '[hash].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/assets/index.html',
hash: true,
filename: 'index.html',
// favicon: './src/assets/favicon.ico',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new miniCssExtractPlugin({ filename: 'css/build.[hash].css' }),
new OptimizeCssAssetsWebpackPlugin(),
new CleanWebpackPlugin()
],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
mode: 'production',
}
使用到的插件如下:
cnpm i -D webpack webpack-cli
cnpm i -D html-webpack-plugin html-loader clean-webpack-plugin
cnpm i -D mini-css-extract-plugin optimize-css-assets-webpack-plugin style-loader css-loader postcss-loader postcss-preset-env
cnpm i -D less less-loader sass sass-loader
cnpm i -D url-loader image-webpack-loader file-loader raw-loader
cnpm i -D eslint eslint-config-airbnb-base eslint-import-resolver-webpack eslint-plugin-import
cnpm i -D babel-loader @babel/preset-env @babel/core core-js
devServer
npmjs
地址:https://www.npmjs.com/package/webpack-dev-serverwebpack-dev-server
npm i -D webpack-dev-server
// 开启服务器
devServer: {
compress: true, // 开启压缩
port: 9900, // 端口号
open: true, // 自动打开
static: ['assets'], // 静态资源读取配置
client: {
logging: 'info', // 大约基础信息
overlay: true, // 报错页面黑屏
progress: true, // 百分比显示编译进度
},
liveReload: true, // 热模块更新
proxy: { // 配置服务器代理
'/api': {
target: 'http://localhost:3000', // 代理地址
changeOrigin: true, // 允许跨域
pathRewrite: { '^/api': '' }, // 正则,把接口头部`/api`转换为''
},
'/bpi': {
target: 'http://localhost:3000', // 代理地址
changeOrigin: true, // 允许跨域
pathRewrite: { '^/bpi': '' }, // 正则,把接口头部`/api`转换为''
}
},
// 多个路径同时匹配一个地址和端口
// proxy: [
// {
// context: ['/auth', '/api'],
// target: 'http://localhost:3000',
// changeOrigin: true, // 允许跨域
// }
// ]
},
target: 'web', // 配号上面的热模块更新
HMR
热更新如上面示例,
devserver
的liveReload
设置为truetarget: web
webpack5
已经可以监听js的更新了。source
调试就是浏览器调试器报错机制配置。
操作:entry
同级配置:devtool: 'source-map',
即可
不同的关键字:devtool
有不同的关键字,可以查看官网文档
开发时配置:devtool: 'eval-source-map'
或者devtool: 'eval-cheap-module-source-map'
生产时配置:devtool: 'nosource-source-map'
或者devtool:'hidden-source-map'
oneof-loader
减少loader
匹配,加快转移速度
原本:
rules: [
{ /* loader1 */ },
{ /* loader2 */ }
]
修改为
rules: [
{
test: /\.js$/,
exclude: /mode_modules/,
enforce: true, // 优先执行eslint-loader,处理一个文件只能使用一个loader的配置
loader: /eslint-loader/,
options: { fix: true }
},
{
oneOf: [
{ /* loader1 */ },
{ /* loader2 */ }
]
}
]
就是多包裹一层
需要使用处理eslint
时,loader
写在oneOf
外面
babel
缓存存在问题。
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // 按需加载
corejs: 3, // corejs版本号
targets: {
chrome: 60, // 兼容到谷歌60版本
firefox: 60 // 兼容到火狐60版本
}
}
]
],
cacheDirectory: true, // 开启babel缓存,就不需要全部js代码重新转译
plugins: [
[ '@babel/plugin-proposal-optional-chaining' ] // 解析 可选链式语法
]
}
就是每次修改后,将打包的文件名字更换,达到浏览器重新请求服务器文件
使用:contenthash
:根据文件内容生成的hash值,不同的文件hash值不一样
操作:就是将js
和css
文件构建名hash
更换为contenthash
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/build.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
modules: {
// ...里面的静态资源文件不需要使用contenthash
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/build.[contenthash:10].css'
})
]
}
tree-shaking
tree shaking
条件:1、使用es6
导入到处。2、使用production
生成环境
实现:将没用使用到的node_modules
和没用使用到的代码摇下去
code split
多入口文件分割,一个入口就会出现一个chunk
node-module
分割
/*
1、和entry同级
2、可以将node_module中的代码单独打包一个chunk最终输出
3、自动分析多入口chunk,有没有公共的文件,如果有会打包成单独一个chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
}
},
js
文件单独打包chunk
/*
1、通过js代码,将某个文件单独打包成一个chunk
2、import动态语法导入,能将整个文件单独打包
*/
import(/* webpackChunkName: 'test' */ './test')
.then(() => { console.log('文件加载成功') })
.catch(() => { console.log('文件打包失败') })
懒加载:就是使用import()
进行动态加载,可以和代码分割一起使用
预加载:就是加上注解:webpackPrefetch: true
import(/* webpackChunkName: 'test', webpackPrefetch: true */ './test')
.then(() => { console.log('文件加载成功') })
.catch(() => { console.log('文件打包失败') })
babel
多进程打包下载:thread-loader
作用:注意就是减少babel翻译的次数,而且项目体积过小反而会变慢
{
test: /\.js$/,
exclude: /mode_modules/,
use: [
// 每个进程启动需要600ms
{
loader: 'thread-loader',
options: {
workers: 2 // 启动两个进程进行打包
}
},
{
loader: 'babel-loader',
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: true, // 按需加载
corejs: { version: 3 }, // corejs版本号
targets: {
chrome: 60, // 兼容到谷歌60版本
firefox: 60
}
}
]
],
cacheDirectory: true // 开启babel缓存,就不需要全部js代码重新转译
}
}
]
},
处理可以使用cdn
引入的库
dll
将引入的库单独打包为一个chunk
创建webpack.dll.js
文件
const { resolve } = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
// 最终打包生成的[name] ---> jquery
// ['jquery'] ---> 要打包的库是jquery
jquery: ['jquery']
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash]'
// 打包的库里面向外面暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个 manifest.json --> 提供jquery映射
new webpack.DllPlugin({
name: '[name]_[hash]', // 映射库的暴露的内容名称
path: resolve(__dirname, 'dll/manifest.json')
})
],
mode: 'production'
}
运行这个文件:webpack --config webpack.dll.js
然后在webpack.config.js
添加一些配置
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
......
plugins: [
......,
// 告诉webpack那些库不需要打包,同时使用的名字也得变化
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')
}),
// 将某个文件打包输出去,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')
})
]
过程:
1、把jquery
单独打包出去,避免每次重复打包
2、告诉webpack
在打包的时候不用打包jquery
3、并在webpack
打包的使用将打包好的jquery
引入到html
里面
4、其他的库是同理的