webpack的基本配置
入口文件(entry)
要打包哪个文件
出口文件(output)
要打包到哪里去
加载器(loader)
作用:加载除js文件其他文件的功能(css less 图片)
webpack只能处理js文件,非js文件(css less 图片 字体等处理不了,只能借助加载器处理
一般兼容性的处理都是使用loader
-
处理样式 style-loader css-loader less-loader
-
处理图片 url-loader file-loader
区别:
url-loader 会把图片编译成base64格式 ,打包到bundle中
注意: base64 的好处 减少一个http请求,然而,与之同时付出的代价就是css文件体积变大,css文件体检直接影响渲染,导致用户会长时间注视空白屏幕
file-loader 不会把图片打包到bundle.js中,而是单独生成一个图片
劣势:单独生成一个图片就要多发送一个图片的http请求
解决方案:如果图片小,就使用url-loader 编译成base64格式,如果图片大单独生成一个图片文件
url-loader 是file-loader的一个升级
-
处理html 中引入的图片 html -loader
会有问题 :因为url-loader无法解析html中引入的图片,所以需要html-loader。但是这个也会有问题,因为url-loader默认是使用es6模块化语法,而html引入图片是使用commonjs,所以两种解析方式不一样,就会导致问题。此时需要关闭url-loader中的es6模块化解析,使用commonjs解析。
esMoudule:false
-
处理字体图标文件 file-loader
插件(plugin)
作用:处理加载器完成不了对的功能,使用插件
一般压缩的功能都是使用插件
ex:
- html-webpack-plugin
作用:能够根据指定的模板文件(index.html),自动生成一个新的index.html文件,并且注入到dist文件夹下,能够自动引入js文件
- 提取css到css文件中 min-css-extract-plugin
模式(mode)
development:开发模式
production:生产模式
devServer
devServer:{
//项目构建后的路径
contentBase:resolve(__dirname,'build'),
//启动gzip压缩
compress:true,
//端口号
port:3000,
//自动打开浏览器
open:true
}
开发环境的基本配置
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.export = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
//loader的配置
{
//处理less资源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
//处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
//处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]'
},
//关闭es6模块化
esMoudle: false
},
{
//处理html中引入图片资源
test: /\.html$/,
loader: 'html-loader',
},
{
//处理其他资源
test: /\.(html|js|css|less|jpg|png|gif)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
},
]
},
plugins: [
//plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
devServer: {
//项目构建后的路径
contentBase: resolve(__dirname, 'build'),
//启动gzip压缩
compress: true,
//端口号
port: 3000,
//自动打开浏览器
open: true
}
}
生产环境的基本配置
css的处理
- 提取css成单独的文件:
mini-css-extract-plugin
- css兼容性的处理:
postcss-loader postcss-preset-env
- 压缩css:
optimize-css-assets-webpack-plugin
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
module.export = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
//loader的配置
{
//处理css资源
test: /\.css$/,
use: [
//创建style标签,将样式插入
//'style-loader',
//这个loader取代style-loader。作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
//将css文件整合到js文件中
'css-loader',
/*
css兼容性处理:postcss---->postcss-loader----->post-preset-env
帮postcss找到package.json中browserslist里的配置,通过配置加载指定的css兼容性样式
"borwserlist":{
"development":[
'last 1 chrome version',
'last 1 firefox version',
'last 1 safari version',
],
"production":[
'>0.2%',
'not dead',
'not op_mini all',
]
}
*/
//postcss-loader
{
loader: 'post-loader',
options: {
ident: 'postcss',
plugins: () => [//postcss 插件
require('post-preset-env')()
]
}
}
]
},
]
},
plugins: [
//plugins的配置
//处理html
new HtmlWebpackPlugin({
template: './src/index.html'
}),
//将css文件单独提出为一个文件
new MiniCssExtractPlugin({
//对输出的css文件进行重命名
filename: 'css/built.css'
}),
//压缩css文件
new OptimizeCssAssetsWebpackPlugin()
],
mode: 'development'
}
js的处理
-
js语法检查: loader:
eslint-loader
plugin:eslint-config-airbin-base eslint eslint-plugin-import
-
js的兼容性处理:
需要的loader: babel-loader @babel/core @babel/preset-env
1.基本js兼容性处理—>@babel/preset-env 能解决
问题:只能转换基本语法,如promise不能转换
2.全部js兼容性处理—> @babel/polyfill
问题:只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大
3.需要做兼容性处理的就做:按需加载—>core-js
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.export = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
/*
语法检查:eslint-loader eslint
注意:只检查自己写的源代码,第三方的库是不检查的
设置检查规则:
配合package.json中的eslintConfig设置
package.json的eslintConfig设置
"eslintConfig":{
extend:"airbnb-base"
}
需要的插件: airbnb--> eslint-config-airbnb-base --->eslint-plugin-import---> eslint
需要的loader: eslint-loader
*/
{
test: /\.js$/,
//排除对node_modules的检查
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
//自动修复
fix: true
}
},
/*
js 兼容性处理
需要的loader: babel-loader @babel/core @babel/preset-env
1.基本js兼容性处理--->@babel/preset-env 能解决
问题:只能转换基本语法,如promise不能转换
2.全部js兼容性处理---> @babel/polyfill
问题:只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大
3.需要做兼容性处理的就做:按需加载--->core-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'
}
}
]
}
}
]
},
plugins: [
//plugins的配置
//处理html
new HtmlWebpackPlugin({
template: './src/index.html'
}),
],
mode: 'development'
}
js和html的压缩
-
生产环境自动会压缩js代码
只需要修改mode配置为生产环境即可
mode:'production'
此时生产环境下的UglifyJsPlugin
就会压缩js代码 -
html代码的压缩是利用
html-webpacj-plugin
这个插件
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.export = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {},
plugins: [
//plugins的配置
//处理html
new HtmlWebpackPlugin({
template: './src/index.html',
//压缩html的配置
minify: {
//移出空格
collapseWhitespace: true,
//移出注释
removeComments: true
}
}),
],
//生产环境自动会压缩js代码
mode: 'production'
}
生产环境配置(代码)
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
//定义node.js环境变量,决定使用borwserslist的哪个环境
process.env.NODE_ENV = 'production'
//复用loader
const commonCssLoader = [
//压缩css
MiniCssExtractPlugin.loader,
"css-loader",
//css兼容 注意还需要再package.json中配合着browserlist使用
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')()
]
}
}
]
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css&/,
use: [...commonCssLoader],
},
{
test: /\.less&/,
use: [
...commonCssLoader,
"less-loader",
]
},
/*
正常来讲一个文件只能被一个loader处理
当一个文件被多个loader处理,那么一定要指定loader执行的先后是顺序
先执行eslint 再执行babel
*/
{
//js的语法检查 需要配合着package.json中的eslintConfig--->airbnb
test: /\.js&/,
//排除对node_modules的检查
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre',//优先执行
options: {
//自动修复
fix: true
}
},
//js的兼容性处理
{
test: /\.js$/,
//排除对node_modules的检查
exclude: /node_modules/,
loader: 'babel-loader',
options: {
//预设:指示babel做怎样的兼容性处理
presets: [
//只能做基本的兼容性处理
'@babel/preset-env',
//一开始是使用@babel/polyfill 这个库,但是会所有兼容性处理全部引进项目,增加项目体积,所以采用了下面的corejs这种方式
{
useBuiltIns: 'usage',
corejs: { version: 3 }, //指定core-js版本
//指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
}
},
{
//处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]'
},
//关闭es6模块化
esMoudle: false
},
{
//处理html中引入图片资源
test: /\.html$/,
loader: 'html-loader',
},
{
//处理其他资源
test: /\.(html|js|css|less|jpg|png|gif)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: "media"
}
},
]
},
plugins: [
//处理html
new HtmlWebpackPlugin({
template: './src/index.html',
//压缩html的配置
minify: {
collapseWhitespace: true, //移出空格
removeComments: true //移出注释
}
}),
new MiniCssExtractPlugin({
filename: "css/built.css"
}),
//压缩css
new OptimizeCssAssetsWebpackPlugin()
],
mode: 'production'
}
webpack 性能优化
优化的内容:开发环境的优化 和 生产环境的优化
开发环境的优化:
- 优化打包构建速度
- 优化代码调试
生产环境的优化
- 优化打包构建速度
- 优化代码运行的性能
开发环境的优化
打包构建速度的优化
HMR:hot module replacement 热模块替换/模块热替换
作用:一个模块的发生变化,只会重新打包这一个模块(而不是打包所有的模块),极大提升了构建速度
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
port:3000,
open:true,
//开启热模块替换
hot:true
}
HRM对不同文件处理的结果
样式文件:
可以使用HRM功能:因为style-loader内部实现
js文件:
js文件默认是没有HRM的功能 —>需要修改js代码,添加支持HRM功能的代码
注意:HRM功能对js文件的处理,只能处理非入口js文件的其他文件,因为如果是入口文件做了HRM功能,那么只要入口文件发生变化,其他的js文件都会发生变化,因为其他文件再入口文件中都有引入
import print from './print'
console.log('index.js文件被加载了')
print()
function add(x,y){
return x+y
}
console.log(1,2)
if(moudle.hot){
//一旦moudle.hot 为true,说明开启了HRM功能,---->让HRM功能代码生效
moudle.hot.accept('./print.js',function(){
//方法会监听print.js 文件的变化,一旦发生变化,其他默认不会重新打包构建
//会执行后面的回调函数
print()
})
}
html文件
html文件默认是没有HRM功能,同时会导致问题:html文件不能热更新了(不用做HRM功能)
解决:修改entry入口,将html文件引入
entry:['/src/js/index.js','./src/index.html']
但是这么解决还是一个问题:就是html一更新,所有的文件都会重新加载一边,还是没办法做到HRM。
因为html文件只有一个,所以当html文件发生变化的时候,它肯定是要重新夹杂的,所以,html文件时不需要做HRM功能的
调试代码的优化
source-map:一种提供源代码到构建后代码映射技术 (如果构建后代码出错,通过映射可以追踪源代码错误)
先说总结: 开发环境使用eval-source-map 生产环境使用:source-map
配置devtool 属性为true
devServer:{
contentBase:reslove(__dirname,'build'),
compress:true,
port:3000,
open:true,
hot:true
},
devtool:'source-map'
source-map 类型
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
-
source-map:外部
错误代码准确信息 和 源代码的错误位置都能准确提示
-
inline-source-map: 内联(只生成一个source-map)
错误代码准确信息 和 源代码的错误位置都能准确提示(和source-map 基本一致)
-
hidden-source-map:外部
错误代码错误原因可以提示到,但是没有错误位置
不能追踪到源代码的错误位置,只能提示到构建后代码的错误位置
-
eval-source-map:内联(每一个文件都生成对应的source-map,都在eval)
每一个文件都生成对应的source-map,都再eval
错误代码准确信息 和 源代码的错误位置
-
nosources-source-map:外部
错误代码准确信息 ,但是没有任何源代码的信息
-
cheap-module-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 / eval-cheap-module-source-map
生产环境:源代码是否需要隐藏?调试要不要友好?
内联会让代码体积变大,随意再生产环境不用内联
nosources-source-map 源代码和构建代码 全部隐藏
hidden-source-map 只隐藏 源代码,会提示构建后代码提示错误
综合选取: source-map / cheap-module-source-map
生产环境的优化
oneof
正常来讲一个文件只能被一个loader处理。但在执行的时候,该文件会将loader中的所有ruler都过一遍,如果符合,则被对应的loader处理,如果不符合就直接通过,这样对构建的性能很不友好,所有可以用oneof。oneof可以在遇到第一个与之对应的loader之后,不会再往下进行。
oneOf里面的loader只匹配一个。不能有两个配置处理同一种类型的文件
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
//定义node.js环境变量,决定使用borwserslist的哪个环境
process.env.NODE_ENV = 'production'
//复用loader
const commonCssLoader = [
//压缩css
MiniCssExtractPlugin.loader,
"css-loader",
//css兼容 注意还需要再package.json中配合着browserlist使用
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')()
]
}
}
]
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{ /*
正常来讲一个文件只能被一个loader处理
当一个文件被多个loader处理,那么一定要指定loader执行的先后是顺序
先执行eslint 再执行babel
*/
//js的语法检查 需要配合着package.json中的eslintConfig--->airbnb
test: /\.js&/,
//排除对node_modules的检查
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre',//优先执行
options: {
//自动修复
fix: true
}
},
{
oneof: [
{
test: /\.css&/,
use: [...commonCssLoader],
},
{
test: /\.less&/,
use: [
...commonCssLoader,
"less-loader",
]
},
//js的兼容性处理
{
test: /\.js$/,
//排除对node_modules的检查
exclude: /node_modules/,
loader: 'babel-loader',
options: {
//预设:指示babel做怎样的兼容性处理
presets: [
//只能做基本的兼容性处理
'@babel/preset-env',
//一开始是使用@babel/polyfill 这个库,但是会所有兼容性处理全部引进项目,增加项目体积,所以采用了下面的corejs这种方式
{
useBuiltIns: 'usage',
corejs: { version: 3 }, //指定core-js版本
//指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
}
},
{
//处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]'
},
//关闭es6模块化
esMoudle: false
},
{
//处理html中引入图片资源
test: /\.html$/,
loader: 'html-loader',
},
{
//处理其他资源
test: /\.(html|js|css|less|jpg|png|gif)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: "media"
}
},
]
}
]
},
plugins: [
//处理html
new HtmlWebpackPlugin({
template: './src/index.html',
//压缩html的配置
minify: {
collapseWhitespace: true, //移出空格
removeComments: true //移出注释
}
}),
new MiniCssExtractPlugin({
filename: "css/built.css"
}),
//压缩css
new OptimizeCssAssetsWebpackPlugin()
],
mode: 'production'
}
缓存
babel缓存
使用cacheDirectory :true
第二次构建是会读取之前的缓存
文件资源缓存
文件资源缓存其实就是修改文件名,防止文件再http的强制缓存中读取,文件资源已经改了,但是文件没有重新从后台拿取
hash:每次webpack构建时,都会生成一个唯一hash值
问题:因为js 和 css同时使用一个hash值(webpack生成的hash),如果重新打包,会导致所有的缓存都失效(可能只改了一个文件)
chunkhash:根据chunk生成的hash值。如过打包来源于同一个chunk,那么hash就是一样的
问题: js 和 css 还是同一个hash 值。(因为css是在js中被引入的,所以同属于一个chunk)
contenthash:根据文件内容生成hash值。不同文件hash一定不一样
tree shaking (树摇)
前提:
- 必须使用Es6 模块化
- 开启production环境
作用:减少代码的体积
问题:可能会把css也树摇掉
方案:在package.json 设置sideEffects:[‘*.css’]
sideEffects:['*css','*less']
code split (代码分割)
1. 多入口
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
process.env.NODE_ENV = 'production'
module.exports = {
//单入口
// entry: './src/js/index.js',
//多入口:有一个入口,最终输出就有一个bundle
entry: {
main: "./src/js/index.js",
test: "./src/js/test.js"
},
output: {
//[name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
],
mode: 'production'
}
2. optimization [ˌɒptɪmaɪˈzeɪʃən]配置
- 可以将node_modules中的代码单独打包成一个chunk,最终输出
- 同时在多入口模式下,可以自动分析多入口的chunk中,有没有公共文件,如果有,会打包成单独的一个chunk
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
process.env.NODE_ENV = 'production'
module.exports = {
//单入口
entry: './src/js/index.js',
output: {
//[name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
],
/*
可以将node_modules中的代码单独打包成一个chunk,最终输出
同时在多入口模式下,可以自动分析多入口的chunk中,有没有公共文件,如果有,会打包成单独的一个chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
}
},
mode: 'production'
}
3. 通过js代码,让某一个文件被单独打包成一个chunk
利用import 动态导入语法:能将某个文件单独打包
import (/* webpackChunkName: 'test'*/'.test').then((result)=>{
//文件加载成功
console.log(result)
})
.cathch(()=>{
console.log('文件加载失败')
})
懒加载与预加载
懒加载和预加载都是通过自己写代码实现
懒加载
当文件需要使用的时候才加载
console.log('index.js 文件被加载了')
document.getElementById('btn').onClick = function () {
//懒加载
import('./test').then(({ mul }) => {
console.log(mul(4, 5))
})
}
预加载 prefetch
会在使用之前,提前加载js文件
console.log('index.js 文件被加载了')
document.getElementById('btn').onClick = function () {
//懒加载
impor(/* webpackChunkName: 'test',webpackPrefetch:true */'./test').then(({ mul }) => {
console.log(mul(4, 5))
})
}
PWA
渐进式网络开发应用程序(离线可访问)
利用workbox 插件:workbox-webpack-plugin
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
process.env.NODE_ENV = 'production'
module.exports = {
//单入口
entry: './src/js/index.js',
output: {
//[name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new WorkboxWebpackPlugin.GenerateSW({
/*
1.帮助serviceworker快速启动
2. 删除就的serviceworker
生成一个serviceworker配置文件
*/
clientClaim: true,
skipWaiting: true
})
],
/*
可以将node_modules中的代码单独打包成一个chunk,最终输出
同时在多入口模式下,可以自动分析多入口的chunk中,有没有公共文件,如果有,会打包成单独的一个chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
}
},
mode: 'production'
}
同时需要在入口文件中注册serviceworker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceworker
.register('/service-worker.js')
.then(() => {
console.log('sw注册成功了')
})
.catch(() => {
console.log('sw注册失败了')
})
})
}
在入口文件这么写可能会有问题:
-
eslint 不认识 window 、navigator全部变量
解决:需要修改package.json中eslintConfig配置
"eslintConfig":{
"extends":"airbnb-base",
"env":{
"browser":true //支持浏览器全局变量
}
}
- sw代码必须运行在服务器上
多线程打包
使用thread-loader
给babel用
多线程打包有利有弊,进程开启时间大概为600ms,进程通信也有开销
只有工作消耗时间比较长的,才需要多进程打包
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
//定义node.js环境变量,决定使用borwserslist的哪个环境
process.env.NODE_ENV = 'production'
//复用loader
const commonCssLoader = [
//压缩css
MiniCssExtractPlugin.loader,
"css-loader",
//css兼容 注意还需要再package.json中配合着browserlist使用
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')()
]
}
}
]
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{ /*
正常来讲一个文件只能被一个loader处理
当一个文件被多个loader处理,那么一定要指定loader执行的先后是顺序
先执行eslint 再执行babel
*/
//js的语法检查 需要配合着package.json中的eslintConfig--->airbnb
test: /\.js&/,
//排除对node_modules的检查
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre',//优先执行
options: {
//自动修复
fix: true
}
},
{
oneof: [
{
test: /\.css&/,
use: [...commonCssLoader],
},
{
test: /\.less&/,
use: [
...commonCssLoader,
"less-loader",
]
},
//js的兼容性处理
{
test: /\.js$/,
//排除对node_modules的检查
exclude: /node_modules/,
use: [
{
loader:'thread-loader',
options:{
worker:2 //进程2个
}
},
{
loader: 'babel-loader',
options: {
//预设:指示babel做怎样的兼容性处理
presets: [
//只能做基本的兼容性处理
'@babel/preset-env',
//一开始是使用@babel/polyfill 这个库,但是会所有兼容性处理全部引进项目,增加项目体积,所以采用了下面的corejs这种方式
{
useBuiltIns: 'usage',
corejs: { version: 3 }, //指定core-js版本
//指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
}
},
],
},
{
//处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]'
},
//关闭es6模块化
esMoudle: false
},
{
//处理html中引入图片资源
test: /\.html$/,
loader: 'html-loader',
},
{
//处理其他资源
test: /\.(html|js|css|less|jpg|png|gif)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: "media"
}
},
]
}
]
},
plugins: [
//处理html
new HtmlWebpackPlugin({
template: './src/index.html',
//压缩html的配置
minify: {
collapseWhitespace: true, //移出空格
removeComments: true //移出注释
}
}),
new MiniCssExtractPlugin({
filename: "css/built.css"
}),
//压缩css
new OptimizeCssAssetsWebpackPlugin()
],
mode: 'production'
}
externals
防止将某些 import 的包(package)打包到 bundle 中,而是在运行时再去从外部获取这些扩展依赖(external dependencies)
一般配合着CDN资源使用
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
//定义node.js环境变量,决定使用borwserslist的哪个环境
process.env.NODE_ENV = 'production'
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
plugins: [
//处理html
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
mode: 'production',
externals: {
// 拒绝jQuery 被打包进来
jquery: 'jQuery'
}
}
dll
使用dll 技术,对某些库(第三方库:jquery、vue、react…)进行单独打包
webpack.dll.js 文件
const webpack = require('webpack')
moudle.export ={
entry:{
//最终打包生成的[name]----->jquery
//['jquery'] ----> 要打包的库是jquey
jquery:['jquery']
},
output:{
filename:'[name].js',
path:resolve(__dirname,'dll'),
library:['[name]_[hash]'],//打包的库里面向外暴露出去的内容叫什么名字
},
plugins:[
//打包生成一个mainfest.json --> 提供和jquery映射
new webpack.Dllplugin({
name:'[name]_[hash]',//映射库的暴露内容名称
path:resolve(__dirname,'dll/mainfest.json') //输出文件路径
})
]
mode:'production'
}
webpack.config.js文件
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const AddAssetHtmlWebpackPlugin = require('add-assetHtml-webpack-plugin')
//定义node.js环境变量,决定使用borwserslist的哪个环境
process.env.NODE_ENV = 'production'
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
plugins: [
//处理html
new HtmlWebpackPlugin({
template: './src/index.html',
}),
//告诉webpack 哪些库不参与打包,同时使用是的名称也得变
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')
}),
//将某个文件打包输出去,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filePath: resolve(__dirname, 'dll/jquery.js')
})
],
mode: 'production',
externals: {
// 拒绝jQuery 被打包进来
jquery: 'jQuery'
}
}
需要知道的webpack知识
1. 启动gzip压缩
在devserver中,配置compress:true
2. css的兼容性处理
需要利用postcss-loader 和 postcss-preset-env 配合着package.json中的browserslist 来实现
3.优化开发环境的打包构建速度-HRM
css的HRM:无须处理,因为style-loader内部已经处理过了
js的HRM:·只能处理非入口文件的js文件的HRM,需要添加能够实现HRM功能的js代码
if(moudle.hot){
moudle.accept('./文件名.js',function(){
//相应的回调函数
})
}
html的HRM:无需做
4.开发环境下的代码调试
使用source-map技术,在开发环境下使用eval-source-map (速度快,调试友好) ,在生产环境下使用source-map(调试友好)
5.生成环境下的性能优化
-
oneof
-
缓存
- babel缓存
- 文件资源缓存
- hash
- chunkhash
- contenthash
-
tree shaking
作用:减少代码体积,
前提:开启了es6模块化,必须时production环境
可能会对css文件进行树摇 ,解决方案就是在package.json中设置
sideEffects:['*.css','*.less']
-
code split
- 多入口文件 配置entry为一个对象 ,同时给出口文件的filename 里 添加 [name]属性
- 配置optimization,将node_modules单独打包成一个chunk ,或者在多入口文件,使用这个属性,可以加公共文件打包成一chunk
- 使用import 动态导入语法
-
懒加载和预加载
其实懒加载和预加载都是使用import语法来实现的
-
externals
配合着CDN资源使用,将一些包不打到bundle中
-
dll
需要打包一次,以后就不打包了