webpack核心概念
entry(入口)
string
entry:'./src/index.js'
array
在HMR的热更新中让html生效用的最广。
entry:['./src/index.js','./src/test.js']
object
entry:{
index:'./src/index.js'
test:'./src/test.js'
}
对象的特殊用法
entry:{
index:['./src/index.js','./src/add.js']
test:'./src/test.js'
}
outPut(输出)
const {reslove} = require('path')
entry:'./src/index.js'
output:{
filename:'js/[name].js',
path:reslove(__dirname,'build'),
publicPath:'/',
chunkFilename:'js/[name]_chunk.js',
library:'[name]'
libraryTarget:'window'
}
modules(模块)
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
},{
test:/\.js$/,
exclude:'node_modules',
include:resolve(__dirname,'src'),
enforce:'pre',
loader:'eslint-loader',
options:{}
},{
oneOf:[]
}
]
}
resolve
resolve:{
alias:{
css:resolve(__dirname,'src/css').
},
extensions:['js','json','css'],
modules:['node_modules']
}
devServer
devServer:{
contentBase:reslove(__dirname,'build'),
watchcontentBase:true,
watchOptions:{
ignored:/node_modules/
},
compress:true,
port:'8080',
host:'localhost',
open:true,
hot:true,
clientLogLevel:'none',
quiet:true,
overlay:false,
proxy:{
'/api':{
target:'http://loaclhost:8000',
pathRewrite:{
'^/api':''
}
}
}
}
optimization
optimizition:{
splitChunks:{
chunk:'all',
miniSize:30 * 1024
maxSize:0
minChunks:1
maxAsyncRequests:5
maxInitialRequests:3
automaticNameDelimiter:'~'
name:true
cacheGroups:{
}
},
runtimeChunk:{
name:entrypoint => runtime-${entrypoint.name}
},
minimizer:{
new TerserWebpackPlugin({
cache:true,
parallel:true,
sourceMap:true
})
}
}
webpack运行
首先要在终端里面初始化nodejs相关文件,即 npm i
然后下载webpack npm i webpack webpack-cli D D就是开发时依赖
-
引入css,less等样式文件。需要安装对应loader、 -
引入html文件,需要下载 html-webpack-plugin 插件,然后在plugins里面new HtmlWebpackPlugin() -
引入图片资源 需要下载url-loader和file-loader
js相关处理
js兼容性处理
因为平常写代码难免会写到es6中代码,而低版本浏览器又不认识es6代码,所以我们要进行js兼容性处理
都是在webpack.config.js中module块中rules里面配置的
{
test:/\.js$/,
exclude:/node_modules/,
loader:'babel-loader',
options:{
presets:{
[
'@babel/preset-env',
{
useBuiltIns:'usage',
corejs:{
version:3
},
targets:{
chrome:'60',
firefox:'60',
ie:'9'
}
}
]
}
}
}
最后我们是用第一种方法和第三种方法合并这处理js兼容问题
js压缩
js压缩我们只需要将开发模式转化为生产模式,会自动压缩
mode:'production'
js语法检测
{
test:/\.js$/,
exclude:/node_modules/,
loader:'eslint-loader',
options:{
fix:true
}
}
他本身是没有规则的,所以我们要继承airbnb第三方库的规则。在package.json中配置如下
"eslintConfig":{
"extends":"airbnb-base"
}
当js文件同时被处理
当js文件同时被多个loader处理,一定要规定先后顺序
比如上面的被eslint-loader处理同时被babel-loader处理
先处理eslint-loader,再处理babel-loader
test:/\.js$/,
exclude:/node_modules/,
enforce:'pre',
loader:'eslint-loader',
只需要加入 enforce:‘pre’ 即可
css相关处理
1.css样式单独提取
new MiniCssExtractPlugin = require('mini-css-extract-plugin')
module:{
rules:[
{
test:/\.css$/,
use:[
MiniCssExtractPlugin.loader,
'css-loader'
]
},{
test:/\.less$/,
use:[
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'css/buit.css'
})
]
2.兼容性处理
兼容性处理要用postcss-loader
new MiniCssExtractPlugin = require('mini-css-extract-plugin')
process.env.NODE_ENV = 'production'
const CssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader:'postcss-loader',
options:{
ident:'postcss',
plugins:()=>[
require('postcss-preset-env')()
]
}
}
]
module:{
rules:[
{
test:/\.css$/,
use:[...CssLoader]
},{
test:/\.less$/,
use:[..CssLoader,'less-loader']
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'css/buit.css'
})
]
再package.json中配置browserslist
"browserslist":{
"development":[
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production":[
">0.2%",
"not dead",
"not op_mini all"
]
}
css压缩
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
plugins:[
new OptimizeCssAssetsWebpackPlugin()
]
其他相关处理
图片压缩处理
{
test:/\.(jpg|png|svg|gif)$/,
loader:'url-loader',
options:{
limit: 8*1024,
name:'[hash:10].[ext]',
outputPath:'imgs',
esModule:false
}
}
HTML压缩处理
new HtmlWebpackPlugin = require('html-webpack-plugin')
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html',
minify:{
collapseWhitespace:true,
removeComments:true
}
})
]
处理html压缩之后,我们会发现html中的图片并不能压缩处理
HTML中图片资源处理
{
test:/\.html$/,
loader:'html-loader'
}
**这里设置好之后,用的是commonjs,与图片压缩所使es6冲突,所以要在图片压缩加入 esModule:false **
其他资源处理
{
exclude:/\.(js|css|html|less|png|)/,
loader:'file-loader',
options:{
outputPath:'media'
}
}
环境优化
为什么要优化?
如果我们的源文件中有大量的css,js代码。我们修改其中的一个,则会重新进行打包,会将所有的源文件重新打包。我们是不希望这样的。
1.HMR基于开发环境
HMR: hot module replacement 热模块替换/模块热替换 是基于开发环境的
作用:一个模块发生变化,只会宠幸打包这一个文件,而不是打包所有的源文件
样式文件:可以使用HMR,因为在style-loader内部实现了,所以在开发环境中,都用style-loader
js文件:默认不能使用HMR.要使用,在对应js文件中添加如下代码。。。不能处理入口文件!!!!
if(module.hot){
moule.hot.accept('./build.js',function(){
})
}
HTML文件:默认不能使用。 解决:修改entry入口,将html资源引入即可
devServer:{
contentBase:reslove(__dirname,'bundle'),
inline:true,
hot:true
}
2.source-map
source-map 是提供源代码到构建后代码映射技术
如果构建后代码出错了,可以通过映射的方法找到对应源代码。
只要在webpack.config.js中加入
devtool:'source-map'
- source-map 外部
- inline-source-map 在js内部生成source-map 内联
- hidden-source-map 外部
- eval-source-map 每一个文件都生成对应的source-map,在eval函数里面。都在js中 内联
- nosources-source-map 外部
- cheap-source-map 外部会成成.map文件
- cheap-module-source-map 外部 6和7的区别 module:会将loader的source-map加入
外部与内联的区别:
- 外部生成了.map文件,内联没有
- 内联构建速度更快
- 内联会使代码体积变大
开发环境与生产环境
1.开发环境:速度快,调试方便
-
速度快(eval>inline>cheap)
- eval-cheap-source-map
- eval-source-map
-
调试更友好
- source-map
- cheap-moudle-source-map
- cheap-source-map
综上,—》 eval-source-map
2.生产环境:源代码要不要隐藏,调试要不要方便
内联会使代码体积变大,所以我们在选择的时候首先排除内联
如果需要隐藏 —》 nosources-source-map 全部隐藏 / hidden-source-map 之隐藏源代码,会提示构建后代码错误
不考虑隐藏 —》 source-map / cheap-module-source-map
oneof
oneof是提供优化生产环境打包配置的
比如:同时同时处理css文件和less文件,都需要css-loader,会让css-loader重复的执行,而oneof则会优化
module:{
rules:[
{
oneof:[]
}
]
}
注意:两个loader处理一个时,则需要放在外面
比如:js文件需要eslint-loader处理和babel-loader处理。这个时候我们就需要单独提取出。
module:{
rules:[
{
},
{
oneof:[]
}
]
}
缓存基于生产环境
当我们的js代码有很多时,我们修改其中的一个,并不希望所有的js代码都重新被打包。此时我们就要用到生产环境的缓存处理
babel缓存
让第二次打包构建速度更快
{
test:/\.js$/,
exclude:/node_modules/,
loader:'babel-loader',
options:{
presets:{
[
'@babel/preset-env',
{
useBuiltIns:'usage',
corejs:{
version:3
},
targets:{
chrome:'60',
firefox:'60',
ie:'9'
}
}
],
cacheDirectory:true
}
}
}
此时,用户第一次打开就会生成缓存,后面打开的话就会很快。
但是,如果你的js css代码修改的话,重新打包,页面将不会有任何反应,因为他们用的都是第一次留下的缓存
那我们怎么让他正常的处理呢? 我们对文件名加入hash值即可
文件资源缓存
让代码上线运行缓存更好使用
filename:'index[hash:10].js'
造成的问题:因为css和js同时使用一个hash值。
如果重新打包,会导致所有的缓存失效。(我们只想改变其中的一个文件)
chunkhash也不行,因为所引入的js。css等文件都是源自一个chunk,所以他们生成的哈希值也一样
contenthash不同文件会生成不同的哈希值,可以
filename:'index[contenthash:10].js'
tree shaking
作用:去除无用代码,让代码体积变小
前提:1.必须使用模块化 2.开启production环境
mode:'production'
在package.json中配置
"sideEffects":false
问题:可能会把css / @babel/polyfill (副作用)等文件干掉 ,此时我们要再加
"sideEffects":["*.css"]
code split
code split就是解决防止打包后一个文件过大,而请求缓慢.
code split就是生成多个chunk,即把代码分成很多块
作用:1.可以将node_modules中代码单独打包一个chunk
? 2.自动分析多入口chunk中,有没有公共的文件,如果有则会打包成一个chunk
entry:'./src/index.js'
entry:{
index:'./src/index.js',
test:'./src/test.js'
}
在后面加入下述代码即可
optimization:{
splitChunks:{
chunks:'all'
}
}
如果是单入口,则会将node_modules中代码单独打包一个chunk
如果是多入口,则自动分析多入口chunk中,有没有公共的文件,如果有则会打包成一个chunk
其次,我们还可以通过写js代码方式进行单独打包,首先要配置optimization和单入口
import('./test')
.then(()={
}).catch(()=>{
})
总结三种方法
- 使用多入口文件进行单独打包
- 引入optimization相关配置,会根据单入口,多入口进行打包
- 引入optimization相关配置,在js中写入对应js代码,进行单独打包
lazy loading
不是图片的懒加载,这里指的是js代码的懒加载
懒加载:当文件使用的时候加载
预加载 prefetch :等其他资源加载完,再加载…。 兼容性较差.一般都是用懒加载就够了
document.getElementById('btn').onclick = function(){
import('./test.js').then(res=>{
console.log(res)
})
}
PWA
pwa即离线可访问技术。
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
plugins:[
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim:true,
skipWaiting:true
})
]
然后还要去index.js中输入相应js代码
if('serviceWorker' in navigator){
window.addEventListener('load',()={
navigator.serviceWorker
.register('/service-worker.js')
.then(()=>{
console.log('注册成功')
.catch(()=>{
console.log('注册失败')
})
})
})
}
到这里,再打包eslint则会报错,不认识navigator等关键字,故我们要修改eslint中的配置
"env":{
"browser":true
}
serviceWorker必须运行在服务器上
多进程打包
多进程打包主要用来优化打包速度。用的是thread-loader
在哪里用,在那里加就可以。基本是给js文件处理.
例如:
use:[
{
loader:'thread-loader',
options:{
workers:2
}
}
{
loader:'babel-loader',
options:{
}
}
]
开启多线程打包。只有工作消耗时间比较长,我们才开启多线程打包
否则会适得其反,多线程启动大概600ms
externals
可以禁止打包一些从cdn中可以获取到库,从而达到代码量少,在webpack.config.js中配置
externals:{
vue:'Vue'
}
然后在html中通过script标签引入cdn链接。
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.0-beta.7/vue.cjs.js"></script>
dll
dll和上面的externals相似。dll是需要打包一次。而externals是不打包
我们要新建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]'
},
plugins:[
new webpack.DllPlugin({
name:'[name]_[hash]'
path:resolve(__dirname,'dll/mainfest.json')
})
],
mode:'production'
}
然后在config.js配置如下即可
const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
module.exprots = {
entry:'./src/index.js',
output:{
filename:'built.js',
path:resolve(__dirname,'build')
},
plugins:[
new HtmlWebpackPlugin({
filename:'./src/index.html'
}),
new webpack.DllReferencePlugin({
mainfest:resolve(__dirname,'dll/manifest.json')
}),
new AddAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,'dll/jquery.js')
})
],
mode:'production'
}
|