解决代码拆分问题nodecommonjs模块化
解决浏览器支持问题requirejs
想要主js调用别的js要在主js前引入
hello.jsexporthello()
main.jshello()
importhello.jsimportmain.js
先安装node
然后安装webpackwebpack-cli全局安装(不推荐,会锁定版本)
npminstallwebpackwebpack-cli--global
本地安装
npminitnpminstallwebpackwebpack-cli--save-devcmdcls清屏
webpack打包
webpackwebpack--statsdetailed查看详细打包信息
npx牛逼
webpack--entryxxx
加--modeproduction生产环境
output
webpack.config.js文件
绝对路径使用require(‘path’)
path.resolve(__dirname,'xxx')module.exports={ entry:'', output:{ filename:'', path:'结对路径'' } }自动引入资源插件-html-webpack-pluginnpminstallhtml-webpack-plugin引入
constHtmlWebpackPlugin=require('html-webpack-plugin')在根{}下
plugins:[ newHtmlWebpackPlugin()]配置HtmlWebpackPluginnewHtmlWebpackPlugin({ template:'./index.html',模板文件 filename:'app.html',生成文件名 inject:'body'在哪个标签引入})清理dist(清理旧的打包)在output选项里面
output:{ filename:'', path:'结对路径'', clean:true }搭建开发环境mode选项定位错误更好显示代码定位错误
devtool:'inline-source-map',监听代码变化webpack--watch使用webpack-dev-servernpminstallwebpack-dev-server加-D在本地开发环境运行
在配置文件中
devServer:{ devServer:{ static:'./dist'//注意这里的./dist是路径 }}在控制台webpack-dev-server
module:{ rules:[ { test:/\.png$/, type:'asset/resource' } ] }在js文件中引入
importimgsrcfrom'./assets/img-1.png'constimg=document.createElement('img')创建一个照片元素img.src=imgsrc添加路径document.body.appendChild(img)将照片添加进页面webpack-dev-server--open加–open默认打开
在output中定义导出路径以及名字
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来生成文件名以及扩展名
若在modulerulesgenerator配置则generator高于output
使图片变成base64资源
test:/\.svg$/,type:'asset/inline'配置sourcetest:/\.txt$/,type:'asset/source配置assettest:/\.jpg$/,type:'asset'自动选择url还是文件base64一般小于8k会生成base64
可通过追加parser来控制
test:/\.jpg$/,type:'asset',parser:{dataUrlCondition:{maxSize:4*1024//默认大小4*1024}}loader使用安装css-loader以及style-loader执行
npminstallcss-loader-Dnpminstallstyle-loader-D配置
{test:/\.css$/,use:['style-loader','css-loader']}在index.js引入import‘./style.css’
先执行css-loader再执行style-loader
npminstallless-loaderless-D配置
{test:/\.(css|less)$/,use:['style-loader','css-loader','less-loader']}在index.js引入import‘./style.less’
安装插件
npminstallmini-css-extract-plugin-D在webpack.js引入
constMiniCssExtract=require(‘mini-css-extract-plugin’)
在plugins中添加
newMiniCssExtract()
配置
{test:/\.(css|less)$/,use:[MiniCssExtract.loader','css-loader','less-loader']}更换style-loader为MiniCssExtract.loader
style-loader作用是将css连接到页面而为了抽离改为MiniCssExtract.loader
自定义生成的文件名
newMiniCssExtract({filename:‘styles/[contenthash].css’})
npminstallcss-minimizer-webpack-plugin-D引入
constCssMinimizerPlugin=require(‘css-minimizer-webpack-plugin’)
在优化配置中配置
webpack配置根级
optimization:{ minimizer:[ newCssMinimizerPlugin() ]}注意配置此项之后代码压缩会失效需要单独配置terser
且mode更换为生产环境
mode:‘production’,
.block-bg{background-image:url(./assets/webpack-logo.svg)!important;}
!important使优先级最高
配置webpack
{test:/\.(woff|woff2|eot|ttf|otf)$/,type:'asset/resource'}在css文件引入字体文件
@font-face{font-family:'iconfont';src:url('./assets/iconfont.ttf');}.icon{font-family:'iconfont';font-size:30px;}在index.js引入字体
constspan=document.createElement('span')span.classList.add('icon')span.innerHTML=''document.body.appendChild(span)加载数据csv-loaderxml-loader安装
npminstallcsv-loaderxml-loader-D配置
{test:/\.(csv|tsv)$/,usr:'csv-loader'},{test:/\.xml$/,usr:'xml-loader'}引入数据在index.js
importDatafrom'./assets/data.xml'importNotesfrom'./assets/data.csv'xml转成js对象
csv转换为数组
安装
npminstalltomlyamljson5-D配置webpack
consttoml=require('toml')constyaml=require('yaml')constjson5=require('json5'){ test:/\.toml$/, type:'json', parser:{ parse:toml.parse }},{ test:/\.yaml$/, type:'json', parser:{ parse:yaml.parse }},{ test:/\.json5$/, type:'json', parser:{ parse:json5.parse }}使用文件
将es6转化为es5
babel-loader:在webpack解析es6@babel/core:babel核心模块@babel/preset-env:babel预定,一组babel插件的集合
npminstall-Dbabel-loader@babel/core@babel/preset-env配置{test:/.js$/,exclude:/node_modules/,use:{loader:‘babel-loader’,options:{presets:[’@babel/preset-env’]}}}
原因babel生产用于兼容async/await
安装插件@babel/runtime
npminstall@babel/runtime-D安装插件@babel/plugin-transform-runtime
npminstall@babel/plugin-transform-runtime-D配置
{ test:/\.js$/, exclude:/node_modules/, use:{ loader:'babel-loader', options:{ presets:['@babel/preset-env'], plugins:[ ['@babel/plugin-transform-runtime'] ] } }}分离代码如果有多个入口文件
entry:{ index:'./src/index.js', another:'./src/another-module.js'},出口的filename:'[name].bundle.js',但是这样会导致重复打包
entry:{ index:{ import:'./src/index.js', dependOn:'shared' }, another:{ import:'./src/another-module.js', dependOn:'shared' }, shared:'lodash'},方案二配置splitChunksoptimization:{splitChunks:{chunks:‘all’}}
如下
functiongetComponent(){returnimport('lodash').then(({default:_})=>{constelement=document.createElement('div')element.innerHTML=_.join(['hello','webpack'],'')returnelement})}getComponent().then((element)=>{document.body.appendChild(element)})constbutton=document.createElement('button')懒加载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’,
optimization:{ minimizer:[ newCssMinimizerPlugin() ], splitChunks:{ cacheGroups:{ vendor:{ test:/[\\/]node_modules[\\/]/, name:'vendors', chunks:'all' } } }}js放到一个文件夹output:{filename:‘scripts/[name].[contenthash].js’,…
module.exports=(env)=>{console.log(env)return{webpack配置项可通过env参数配置}}
比如
mode:env.production‘production’:‘development’
webpack--envproduction
可以传参a=1
npminstallterser-webpack-plugin-D使用
optimization:{ minimizer:[ newCssMinimizerPlugin(), newTerserPlugin() ],...拆分配置文件开发环境和生产环境
项目根目录新建webpack.config.dev.js开发环境
修改mode为开发环境
去掉压缩代码以及公共路径或包括缓存
启动
webpack-c./config/webpack.config.dev.js
-c可用-config替换
注意生成的文件的路径
在config目录下新建webpack.config.prod.js文件
修改mode为生产环境
删除调试devtooldev-server
webpack-c./config/webpack.config.prod.js
可通过webpackserve-c./config/webpack.config.dev.js
在项目根目录下package.json
{"scripts":{"start":"npxwebpackserver-c./config/webpack.config.dev.js","build":"npxwebpack-c./config/webpack.config.prod.js"}}忽略性能优化提示在webpack配置根{}下
performance:{hints:false}
项目根目录创建webpack.config.common.js文件
去除掉devprod中相同配置
npminstallwebpack-merge-Dconfig目录下创建wenpacj.config.js
const{merge}=require('webpack-merge')constcommonConfig=require('./webpack.config.common')constproductionConfig=require('./webpack.config.prod')constdevelopmentConfig=require('./webpack.config.dev')module.exports=(env)=>{switch(true){//可定义key-value判断caseenv.development:returnmerge(commonConfig,developmentConfig)caseenv.production:returnmerge(commonConfig,productionConfig)default:returnnewError('Nomatchingconfigurationwasfound')}}source-map新建目录npminit初始化
安装npminstallwebpackwebpack-cliwebpack-dev-serverhtml-webpack-plugin-D
默认devtool为eval
会生产main.js.map且生产的main.js注释里会显示sourceUrlmain.js.map(显示行列)且关联能找到代码问题
会生产main.js.map且生产的main.js注释里不会显示sourceUrlmain.js.map且不关联不能直接找到代码问题
不会生产main.js.map但生产的main.js注释里会显示sourceUrlmain.js.map且关联能找到代码问题
不会生成sourcemap文件而是放到了eval后面能找到代码问题
生成map文件mappings带有行数不带列能找到代码问题
生成map文件mappings带有行数不带列带有module的能找到代码问题
devServer:{hot:true}修改js热更新
在app.js
if(module.hot){module.hot.accept('./input.js',()=>{})}热加载devServer:{liveReload:true}代码规范eslint安装npmieslint-Deslint./src项目使用constHtmlWebpackPlugin=require('html-webpack-plugin')module.exports={mode:'development',entry:'./src/app.js',module:{rules:[{test:/\.js$/,usr:['babel-loader','eslint-loader']//先eslint-loader'},],},plugins:[newHtmlWebpackPlugin()]};开启后可关闭报错
devServer:{client:{overlay:false//报错覆盖层}}Githooks–Husky目的提交之前检测代码
.git/hooks/pre-commit文件
文件内容
eslint./src或者npxeslint./src自定义新建目录.mygithooks
文件.mygithooks/pre-commit内容一样
git配置
gitconfigcore.hooksPath.mygithoosk
npmhuskyinstall-Dhuxkyinstallpackage.json"main":"index.js","scripts":{"prepare":"huskyinstall"},在./husky目录下新增pre-commit文件
记得给予pre-commit文件权限(+x)
写入npxeslint.src
执行
gitadd.
gitcommit-m‘xxx’
如果代码出错会提示
解析绝对目录
用@指向src
webpack.js
resolve:{alias:{'@':path.resolve(__dirname,'./src')}}优先级配置默认js>json配置
resolve:{alias:{'@':path.resolve(__dirname,'./src')},extensions:['.json','.js','vue']}配置外部资源引入(链接引入)方式一wepack配置文件
externals:{jquery:'jQuery'}在html模板文件里面加入
npmiwebpack-bundle-analyzer-D引入
const{BundleAnalyzerPlugin}=require('webpack-bundle-analyzer')plugins:[newBundleAnalyzerPlugin()]启动webpackserve就会弹出
npmipostcss-loader-D
npmiautoprefixer-D
module:{rules:[{test:/\.css$/,use:['style-loader','css-loader','postcss-loader']}]}配置postcss.config.js在根目录下创建文件
module.exports={plugins:[require('autoprefixer')]}使用在package.json目录下根{}
"browserslist":[">1%",//全球浏览器使用率要大于1%"last2versions"//每个浏览器的最近两个版本]插件postcss-nested支持比如body下包括div的这种
npmipostcss-nested-D
配置postcss.config.js
module.exports={plugins:[require('autoprefixer'),require('postcss-nested')]}开启css模块化
use:['style-loader',{loader:'css-loader',options:{modules:true//开启css模块化}},'postcss-loader'],exclude:[path.resolve(__dirname,'..','node_modules')]//排除外部modules可设置两个配置一个全局一个局部
如下在webpack配置
全局配置
{test:newRegExp(`^(!.*\\.global).*\\css`),use:['style-loader',{loader:'css-loader',options:{modules:true//开启css模块化}},'postcss-loader'],exclude:[path.resolve(__dirname,'..','node_modules')]//排除外部modules}局部配置
{test:newRegExp(`^(.*\\.global).*\\css`),use:[{loader:'style-loader'},{loader:'css-loader'},{loader:'postcss-loader'}],exclude:[path.resolve(__dirname,'..','node_modules')]//排除外部modules}WebWorks创建一个workerconstworker=newWorker(newURL(’./work.js’,import.meta.url))
接收主线程信息self.onmessage=()=>{
}
主线程接收信息worker.onmessage=(message)=>{console.log(message)}
向主线程发送信息self.postMessage({answer:1111})
主线程发送信息worker.postMessage({question:‘hi,那边的worker线程,请告诉我今天的幸运数字是多少?’})
npmitypescriptts-loader-D配置webpack
constHtmlWebpackPlugin=require('html-webpack-plugin')constpath=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:[newHtmlWebpackPlugin()]}初始化ts配置文件
tsc--init修改ts配置
rootDir:“./src”
outDir:“./dist”
ts使用模块
查询需求模块安装
entry:['./src/app.js','./src/app2.js']配置二//entry:[//'./src/app.js',//'./src/app2.js',//'lodash'//],entry:{main:['./src/app2.js','./src/app.js'],lodash:'lodash'},配置三entry:{main:{import:['./src/app2.js','./src/app.js'],dependOn:'lodash'//依赖},lodash:'lodash'},index.html模板配置配置一基础配置webpack
es2015特性
但是无法额外模块
constHtmlWebpackPlugin=require('html-webpack-plugin')module.exports={mode:'production',entry:'./src/app.js',plugins:[newHtmlWebpackPlugin()],optimization:{usedExports:true//此处开启}}配置二sideEffects在packages.json配置
{"sideEffects":true,//true都加载false都不加载"sideEffects":["*.css"],//对于所有的css文件都加载,其它不加载"sideEffects":["*.css","*.global.js"],//对于所有的css文件以及.global.js文件都加载,其它不加载}离线环境下运行非离线环境下运行打包完成
devServer:{devMiddleware:{writeToDisk:true}}添加workbox实现pwa安装
npmiworkbox-webpack-plugin-D配置
constHtmlWebpackPlugin=require('html-webpack-plugin')constWorkboxPlugin=require('workbox-webpack-plugin')module.exports={mode:'production',entry:'./src/app.js',plugins:[newHtmlWebpackPlugin(),newWorkboxPlugin.GenerateSW({clientsClaim:true,skipWaiting:true})],浏览器注册入口文件app.js
if('serviceWorker'innavigator){//浏览器是否支持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配置
constHtmlWebpackPlugin=require('html-webpack-plugin')constwebpack=require('webpack')module.exports={mode:'development',entry:'./src/index.js',plugins:[newHtmlWebpackPlugin(),newwebpack.ProvidePlugin({_:'lodash'})]}使用index.js
//import_from'lodash'//无需引入console.log(_.join(['hello','webpack'],''))细颗粒度shimmingthis问题imports-loader安装
npmiimports-loader-D配置webpack
constHtmlWebpackPlugin=require('html-webpack-plugin')constwebpack=require('webpack')module.exports={mode:'development',entry:'./src/index.js',plugins:[newHtmlWebpackPlugin(),newwebpack.ProvidePlugin({_:'lodash'})],module:{rules:[{test:require.resolve('./src/index.js'),use:'imports-loaderwrapper=window'//让包里的this指向window}]}}全局exports插件exports-loader
npmiexports-loader-D使用webpack配置
module:{rules:[{test:require.resolve('./src/index.js'),use:'imports-loaderwrapper=window'},{test:require.resolve('./src/global.js'),use:'exports-loadertype=commonjs&exports=file,multiple|helpers.parse|parse'//相当于暴露parse:helper.parse}]}polyfills垫片简单原理不能这样引入
安装@babel/polyfill
npmi@babel/polyfill-Dimport'@babel/polyfill'//垫片这样导入Xconsole.log(Array.from([1,2,3],x=>x+x))进一步优化安装babel环境
npmibabel-loader@babel/core@babel/preset-env-D配置webpack
constHtmlWebpackPlugin=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:['last1version',//浏览器最新的一个版本'>1%'//代码使用超过1%],useBuiltIns:'usage',corejs:3}]]}}}]}}额外安装
npminstall--savecore-js@3library打包配置为不同模块constpath=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}}}打包为通用模块constpath=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}}构建小轮子配置
constpath=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执行
npmconfiggetregistry
确保为
npmadduser添加用户
npmpublish发布
使用webpack的ModuleFederationPlugin
先准备好两个模块
组件jsHeader.js
constHeader=()=>{constheader=document.createElement('h1')header.textContent='公共头部内容'returnheader}exportdefaultHeaderwebpack配置项
constHtmlWebpackPlugin=require('html-webpack-plugin')const{ModuleFederationPlugin}=require('webpack').containermodule.exports={mode:'production',entry:'./src/index.js',plugins:[newHtmlWebpackPlugin(),newModuleFederationPlugin({name:'nav',//模块名filename:'remoteEntry.js',//模块文件名remotes:{},//引入的模块exposes:{//导出的模块'./Header':'./src/Header.js'//模块路径},shared:{}//共享包})]}模块home引入navwebpack配置项
异步加载
importHomeListfrom"./HomeList";import('nav/Header').then((Header)=>{constbody=document.createElement('div')body.appendChild(Header.default())document.body.appendChild(body)document.body.innerHTML+=HomeList(5)})模块search引入两个资源暴露home的homeList组件
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最新版本
内置优化
解析必要的提高打包速度
{test:/\.js$/,include:'xxxxxx',loader:'xxx'}能不用loader和plugin就不用引导解析减少resolve,modules,resolve.extensions,resolve.mainFiles,resolve.descriptionFiles中的条目数量来减少系统文件调用次数
如果不使用symlinks设置resolve.symlinks:false
如果自定义resolveplugin规则并且没有指定context,可以设置resolve.cacheWithContext:false
使用更少或者更小的library
在多页面应用使用splitChunksPlugin并且开启async
移除未引用代码
只编译当前正在开发的代码
在webpack配置中使用cache选项使用package.json中的“postinstall”清除缓存目录
将cache类型设置为内存或者文件系统memory选项很简单它告诉webpack在内存中存储缓存
cache:{type:‘memory’}
对它们概要分析以免在此处引入性能问题
constpath=require('path')constwebpack=require('webpack')module.exports={mode:'production',entry:{jquery:['jquery']},output:{filename:'[name].js',path:path.resolve(__dirname,'dll'),library:'[name]_[hash]'},plugins:[newwebpack.DllPlugin({name:'[name]_[hash]',path:path.resolve(__dirname,'dll/manifest.json')})]}引入constHtmlWebpackPlugin=require('html-webpack-plugin')constwebpack=require('webpack')constpath=require('path')module.exports={mode:'production',entry:'./src/index.js',plugins:[newHtmlWebpackPlugin(),newwebpack.DllReferencePlugin({manifest:path.resolve(__dirname,'./dll/manifest.json')})]}此时并不能使用
constHtmlWebpackPlugin=require('html-webpack-plugin')constwebpack=require('webpack')constpath=require('path')constAddAssetHtmlPlugin=require('add-asset-html-webpack-plugin')module.exports={mode:'production',entry:'./src/index.js',plugins:[newHtmlWebpackPlugin(),newwebpack.DllReferencePlugin({manifest:path.resolve(__dirname,'./dll/manifest.json')}),newAddAssetHtmlPlugin({filePath:path.resolve(__dirname,'./dll/jquery.js'),publicPath:'./'})]}workerpool注意多个loader从下到上运行
使用thread-loader
用于非常耗时的loader
因为worker也会消耗资源
//constHtmlWebpackPlugin=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的watchmode监听过多导致的cpu负载
webpack-dev-server
webpack-hot-middleware
webpack-dev-middleware
eval性能最好但无法转译
cheap-source-map稍差的map但性能不错
eval-source-map增量编译
多数情况为eval-cheap-module-source-map
TerserPlugin压缩和混淆
[fullhash]/[chunkhasn]/[contenthash]
AggressiveSplittingPlugin
AggressiveMergingPlugin
ModuleConcatenationPlugin
optimization:{runtimeChunk:true}
optimization:{removeAvailableModules:false,removeEmptyChunks:false,splitChunks:false}