我的前端之路笔记
cdn资源 cdn资源
webpack官网
webpack插件
webpack笔记
解决作用域问题 快速执行函数
;(function(){ … })
解决代码拆分问题 node commonjs 模块化
解决浏览器支持问题 requirejs
想要主js调用别的js要在主js前引入
hello.js export hello()
main.js hello()
import hello.js import main.js
安装webpack
先安装node
然后安装webpack webpack-cli 全局安装(不推荐,会锁定版本)
npm install webpack webpack-cli --global
本地安装
代码语言:javascript复制npm init
npm install webpack webpack-cli --save-dev
cmd cls清屏
webpack打包
代码语言:javascript复制webpack
webpack --stats detailed 查看详细打包信息
npx牛逼
配置入口文件(指令不如文件配置不可保存)
webpack --entry xxx
加 --mode production生产环境
配置出口
output
文件配置
webpack.config.js文件
绝对路径 使用 require(‘path’)
代码语言:javascript复制path.resolve(__dirname,'xxx')
module.exports = {
entry:'',
output:{
filename: '',
path: '结对路径''
}
}
自动引入资源
插件-html-webpack-plugin
代码语言:javascript复制npm install html-webpack-plugin
引入
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
在根{}下
代码语言:javascript复制plugins:[
new HtmlWebpackPlugin()
]
配置HtmlWebpackPlugin
new HtmlWebpackPlugin({
template: './index.html', 模板文件
filename: 'app.html', 生成文件名
inject: 'body' 在哪个标签引入
})
清理dist(清理旧的打包)
在output选项里面
代码语言:javascript复制output:{
filename: '',
path: '结对路径'',
clean: true
}
搭建开发环境
mode选项
定位错误
更好显示代码定位错误
代码语言:javascript复制devtool: 'inline-source-map',
监听代码变化
代码语言:javascript复制webpack --watch
使用 webpack-dev-server
代码语言:javascript复制npm install webpack-dev-server
加-D 在本地开发环境运行
在 配置文件中
代码语言:javascript复制devServer: {
devServer: {
static: './dist' //注意这里的./dist是路径
}
}
在控制台 webpack-dev-server
资源模块
代码语言:javascript复制module: {
rules: [
{
test: /.png$/,
type: 'asset/resource'
}
]
}
在js 文件中引入
代码语言:javascript复制import imgsrc from './assets/img-1.png'
const img = document.createElement('img') 创建一个照片元素
img.src = imgsrc 添加路径
document.body.appendChild(img) 将照片添加进页面
webpack-dev-server --open 加–open 默认打开
在output中定义导出路径以及名字
代码语言:javascript复制output: {
filename: 'bundle.js',
path: path.resolve(__dirname,'./dist'),
clean: true,
assetModuleFilename: 'images/test.png'
},
assetModuleFilename: ‘images/[contenthash].png’ [contenthash]可自动根据hash来生成文件名
assetModuleFilename: ‘images/[contenthash][ext]’ [contenthash]可自动根据hash来生成文件名以及扩展名
若在module rules generator配置 则generator高于output
inline配置资源 使图片变成base64资源
使图片变成base64资源
代码语言:javascript复制test: /.svg$/,
type: 'asset/inline'
配置source
代码语言:javascript复制test: /.txt$/,
type: 'asset/source
配置asset
代码语言:javascript复制test: /.jpg$/,
type: 'asset'
自动选择url还是文件base64 一般小于8k会生成base64
可通过追加 parser 来控制
代码语言:javascript复制test: /.jpg$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4*1024 //默认大小4*1024
}
}
loader使用
安装css-loader以及style-loader
执行
代码语言:javascript复制npm install css-loader -D
npm install style-loader -D
配置
代码语言:javascript复制{
test: /.css$/,
use: ['style-loader','css-loader']
}
在index.js引入 import ‘./style.css’
先执行css-loader再执行style-loader
安装配置less-loader css-loader
代码语言:javascript复制npm install less-loader less -D
配置
代码语言:javascript复制{
test: /.(css|less)$/,
use: ['style-loader','css-loader','less-loader']
}
在index.js引入 import ‘./style.less’
抽离和压缩css
安装插件
代码语言:javascript复制npm install mini-css-extract-plugin -D
在webpack.js引入
const MiniCssExtract = require(‘mini-css-extract-plugin’)
在plugins中添加
new MiniCssExtract()
配置
代码语言:javascript复制{
test: /.(css|less)$/,
use: [MiniCssExtract.loader','css-loader','less-loader']
}
更换style-loader为MiniCssExtract.loader
style-loader作用是将css连接到页面 而为了抽离改为MiniCssExtract.loader
自定义生成的文件名
new MiniCssExtract({ filename: ‘styles/[contenthash].css’ })
压缩
安装插件
代码语言:javascript复制npm install css-minimizer-webpack-plugin -D
引入
const CssMinimizerPlugin = require(‘css-minimizer-webpack-plugin’)
在优化配置中配置
webpack配置根级
代码语言:javascript复制optimization: {
minimizer: [
new CssMinimizerPlugin()
]
}
注意配置此项之后 代码压缩会失效 需要单独配置terser
且mode更换为生产环境
mode: ‘production’,
加载images图像
图片优先级
.block-bg{ background-image: url(./assets/webpack-logo.svg) !important; }
!important 使优先级最高
加载字体
配置webpack
代码语言:javascript复制{
test: /.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource'
}
在css文件引入字体文件
代码语言:javascript复制@font-face {
font-family: 'iconfont';
src: url('./assets/iconfont.ttf');
}
.icon{
font-family: 'iconfont';
font-size: 30px;
}
在index.js引入字体
代码语言:javascript复制const span = document.createElement('span')
span.classList.add('icon')
span.innerHTML = ''
document.body.appendChild(span)
加载数据 csv-loader xml-loader
安装
代码语言:javascript复制npm install csv-loader xml-loader -D
配置
代码语言:javascript复制{
test: /.(csv|tsv)$/,
usr: 'csv-loader'
},
{
test: /.xml$/,
usr: 'xml-loader'
}
引入数据在index.js
代码语言:javascript复制import Data from './assets/data.xml'
import Notes from './assets/data.csv'
xml转成js对象
csv转换为数组
自定义JSON的parser 例如toml yaml json5
安装
代码语言:javascript复制npm install toml yaml json5 -D
配置webpack
代码语言:javascript复制const toml = require('toml')
const yaml =require('yaml')
const json5 = require('json5')
代码语言:javascript复制{
test: /.toml$/,
type: 'json',
parser: {
parse: toml.parse
}
},
{
test: /.yaml$/,
type: 'json',
parser: {
parse: yaml.parse
}
},
{
test: /.json5$/,
type: 'json',
parser: {
parse: json5.parse
}
}
使用文件
babel-loader
将es6转化为es5
babel-loader:在webpack解析es6 @babel/core:babel核心模块 @babel/preset-env:babel预定,一组babel插件的集合
安装
代码语言:javascript复制npm install -D babel-loader @babel/core @babel/preset-env
配置
{ test: /.js$/, exclude: /node_modules/, use: { loader: ‘babel-loader’, options: { presets: [’@babel/preset-env’] } } }
解决报错regeneratorRuntime
原因 babel生产用于兼容async/await
安装插件 @babel/runtime
代码语言:javascript复制npm install @babel/runtime -D
安装插件 @babel/plugin-transform-runtime
代码语言:javascript复制npm install @babel/plugin-transform-runtime -D
配置
代码语言:javascript复制{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
['@babel/plugin-transform-runtime']
]
}
}
}
分离代码
如果有多个入口文件
代码语言:javascript复制entry: {
index: './src/index.js',
another: './src/another-module.js'
},
出口的filename: '[name].bundle.js',
但是这样会导致重复打包
避免重复
方案一 共享
代码语言:javascript复制entry: {
index: {
import: './src/index.js',
dependOn: 'shared'
},
another: {
import: './src/another-module.js',
dependOn: 'shared'
},
shared: 'lodash'
},
方案二 配置splitChunks
optimization: { splitChunks: { chunks: ‘all’ } }
动态(异步)导入
如下
代码语言:javascript复制function getComponent() {
return import('lodash')
.then(({default: _})=>{
const element = document.createElement('div')
element.innerHTML = _.join(['hello','webpack'],' ')
return element
})
}
getComponent().then((element)=>{
document.body.appendChild(element)
})
const button = document.createElement('button')
懒加载
代码语言:javascript复制button.textContent = '点击加法运算'
button.addEventListener('click',()=>{
import(/* webpackChunkName: 'math' */'./math').then(({add})=>{
console.log(add(4,5))
})
})
document.body.appendChild(button)
import(/* webpackChunkName: ‘math’ */’./math’)魔法注释 可以设置打包文件名
预加载预获取
prefetch 浏览器空闲时加载
import(/* webpackPrefetch: true */
preload 类似懒加载
import(/* webpackPreload: true */
缓存
输出文件名
filename: ‘[name].[contenthash].js’,
缓存第三方库
代码语言:javascript复制optimization: {
minimizer: [
new CssMinimizerPlugin()
],
splitChunks: {
cacheGroups: {
vendor: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
js放到一个文件夹
output: { filename: ‘scripts/[name].[contenthash].js’, …
开发配置
公共路径
在output中 加入publicPath: ‘http://localhost:8080/’
环境变量
module.exports = (env) => { console.log(env) return { webpack配置项 可通过env参数配置 } }
比如
mode: env.production ? ‘production’ :‘development’
webpack --env production
可以传参 a = 1
压缩代码 使用terser-webpack-plugin -D
代码语言:javascript复制npm install terser-webpack-plugin -D
使用
代码语言:javascript复制optimization: {
minimizer: [
new CssMinimizerPlugin(),
new TerserPlugin()
],
...
拆分配置文件
开发环境和生产环境
开发环境
项目根目录新建webpack.config.dev.js 开发环境
修改mode为开发环境
去掉压缩代码以及公共路径或包括缓存
启动
webpack -c ./config/webpack.config.dev.js
-c可用 -config替换
注意生成的文件的路径
生产环境
在config目录下新建 webpack.config.prod.js文件
修改mode为生产环境
删除调试 devtool dev-server
启动
webpack -c ./config/webpack.config.prod.js
额外webpack serve (webpack-dev-server)
可通过 webpack serve -c ./config/webpack.config.dev.js
npm 脚本
在项目根目录下 package.json
代码语言:javascript复制{
"scripts": {
"start": "npx webpack server -c ./config/webpack.config.dev.js",
"build": "npx webpack -c ./config/webpack.config.prod.js"
}
}
忽略性能优化提示
在webpack配置根{}下
performance: { hints: false }
提取公共配置
项目根目录创建webpack.config.common.js文件
去除掉 dev prod中相同配置
合并配置文件 使用webpack-merge
安装
代码语言:javascript复制npm install webpack-merge -D
config目录下创建 wenpacj.config.js
代码语言:javascript复制const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.config.common')
const productionConfig = require('./webpack.config.prod')
const developmentConfig = require('./webpack.config.dev')
module.exports = (env) => {
switch (true) { //可定义key-value判断
case env.development:
return merge(commonConfig,developmentConfig)
case env.production:
return merge(commonConfig,productionConfig)
default:
return new Error('No matching configuration was found')
}
}
source-map
新建目录 npm init 初始化
安装 npm install webpack webpack-cli webpack-dev-server html-webpack-plugin -D
默认devtool为eval
‘source-map’
会生产main.js.map 且生产的main.js注释里会显示sourceUrl main.js.map(显示行列) 且关联 能找到代码问题
‘hidden-source-map’
会生产main.js.map 且生产的main.js注释里不会显示sourceUrl main.js.map 且不关联 不能直接找到代码问题
‘inline-source-map’
不会生产main.js.map 但生产的main.js注释里会显示sourceUrl main.js.map 且关联 能找到代码问题
‘eval-source-map’
不会生成sourcemap文件 而是放到了eval后面 能找到代码问题
‘cheap-source-map’
生成map文件 mappings带有行数不带列 能找到代码问题
‘cheap-module-source-map’ 推荐开发环境
生成map文件 mappings带有行数不带列 带有module的 能找到代码问题
webpack-server 配置
代码语言:javascript复制devServer: {
static: path.resolve(__dirname, './dist'),
compress: true, //代码压缩 增加gzip
port: 3000, //端口号
host: '0.0.0.0', //局域网下可访问
headers: {
'X-Access-Token': 'abc123'
},
proxy: { //代理配置
'/api': 'http://localhost:9000'
},
// https: true, //开启https
// {
// cacert: './server/pem',
// pfx: './server.pfx',
// key: './server.key',
// cert: './server.crt',
// passphrase: 'webpack-dev-server',
// requestCert: true
// }
http2: true, //开启 http2 https默认自签名
historyApiFallback: true //历史路径
}
模块热替换和热加载
热替换
hmr在webpack5不需要再繁琐配置 疫情开箱即用
代码语言:javascript复制devServer: {
hot: true
}
修改js热更新
在app.js
代码语言:javascript复制if(module.hot){
module.hot.accept('./input.js', () => {
})
}
热加载
代码语言:javascript复制devServer: {
liveReload: true
}
代码规范 eslint
安装
代码语言:javascript复制npm i eslint -D
代码语言:javascript复制eslint ./src
项目使用
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/app.js',
module: {
rules: [
{
test: /.js$/,
usr: ['babel-loader','eslint-loader'] //先eslint-loader'
},
],
},
plugins: [
new HtmlWebpackPlugin()
]
};
开启后可关闭报错
代码语言:javascript复制devServer: {
client: {
overlay: false //报错覆盖层
}
}
Githooks–Husky
目的 提交之前检测代码
基本原理
.git/hooks/pre-commit文件
文件内容
代码语言:javascript复制eslint ./src
或者
npx eslint ./src
自定义
新建目录 .mygithooks
文件 .mygithooks/pre-commit 内容一样
git 配置
git config core.hooksPath .mygithoosk
Husky
代码语言:javascript复制npm husky install -D
huxky install
package.json
"main": "index.js",
"scripts": {
"prepare": "husky install"
},
在./husky目录下 新增pre-commit文件
记得给予 pre-commit 文件权限 ( x)
写入 npx eslint .src
执行
git add.
git commit -m ‘xxx’
如果代码出错会提示
探索webpack原理
解析绝对目录
别名配置
用@ 指向 src
webpack.js
代码语言:javascript复制resolve: {
alias: {
'@': path.resolve(__dirname,'./src')
}
}
优先级配置 默认 js>json
配置
代码语言:javascript复制resolve: {
alias: {
'@': path.resolve(__dirname,'./src')
},
extensions: ['.json','.js','vue']
}
配置外部资源引入(链接引入)
方式一
wepack配置文件
代码语言:javascript复制externals: {
jquery: 'jQuery'
}
在html模板文件里面加入
代码语言:javascript复制<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
方式二
wepack配置文件
代码语言:javascript复制externalsType: 'script', //暴露为script标签
externals: {
jquery: [
'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js', //链接
'$' //暴露标签
]
}
依赖图
安装
代码语言:javascript复制npm i webpack-bundle-analyzer -D
引入
代码语言:javascript复制const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
plugins: [
new BundleAnalyzerPlugin()
]
启动webpack serve就会弹出
PostCSS和CSS模块 处理浏览器css兼容问题
安装
npm i postcss-loader -D
npm i autoprefixer -D
配置 webpack
代码语言:javascript复制module: {
rules: [
{
test: /.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}
]
}
配置 postcss.config.js
在根目录下创建文件
代码语言:javascript复制module.exports = {
plugins: [
require('autoprefixer')
]
}
使用
在package.json目录下 根{}
代码语言:javascript复制"browserslist": [
"> 1%", //全球浏览器使用率要大于1%
"last 2 versions" //每个浏览器的最近两个版本
]
插件 postcss-nested
支持比如 body下包括div的 这种
安装
npm i postcss-nested -D
配置postcss.config.js
代码语言:javascript复制module.exports = {
plugins: [
require('autoprefixer'),
require('postcss-nested')
]
}
开启css模块化
代码语言:javascript复制use: ['style-loader',
{
loader: 'css-loader',
options: {
modules: true //开启css模块化
}
}
, 'postcss-loader'],
exclude: [path.resolve(__dirname,'..','node_modules')] //排除外部modules
可设置两个配置 一个全局一个局部
如下 在webpack配置
全局配置
代码语言:javascript复制{
test: new RegExp(`^(?!.*\.global).*\css`),
use: ['style-loader',
{
loader: 'css-loader',
options: {
modules: true //开启css模块化
}
}
, 'postcss-loader'],
exclude: [path.resolve(__dirname,'..','node_modules')] //排除外部modules
}
局部配置
代码语言:javascript复制{
test: new RegExp(`^(.*\.global).*\css`),
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader'
}
],
exclude: [path.resolve(__dirname,'..','node_modules')] //排除外部modules
}
WebWorks
创建一个worker const worker = new Worker(new URL(’./work.js’,import.meta.url))
接收主线程信息 self.onmessage = () => {
}
主线程接收信息 worker.onmessage = (message) => { console.log(message) }
向主线程发送信息 self.postMessage({ answer: 1111 })
主线程发送信息 worker.postMessage({ question: ‘hi,那边的worker线程,请告诉我今天的幸运数字是多少?’ })
集成typescript
安装
代码语言:javascript复制npm i typescript ts-loader -D
配置 webpack
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
mode: 'development',
entry: './src/app.ts',
devtool: 'inline-source-map',
module: {
rules: [
{
test: /.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.ts', '.js'] //设置优先ts扩展名
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, './dist')
},
plugins: [
new HtmlWebpackPlugin()
]
}
初始化ts配置文件
代码语言:javascript复制tsc --init
修改ts配置
rootDir: “./src”
outDir: “./dist”
ts 使用模块
网址 https://www.typescriptlang.org/dt/search?search=
查询需求模块安装
entry 配置
配置一
代码语言:javascript复制entry: [
'./src/app.js',
'./src/app2.js'
]
配置二
代码语言:javascript复制// entry: [
// './src/app.js',
// './src/app2.js',
// 'lodash'
// ],
entry: {
main: ['./src/app2.js', './src/app.js'],
lodash: 'lodash'
},
配置三
代码语言:javascript复制entry: {
main: {
import: ['./src/app2.js', './src/app.js'],
dependOn: 'lodash' //依赖
},
lodash: 'lodash'
},
index.html模板配置
配置一 基础配置
webpack
代码语言:javascript复制 plugins: [
new HtmlWebpackPlugin({
title: '多页面应用', //参数
template: './index.html',
inject: 'body', //引入js的地方
chunks: ['main'] //规定引入的js
})
]
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
</body>
</html>
配置二
多页面配置
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
// entry: [
// './src/app.js',
// './src/app2.js',
// 'lodash'
// ],
entry: {
main: {
import: ['./src/app2.js', './src/app.js'],
dependOn: 'lodash',
filename: 'chanel1/[name].js'
},
main2: {
import: './src/app3.js',
dependOn: 'lodash',
filename: 'chanel2/[name].js'
},
lodash: {
import: 'lodash',
filename: 'common/[name].js'
}
},
output: {
clean: true
},
plugins: [
new HtmlWebpackPlugin({
title: '多页面应用',
template: './index.html',
inject: 'body',
filename: 'chanel1/index.html',
chunks: ['main', 'lodash'],
publicPath: 'http://www.b.com'
}),
new HtmlWebpackPlugin({
template: './index2.html',
inject: 'body',
filename: 'chanel2/index2.html',
chunks: ['main2', 'lodash'],
publicPath: 'http://www.a.com'
})
]
}
Tree Shaking
移除未使用模块
配置一 usedExports
es2015特性
但是无法额外模块
配置webpack
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'production',
entry: './src/app.js',
plugins: [
new HtmlWebpackPlugin()
],
optimization: {
usedExports :true //此处开启
}
}
配置二 sideEffects
在packages.json配置
代码语言:javascript复制{
"sideEffects": true, //true都加载 false都不加载
"sideEffects": ["*.css"], //对于所有的css文件都加载,其它不加载
"sideEffects": ["*.css", "*.global.js"],//对于所有的css文件以及.global.js文件都加载,其它不加载
}
离线环境下运行
非离线环境下运行
打包完成
安装 http-server
代码语言:javascript复制npm i http-server -D
配置 packages.json
代码语言:javascript复制"scripts": {
"start": "http-server dist"
},
使webpack serve 运行时变动打包而不是内存
webpack 配置
代码语言:javascript复制devServer: {
devMiddleware: {
writeToDisk: true
}
}
添加workbox 实现pwa
安装
代码语言:javascript复制npm i workbox-webpack-plugin -D
配置
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
const WorkboxPlugin = require('workbox-webpack-plugin')
module.exports = {
mode: 'production',
entry: './src/app.js',
plugins: [
new HtmlWebpackPlugin(),
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true
})
],
浏览器注册
入口文件 app.js
代码语言:javascript复制if ('serviceWorker' in navigator) { //浏览器是否支持
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log("SW 注册成功")
console.log(registration)
})
.catch(registrationError => {
console.log("SW 注册失败", registrationError)
})
})
}
shimming 全局变量
webpack配置
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
module.exports = {
mode: 'development',
entry: './src/index.js',
plugins:[
new HtmlWebpackPlugin(),
new webpack.ProvidePlugin({
_: 'lodash'
})
]
}
使用 index.js
代码语言:javascript复制// import _ from 'lodash' //无需引入
console.log(_.join(['hello', 'webpack'], ' '))
细颗粒度 shimming
this问题 imports-loader
安装
代码语言:javascript复制npm i imports-loader -D
配置webpack
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
module.exports = {
mode: 'development',
entry: './src/index.js',
plugins:[
new HtmlWebpackPlugin(),
new webpack.ProvidePlugin({
_: 'lodash'
})
],
module: {
rules: [
{
test: require.resolve('./src/index.js'),
use: 'imports-loader?wrapper=window' //让包里的this指向window
}
]
}
}
全局exports
插件 exports-loader
代码语言:javascript复制npm i exports-loader -D
使用 webpack配置
代码语言:javascript复制module: {
rules: [
{
test: require.resolve('./src/index.js'),
use: 'imports-loader?wrapper=window'
},
{
test: require.resolve('./src/global.js'),
use: 'exports-loader?type=commonjs&exports=file,multiple|helpers.parse|parse' //相当于暴露parse:helper.parse
}
]
}
polyfills 垫片
简单原理
不能这样引入
安装 @babel/polyfill
代码语言:javascript复制npm i @babel/polyfill -D
代码语言:javascript复制import '@babel/polyfill' //垫片 这样导入 X
console.log(Array.from([1, 2, 3], x => x x))
进一步优化
安装babel环境
代码语言:javascript复制npm i babel-loader @babel/core @babel/preset-env -D
配置webpack
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
targets: [
'last 1 version', //浏览器最新的一个版本
'> 1%' //代码使用超过1%
],
useBuiltIns: 'usage',
corejs: 3
}
]
]
}
}
}
]
}
}
额外安装
代码语言:javascript复制npm install --save core-js@3
library
打包配置为不同模块
代码语言:javascript复制const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
experiments: {
outputModule:true // module时候开启此配置
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'mylib.js',
library: {
// name: 'mylib', // module时候取消此配置
type: 'module' // window/commonjs/module
}
}
}
打包为通用模块
代码语言:javascript复制const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
// experiments: {
// outputModule:true // module时候开启此配置
// },
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'mylib.js',
library: {
// name: 'mylib', // module时候取消此配置
type: 'umd' // window/commonjs/module/umd
},
globalObject: 'globalThis' //全局this代替self
}
}
构建小轮子
配置
代码语言:javascript复制const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
library: {
name: 'webpackNumbers',
type: 'umd'
},
globalObject: 'globalThis'
},
externals: { //优化依赖
lodash: {
commonjs: 'lodash',
commonjs2: 'lodash',
amd: 'lodash',
root: '_'
}
}
}
发布为 npm-package
执行
npm config get registry
确保为
“https://registry.npmjs.org/”
如果不是 切换 npm set registry “https://registry.npmjs.org/”
npm adduser 添加用户
npm publish 发布
模块联邦 多项目共享模块
使用webpack 的 ModuleFederationPlugin
先准备好两个模块
模块nav
组件js Header.js
代码语言:javascript复制const Header = () =>{
const header = document.createElement('h1')
header.textContent = '公共头部内容'
return header
}
export default Header
webpack配置项
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
const { ModuleFederationPlugin } = require('webpack').container
module.exports = {
mode: 'production',
entry: './src/index.js',
plugins: [
new HtmlWebpackPlugin(),
new ModuleFederationPlugin({
name: 'nav', //模块名
filename: 'remoteEntry.js', //模块文件名
remotes: {}, //引入的模块
exposes: { //导出的模块
'./Header': './src/Header.js' //模块路径
},
shared: {} //共享包
})
]
}
模块home引入 nav
webpack配置项
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
const { ModuleFederationPlugin } = require('webpack').container
module.exports = {
mode: 'production',
entry: './src/index.js',
plugins: [
new HtmlWebpackPlugin(),
new ModuleFederationPlugin({
name: 'home', //模块名
filename: 'remoteEntry.js', //模块文件名
remotes: { //引入的模块
nav: 'nav@http://localhost:3003/remoteEntry.js' //网络位置
},
exposes: {}, //导出的模块
shared: {} //共享包
})
]
}
使用nav下的Header
异步加载
代码语言:javascript复制import HomeList from "./HomeList";
import('nav/Header').then((Header)=>{
const body = document.createElement('div')
body.appendChild(Header.default())
document.body.appendChild(body)
document.body.innerHTML = HomeList(5)
})
模块 search 引入两个资源
暴露 home的homeList组件
代码语言:javascript复制new ModuleFederationPlugin({
name: 'home',
filename: 'remoteEntry.js',
remotes: {
nav: 'nav@http://localhost:3003/remoteEntry.js'
},
exposes: {
'./HomeList': './src/HomeList.js'
},
shared: {}
})
在webpack配置项引入
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
const { ModuleFederationPlugin } = require('webpack').container
module.exports = {
mode: 'production',
entry: './src/index.js',
plugins: [
new HtmlWebpackPlugin(),
new ModuleFederationPlugin({
name: 'search',
filename: 'remoteEntry.js',
remotes: {
nav: 'nav@http://localhost:3003/remoteEntry.js',
home: 'home@http://localhost:3001/remoteEntry.js'
}
})
]
}
在 search 中引入 index.js
代码语言:javascript复制Promise.all([import('nav/Header'),import('home/HomeList')])
.then(([
{
default: Header
},
{
default: HomeList
}
]) => {
document.body.appendChild(Header())
document.body.innerHTML = HomeList(3)
})
Promise.all() 可执行多个异步
优化
使用最新版本
webpack 以及 nodejs最新版本
内置优化
将loader应用于最少数量的必要模块
解析必要的 提高打包速度
代码语言:javascript复制{
test: /.js$/,
include: 'xxxxxx',
loader: 'xxx'
}
能不用loader和plugin就不用 引导
解析
减少 resolve,modules,resolve.extensions,resolve.mainFiles,resolve.descriptionFiles中的条目数量 来减少系统文件调用次数
如果 不使用 symlinks 设置resolve.symlinks: false
如果自定义resolve plugin规则 并且没有指定 context,可以设置resolve.cacheWithContext:false
小即快
使用更少或者更小的library
在多页面应用使用splitChunksPlugin 并且开启async
移除未引用代码
只编译当前正在开发的代码
持久化缓存
在webpack配置中使用cache选项 使用package.json中的 “postinstall” 清除缓存目录
将cache类型设置为内存或者文件系统 memory 选项很简单 它告诉webpack在内存中存储缓存
cache: { type: ‘memory’ }
自定义plugin/loader
对它们概要分析 以免在此处引入性能问题
权衡progress plugin的利弊
通用构建优化 dll
把包生成dll
代码语言:javascript复制const path = require('path')
const webpack = require('webpack')
module.exports = {
mode: 'production',
entry: {
jquery: ['jquery']
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dll'),
library: '[name]_[hash]'
},
plugins: [
new webpack.DllPlugin({
name: '[name]_[hash]',
path: path.resolve(__dirname, 'dll/manifest.json')
})
]
}
引入
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
plugins: [
new HtmlWebpackPlugin(),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, './dll/manifest.json')
})
]
}
此时并不能使用
额外配置
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const path = require('path')
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
module.exports = {
mode: 'production',
entry: './src/index.js',
plugins: [
new HtmlWebpackPlugin(),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, './dll/manifest.json')
})
,
new AddAssetHtmlPlugin({
filePath: path.resolve(__dirname, './dll/jquery.js'),
publicPath: './'
})
]
}
worker pool
注意 多个loader 从下到上运行
使用 thread-loader
用于非常耗时的loader
因为worker也会消耗资源
代码语言:javascript复制// const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
module: {
rules:[
{
test: /.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options:{
presets: ['@babel/preset-env']
}
},
{
loader: 'thread-loader',
options: {
workers: 2
}
}
]
}
]
}
}
开发环境提升构建性能
使用webpack的 watch mode
监听过多导致的cpu负载
可用watchOptions.poll来增加轮询的时间间隔
在内存中编译
webpack-dev-server
webpack-hot-middleware
webpack-dev-middleware
stats.toJson加速
devtool
eval性能最好 但无法转译
cheap-source-map 稍差的map 但性能不错
eval-source-map 增量编译
多数情况为 eval-cheap-module-source-map
避免使用生产环境的工具
比如
TerserPlugin 压缩和混淆
[fullhash]/[chunkhasn]/[contenthash]
AggressiveSplittingPlugin
AggressiveMergingPlugin
ModuleConcatenationPlugin
最小化 entry chunk
optimization: { runtimeChunk: true }
避免额外优化步骤
代码语言:javascript复制optimization: {
removeAvailableModules: false,
removeEmptyChunks: false,
splitChunks: false
}
输出结果不要带路径信息
代码语言:javascript复制output: {
pathinfo: false
}
nodejs版本
v8.9.10-v9.11.1存在性能回退
ts-loader
加
代码语言:javascript复制use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
]
生产环境提升构建性能
不启用 SourceMap