# webpack基本使用
## 样式资源引入
import"index.css"
{
test: /\.css$/,
use: [
// 创建style标签,将js中的样式资源添加到header中生效,且不是直接写入到html中,是通过js执行时写入
'style-loader',
// // 将css变成commonjs模块加载到js中,里面的内容是样式字符串
'css-loader'
]
}
处理css和js中的图片用到file-loader、url-load
{
test: /\.(png|jpg|jpeg)$/,
use: 'url-loader',
options: {
// 图片大小小于8KB时,将图片转为Base64处理,base64会导致图片变大
limit: 8 * 1024
}
}
- 打包其他资源
如在css中的字体文件,但是打包后会将这些文件名更改为MD5
{
exclude: /\.(css|js|html)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
分离css文件
用到的插件min-css-extract-plugin,需要在将style-loader换成是MinCssExtractPlugin.loader
{
test: /\.css$/,
// use中的执行顺序是从下至上
use: [
MinCssExtractPlugin.loader, // 提取js中的css,分离成单独的文件
// 将css变成commonjs模块加载到js中,里面的内容是样式字符串
'css-loader',
]
},
new MinCssExtractPlugin({
filename: 'public/index.css'
})
修改css的兼容性
引入loader,postcss-loader,引入loader中的插件postcss-preset-env
帮助postcss在package.json中找到browserlist中的配置,在postcss的官网中可以找到相关配置
{
test: /\.css$/,
// use中的执行顺序是从下至上
use: [
MinCssExtractPlugin.loader, // 提取js中的css,分离成单独的文件
// 将css变成commonjs模块加载到js中,里面的内容是样式字符串
'css-loader',
{
loader: 'postcss-loader',
plugin: () => [
require('postcss-preset-env')()
]
}
]
},
package.json
"browserlist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
环境变量不是webpack中的环境变量,而是node中的环境变量,即procss.env.NODE_ENV
压缩css
用到的插件
optimize-css-assest-webpack-plugin
使用
new OptimizeCssAssetsWebpackPlugin()
js 语法检查
依赖eslint-loader eslint airbnb eslint-config-airbnb-base eslint-plugin-import
配置
{
test: /\.js$/
loader: "eslint-loader",
exclude: /node_modules/
options: {
fix: ture // 自动修复错误
}
}
设置的规则在package.json中eslintConfig
airbnb github上有规则
npm上有现成eslint-config-airbnb
一般用的是es6,所以用eslint-config-airbng-base
JavaScript兼容性处理
使用插件babel-loader、@babel/core
基本的兼容性处理
@babel/preset-env
{
loader: 'babel-loader',
exclude: /node_modules/,
options: {
preset: ['@babel-preset-env']
}
}
全部兼容性处理
@babel/profill
可以在js中引入import “@babel/profill”,但是是全部引入
按需加载需要引入core-js
{
loader: 'babel-loader',
exclude: /node_modules/,
options: {
preset: [
'@babel-preset-env',
{
useBuildIns: 'usage',
// 指定coreJS版本
corejs: {
version: 3
},
targets: {
chrome: '60',
firefox: '60',
ie: '9',
edge: '17'
}
}
]
}
}
压缩HTML
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
//移除空格
collapseWhitespace: true,
// 移除注释
removeCommnets: true
}
})
webpack性能优化
概览
开发环境
- 打包构建速度
- 优化代码调试
生产环境
- 优化构建打包速度
- 优化运行速度
HMR 模块热替换
一个模块发生变化,一个模块变化只更新变化的模块
devServer: {
content: resolve(__dirname, 'build'),
compress: true,
port: 3000,
// open: true,
hot: true // 开启HMR模式
},
样式文件,需要使用style-loader,style-loader中内部实现HMR模式
js文件, 默认不实用HMR模式
需要修改js代码,添加对HMR的功能
if(module.hot) {
module.hot.accept('./print.js', function() {
console.log('loader print.js');
});
}
HTMl文件: 不会产生变化
解决办法在entry中引入,html变化,整体都会刷新
开发环境下调试代码source-map
在webpack.config.js根对象下配置
{
devtool: 'inline-source-map'
}
- source-map
能够提供错误代码的准确位置,和源代码的准确位置 - inline-source-map 内联到文件末尾
与source-map基本一致,只是内联而已 - hidden-source-map 外联,单独生成.map文件
提示错误是构建后的电脑及错误原因 - eval-source-map 每一个都生成一个对应source-map, 在eval函数中执行
跟inline-source-map一致 - nosources-source-map 外部
能找到代码的准确信息,但是找不到任何源码的信息 - cheap-source-map 外部
与inline差不多,但是cheap只是提供到代码行,而inline会找到准确位置 - cheap-module-source-map 外部
错误代码的准确位置,和源代码的准确位置,回家loader的source-map加入
这些可以两两组合
开发环境
速度 eval > inline > cheap
速度快
- eval-cheap-source-map
- eval-source-map (一般选择这个)
调试更友好 - source-map
- cheap-module-source-map
- cheap-source-map
oneOf
修改webpack中的rule
只会匹配一个loader,同事
{
module: {
rules: [
{
test: /\.js$/
exclude: /node_modules/,
enforce: 'pre', // 优先执行
loader: 'eslint-loader',
options: {
fix: true
}
},
{
oneOf: [
]
}
]
}
}
// eslint-disable-next-line
忽略eslint检查的warn
缓存
{
output: {
filename: 'build.[hash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MinCssExtractPlugin({
filename: 'public/index.[hash:10].css'
}),
new OptimizeCssAssetsWebpackPlgin()
],
}
当出现变化时全部都重新构建,相关联的hash也变化,因为js和css使用同一个hash
babel缓存catchDireactory:true
{
output: {
filename: 'build.[chunkhash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MinCssExtractPlugin({
filename: 'public/index.[chunkhash:10].css'
}),
new OptimizeCssAssetsWebpackPlgin()
],
}
关联时也会全部重新构建
根据文件来单独hash用contenthash
{
output: {
filename: 'build.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MinCssExtractPlugin({
filename: 'public/index.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlgin()
],
}
代码树摇
前提条件必须es6,production环境,webpack自动tree shaking
在package.json中写sideEffects: false,所有代码都可以进行tree shaking,会把css文件文件干掉
sideEffects:[’*.css’]
代码分割
多入口
{
entry: {
index: './src/index.js',
test: './src/test.js'
},
output: {
filename: './js/[name].[contenthash:10].js',
path: resolve(__dirname,'dist')
}
}
单入口
webpack.config.js 根
自动分析多入口中有没有公用的文件
optimization: {
// 将node_modules中代码单独打包成一个chunk
splitChunks: 'all'
}
通过js将一个文件单独打包成一个chunk
import('./simple.js').then(() => {
console.log('load success!');
});
懒加载
在代码中import
btn.onclick = () => {
import(/* webpackChunkname: 'test'*/).then(() => {
console.log('load success!');
});
}
预加载
btn.onclick = () => {
import(/* webpackChunkName: 'test', webpackPrefetch: true */).then(() => {
console.log('load success!');
});
}
PWA 离线 渐进式开发
采用workbox技术
插件workbox-webpack-plugin
const WorkWebpackPlugin = require('work-webpack-plugin');
{
Plugins: [
new WorkWebpackPlugin({
/*
帮助serviceworker快速启动,删除旧的serviceworker
生成一个serviceworker文件
*/
clientClaim: true,
skipWwaiting: true
});
]
}
在代码中
if('serviceWorker' in navigater) {
navigater.serviceWorker.register('./serviceworker.js').then(() => {
console.log('regist successful');
}).catch(() => {
console.log('regist error!');
});
}
多进程打包
用到的loader: thread-loader
用在babel-loader中
{
test: /\.js$/
exclude: /node_modules/,
use: [
'thread-loader',
{
loader: 'thread-loader',
options: {
workder: 2 // 两个进程
}
},
{
loader: 'babel-loader',
exclude: /node_modules/,
options: {
preset: [
'@babel-preset-env',
{
useBuildIns: 'usage',
// 指定coreJS版本
corejs: {
version: 3
},
targets: {
chrome: '60',
firefox: '60',
ie: '9',
edge: '17'
}
}
]
}
]
}
有利有弊
开启也是需要时间,进程之间通信也是要成本的
只有工作需要消耗大量时间时才使用
external
打包时忽略的一些包
webpack.config.js根
externals: {
// 忽略掉指定的包名,jquery
jquery:
}
dll
对一个库进行打包,第三方库打包,可以打包成不同chunk
webpack.dll.js
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
jquery: ['jquery']
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash]'
},
plugin: [
new webpack.DllPlugin({
name: '[name]_[hash]', // 映射库的名称
path: resolve(__name, 'dll/manifest.json') // 提供jquery的包的映射关系
})
]
}
webpack.config.js
const webpack = require('webpack');
const addAssetsHtmlWebpackPlugin = require('add-html-webpack-plugin');
{
plugin: [
// 高速webpack哪些库不参与打包,使用时的名称也将会被更改
new webpack.DllReferencPlugin({
manifest: resolve(__dirname, 'dll/manifest.json')
}),
new addAssetsHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')
});
]
}
其他
{
output: {
filename: '/js/[name].js',
path: resolve(__dirname, 'dist'),
publicPath: '/',
chunkFilename: '[name]_chunk.js', // 非入口chunk的名称,
labraryTarget: 'window' // node commonjs
}
}
resolve
{
resolve: {
alias: {
$css: resolve(__dirname, 'src/css')
},
extensions: ['.js', '.json'],
modules: [
'node_modules',
]
}
}
devServer
{
// 项目构建后的目录
contentBase: resolve(__dirname, 'dist'),
// 启动gizp压缩
compress: true,
// 端口好
port: 3000,
// 自动打开浏览器
open: true,
// 开启HMR功能,
hot: true,
// 监视contentbase目录变化重载
watchContentBase: true,
// 不要启动服务器日志
clientLogLevel: 'none',
quiet: true, // 不要打印其他不必要的信息
watchOptions: {
ignored: /node_modules/
},
overlay: false, // 出现错误不要全屏提示,
proxy: {
'/api': {
target: 'http://localhost:5000',
pathRewrite: {
'^/api': '' // 路径重写
}
}
}
}
optimizions
const TerserWebpackPlugin = requrie('terser-webpack-plugin');
{
optimizions: {
splitChunk: 'all', //
miniSize: 30 * 1024, // 最小分割size
maxSize: 0, // 都要分割,
minChunck: 1, // 最少被引入一次
maxAsyncRequest: 5, // 最大并行加载数
maxInitialRequest: 3, // 入口最大请求并行数量
automaticNameDelimiter: "~",// 命名链接规则
name: true, // 可以使用,
cacheGroups: { // 分割chunk组
// node_modules中的文件会打包到vendor中
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
// 要提取的chunk至少被引用两次
minChunk: 2,
priority: -20,
// 如果当前要打包的模块,和之前已经被提取的模块是同一个,复用不必在打包
reuseExistingChunk: true,
}
},
// 将当前模块记录其他模块的hash值单独打包到一个文件中将runtime文件
runtimeChunk: {
name: entrypoint=> 'runtime-${entryport.name}'
},
minimizer: [
new TerserWebpackPlugin(
cache: true, // 开启缓存
parallel: true, // 开启多进程打包
sourceMap: true
)
]
}
}