webpack能处理js/json资源,不能处理css/img等其他资源
webpack构建工具都是基于node.js平台运行的,模块化默认采用common.js
安装:
npm install webpack webpack-cli --save-dev
打包样式资源
webpack配置文件:
const {resolve} = require('path')
module.exports = {
//入口文件配置
entry:'./src/index.js',
//输出配置
output:{
//打包生成build文件夹中的build.js
filename:'built.js',
//打包生成build文件夹中的js文件夹中的build.js
//filename:'js/build.js'
//__dirname表示文件所在的目录
path:resolve(__dirname,'build')
},
//主要用来处理css,img等资源
module:{
rules:[
{
test:/\.css$/,
//要使用多个loader处理用use
use:[
'style-loader',
'css-loader'
]}
]
},
//插件
plugins:[
],
//模式development或者production
mode:'development'
}
注意:要使用多个loader处理用use,使用一个直接loader[^注意]
如何引入的是.less文件,则需要下载
npm i less less-loader --save-dev
webpack配置文件如下:
~
modele:{
rules:[
{test:/\.less$/,
use:[
'style-loader',
'css-loader',
'less-loader'
]}
]
}
~
打包html资源
下载插件,plugins: 1.下载 2.引入 3.使用
-
下载
#具体用法可以查找 中文文档--》插件 #功能:默认会创建一个空的html,自动引入打包输出的所有资源(js/css) npm install --save-dev html-webpack-plugin -
引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin'); -
使用
//插件 //将html文件打包 plugins:[ new HtmlWebpackPlugin( { template:'html文件路径' }) ],
打包图片资源
webpack5中第1步似乎不需要,有待验证;第一步为webpack4中的loader
1.下载的包:url-loader file-loader
注意:要使用多个loader处理用use,使用一个直接loader
//主要用来处理css,img等资源
rules:[
{ test:/\.css$/,
//要使用多个loader处理用use
use:[ 'style-loader', 'css-loader' ]
},
{
//处理图片资源
//问题:处理不了html中的img图片
test:/\.(jpg|png|gif)$/,
//使用一个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]',
//设置存放图片的文件夹
outputPath:'img'
},
//如果要在webpack5中使用本loader
type:'javascript/auto'
}
]
上面的步骤可以跳过[^注意]
2.问题:处理不了html中的img图片
解决:下载html-loader
{
test:/\.html$/,
//处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
loader:'html-loader'
}
打包其他资源
需要下载:file-loader
module:{
rules:[
//打包其他资源(除了html/js/css资源以外的资源)
{
//排除css/js/html资源
exclude:/\.(css|js|html)$/,
loader:'file-loader',
options:{
name:'[hash:10].[ext]'
}
}
]
}
devServer
开发服务器devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
特点:只会在内存中编译打包,不会有任何输出
启动devServer指令为:webpack-dev-server
devServer:{
static:{
directory:resolve(__dirname,'build')
},
//启动gzip压缩
compress:true,
//端口
port:3000,
//自动打开浏览器
open:true
}
提取css到单独文件
本插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
下载:mini-css-extract-plugin
配置:
//引入
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
~
{
test:/\.css$/,
use:[
//替换style-loader
//'style-loader',
MiniCssExtractPlugin.loader,
'css-loader'
]},
~
plugins:[
new MiniCssExtractPlugin({
//打包的css文件重命名为built.css放在css文件夹中
filename:'css/built.css'
}
)
],
css兼容性处理
下载:postcss-loader postcss-preset-env
查看文档postcss-loader | webpack 中文文档 (docschina.org)
帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
webpack.config.js文件中
rules: [
{
test: /\.css$/i,
use: [
'style-loader','css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
[
'postcss-preset-env',
{
// 其他选项
},
],
],
},
},
},
],
js兼容性处理(babel)
查看文档:babel-loader | webpack 中文文档 (docschina.org)
下载:babel-loader @babel/core @babel/preset-env
npm install babel-loader @babel/core @babel/preset-env -D
webpack.config.js
rules:[
{
test:/\.js$/,
exclude:/node_modules/,
loader:'babel-loader',
options:{
// 预设:指示babel做怎么样的兼容处理
presets:['@babel/preset-env']
}
},
]
js兼容性处理:babel-loader @babel/core @babel/preset-env
-
基本js兼容性处理 --> @babel/preset-env 问题:只能转换基本语法,如promise高级语法不能转换,IE浏览器报错
-
全部js兼容性处理 --> @babel/polyfill,可以兼容ie浏览器
下载:
@babel/polyfillindex.js
import '@babel/polyfill'问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了
-
需要做兼容性处理的就做:按需加载 --> core-js
使用第三种方案则不能使用第二种方案,需要注释
import '@babel/polyfill'[^注意]下载:
core-jsrules:[ { test:/\.js$/, 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' } } ] ], } }, ]
设置node.js环境变量
Tip:不是webpack的环境变量
在webpack.config.js文件中:
//注释后nodejs环境变量为production
process.env.NODE_ENV = 'development';
压缩html(webpack4)和 js
//插件
//将html文件打包
plugins:[
new HtmlWebpackPlugin(
{
template:'html文件路径',
//压缩html代码
minify:{
//移除空格
collapseWhitespace:true,
//移除注释
removeComments:true
}
})
],
//生产环境下会自动压缩js
mode:'production'
压缩css
webpack5中设置mode:'production'可以压缩其他资源(html...)
安装:css-minimizer-webpack-plugin
查看文档:CssMinimizerWebpackPlugin | webpack 中文文档 (docschina.org)
webpack.config.js
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
~~~
optimization: {
minimizer: [
// 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
// `...`,
new CssMinimizerPlugin(),
],
//在开发环境下启用css优化,不写只在生产环境中开启
minimize:true
},
HRM热模块替换
作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有的模块),极大提升构建速度
HRM基于devserver,不适用于生产环境[^注意]
开启热模块替换webpack.config.js
devServer:{
static:{
directory:resolve(__dirname,'build')
},
compress:true,
port:3000,
open:true,
// 开启HMR功能
// 当修改了webpack配置,新配置想要生效,必须重新webpack服务
hot:true
}
出现的问题:
-
样式文件:可以使用HMR功能,因为syle-loader内部实现了
-
js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR代码
注意:HMR功能对js的处理,只能处理非入口js文件的其他文件
-
html文件:默认不能使用HMR功能,同时会导致问题,HTML文件不能热更新了(不需要做HMR功能)
解决:修改entry入口,将html文件引入
Tip:该方法可以实现修改html文件刷新浏览器页面
//根据文件路径填写
//该方法可以实现修改html文件刷新浏览器页面
entry:['./src/js/index.js','./src/index.html']
source-map
source-map:一种提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射可以追踪源代码错误)
查看文档:Devtool | webpack 中文文档 (docschina.org)
webpack.config.js
~
devServer:{}
devtool:'source-map'
打包后生成source-map文件,例如,built.js.map
devtool有多种配置如下
[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-source-map > eval-source-map
- 调试更友好:
source-map > cheap-module-source-map > cheap-source-map
- 推荐配置:
---> eval-source-map(调试最友好,react和vue默认) / eval-cheap-module-source-map(新能更好)
生产环境:源代码要不要隐藏?调试要不要更友好
-
内联会让代码体积变大,所以在生产环境不用内联
-
nosources-source-map 全部隐藏
-
hidden-source-map 只隐藏源代码,会提示构建后代码错误信息
-
推荐配置:
-->source-map / cheap-module-source-map
oneOf
作用:提升构建速度
查看文档:文档->配置->Module->Rule.oneOf
module:{
rules:[
{
~
},
{
//以下loader只会匹配一个
//注意:不能有两个配置处理同一种类型文件
oneOf:[
{test:/\.css$/}
~
]
}
]
}
缓存
由于HRM只能在开发环境中使用,所以生产环境中需要以下方法:
-
开启babel缓存
rules:[ { test:/\.js$/, exclude:/node_modules/, loader:'babel-loader', options:{ // 预设:指示babel做怎么样的兼容处理 presets:['@babel/preset-env'], //开启babel缓存 //第二次构建时,会读取之前的缓存 cacheDirectory:true } }, ]--> 让第二次打包构建速度更快,实测速度对比明显
-
资源文件缓存
hash:每次webpack构建时会生成一个唯一的hash值。
问题:因为js和css同时使用一个hash值。如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)
output:{ //添加hash值 filename:'js/index.[hash:10].js', path:resolve(__dirname,'build') }, -
chunkhash:根据chunk生产的hash值。如果打包来源同一个chunk,那么hash值就一样
问题:js和css的hash值还是一样的,因为css是在js中被引入的,所以同属于一个chunk
output:{ //添加chunkhash值 filename:'js/index.[chunkhash:10].js', path:resolve(__dirname,'build') }, -
contenthash:根据文件内容生产hash值。不同文件hash值一定不一样
output:{ //添加contenthash值 filename:'js/index.[contenthash:10].js', path:resolve(__dirname,'build') },--> 让代码上线运行缓存更好使用
tree shaking
作用:去除无用代码,减少打包体积
前提:
-
必须使用ES6模块化
-
开启production环境
在package.json中设置(webpack4?):
"sideEffects":false//所有代码都没有副作用(都可以进行tree shaking)
问题:可能会把css/@babel/polyfill(副作用)文件干掉
"sideEffects":["*.css","*.less"]//不再使用tree shaking
webpack5配置如下(查看文档:Tree Shaking | webpack 中文文档 (docschina.org)):
webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
+ mode: 'development',
+ optimization: {
+ usedExports: true,
+},
};
code split(代码分割)
查看文档:代码分离 | webpack 中文文档 (docschina.org)
多入口文件
webpack.config.js
entry:{
//单入口
entry:'./src/js/index.js'
//多入口
//打包生成多个js文件,打包后的文件名和index,test同名
entry:{
index(自定义名称):'./src/js/index.js',
test:'./src/js/test.js'
}
output:{
//多文件入口记得配置[name]
//[name]:去文件名
filename:'js/[name].[contenthash:10].js',
path:resolve(__dirname,'build')
}
}
多入口配置将打包成两个js文件(index.js and test.js)
SplitChunksPlugin[^Tip:not install]
将node_modules中代码单独打包一个chunk最终输出(引入的loader和入口文件单独打包)
Tip:自动分析多入口chunk中,有没有公共的文件,如果有就会打包成单独一个chunk;
单入口如果引入npm包则npm包也会打包成一个chunk[^用的多]
例如,两个js文件同时引入了第三方文件(npm包),如果没有配置code split则只打包成两个文件,且都把第三方文件一同打包了;
配置后则会打包成三个文件,第三方文件单独打包了,避免了资源重复打包,第三方文件如果太小则该功能不生效。
webpack.config.js
entry:{
index:'xxxx.js',
test:'xxx.js'
},
optimization:{
splitChunks:{
chunks:'all'
}
}
通过js代码实现多入口文件功能
如果不想配置webpack.config.js,可以通过js代码,让某个文件被单独打包成一个chunk
import动态导入语法:能将某个文件单独打包
//懒加载
import(/*webpackChunkName:'test'*/ './test')
.then(()=>{
//文件加载成功
})
.catch(()=>{
//文件加载失败
})
/*webpackChunkName:'test'*/给test.js打包后的文件固定文件名
懒加载和预加载
-
懒加载和上面一样 --> 通过js代码实现多入口文件功能
-
预加载prefetch:会在使用之前,提前加载js文件
//懒加载
import(/*webpackChunkName:'test'*/ './test')
.then(()=>{
//文件加载成功
})
.catch(()=>{
//文件加载失败
})
//预加载
import(/*webpackChunkName:'test',webpackPrefetch:true*/ './test')
.then(()=>{
//文件加载成功
})
.catch(()=>{
//文件加载失败
})
pwa渐进式网络应用程序
安装:workbox-webpack-plugin
查看文档:渐进式网络应用程序 | webpack 中文文档 (docschina.org)
配置webapck.config.js
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
~
plugins:[
new WorkboxWebpackPlugin.GenerateSW({
/*
1.帮助serviceworker快速启动
2.删除旧的serviceworker
生成一个serviceworker配置文件
*/
clientsClaim:true,
skipWaiting:true
})
]
index.js
//注册serviceworker
//sw代码必须运行在服务器上
//处理兼容性问题
if('serviceWorker' in navigator){
navigator.serviceworker
.register('./service-worker.js')
.then(()=>{
console.log('注册成功')
})
.catch(()=>{
console.log('注册失败')
})
}
如果配置了eslint会报错,eslint不能识别navigator window
解决:需要修改package.json中eslintConfig配置
package.json
"eslintConfig":{
"env":{
"browser":true//支持浏览器全局变量
}
}
多进程打包
安装:thread-loader
开启多进程打包,进程启动大概为600ms,进程通信也有开销所以不要滥用。
只用工作消耗时间比较长,才需要多进程打包。
webpack.config.js
use:[
{
loader:'thread-loader',
options:{
workers:2//进程2个
}
}
]
查看文档:thread-loader | webpack 中文文档 (docschina.org)
Externals外部扩展
查看文档:外部扩展(Externals) | webpack 中文文档 (docschina.org)
在webpack打包的项目中使用cdn,而不是去把它打包,例如,
从cdn引入jQuery,不打包它
index.html
<script src="https://code.jquery.com/jquery.js"></script>
webpack.config.js
entry:{},
externals:{
jquery:'jQuery',
}
index.js
import $ from 'jquery'
$('.xxx').animate()
dll
对某些库(第三方库:jquery,react,vue...)进行单独打包
查看文档:DllPlugin | webpack 中文文档 (docschina.org)
新建webpack.dll.js(自定义)
/*
使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包
当运行webpack时,默认查找webpack.config.js配置文件
需要:需要运行webpack.dll.js文件
-->webpack --config webpack.dll.js
*/
const {resolve} = require('path')
const webpack = require('webpack')
module.exports = {
entry:{
//最终打包生成的[name] --> jquery
//['jquery'] --> 要打包的库是jquery
jqueryVue:['jquery','vue'],
},
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.dll.js
npx webpack --config webpack.dll.js
然后打包生成了一个包含打包的jq和vue库文件还有一个manifest.json文件的dll文件夹。
配置webpack.config.js
const webpack = require('webpack')
~
plugins:[
//告诉webpack那些库不参与打包,同时使用时的名称也要变
new webpack.DllReferencePlugin({
manifest:resolve(__dirname,'dll/manifest.json')
})
]
最后打包,发现打包后的文件小了很多,打包速度也明显变快
参考:
b站尚硅谷 BV1e7411j7T5