1. file-loader加载文件,url-loader也可以加载文件但是当文件小于阙值转为base64返回,url-loader封装了file-loader
css-loader处理css文件、style-loader将css代码以style标签注入到html文件中,less-loader转less文件为css文件
postCss-loader转换css文件,例如添加前缀,转换单位
babel-loader转es6为es5,转换react语法
vue-loader处理vue文件
eslint-loader检查代码规范
devServer 配置服务器webpack-dev-server开发环境静态服务器(属性host、port、proxy、contentbase根目录)
devtool配置sourcemap类型
entry需要多入口配置,{chunkname: filePath/file.js}
2 out需要动态配置[name].hash.js
3 htmlwebpackplugin需要生成多个html(属性template,fimename,chunks),配置html要引入的chunks
在本地的代码中可以用style-loader把CSS文件放到style中, 但是线上必须要把CSS进行抽离,压缩,不然代码体积很大。 不抽离的CSS文件其实是通过js文件写入html的style标签中的 ,这样要执行js才能把css解析出来放入html中,效率很低。 抽离 css 和 less : 注意这里不再使用style-loader,而是使用 MiniCssExtractPlugin.loader 单独拎出来
1. 抽离:使用miniCssExtratPlugin插件,rules中使用miniCssExtratPlugin.loader替换style-loader,plugin中配置MiniCssExtratPlugin
2. 压缩:在webpack optimization属性中配置minmizer,使用optimizeCssAssetsPlugin等工具压缩css文件去除空格和注释
webpack5现在一般要使用CssMinimizerPlugin + MiniCssExtractPlugin,之前的optimize-css-assets-webpack-plugin会报错
const path = require("path");
const {merge} = require("webpack-merge");
const common = require("./webpack.common");
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const {distPath, srcPath} = require("./path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = merge(common, {
mode: "production",
module: {
rules: [
{
test: /\.css$/,
include: srcPath,
exclude: /node_modules/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
},
{
test: /\.less$/,
include: srcPath,
exclude: /node_modules/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader']
}
]
},
output:{
path:distPath,
filename:'bundle.[contenthash:8].js'
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename:'main.[contenthash:8].css'
})
],
optimization:{
minimizer:[
new CssMinimizerPlugin()
]
}
})
对应 html 中引入哪些 js 可以在 HtmlWebpackPlugin 中的 chunks 中 配置
在生产的配置中进行公共代码和第三方代码的抽离: 在 optimization 中加 splitChunks
webpack 5好像 chunks 是按需导入了-慕课网
1 懒加载使用 import(文件路径) 函数来实现,返回一个 promise
import().then(res => res.default) 或者 SetTimeout
2使用 chunk: 入口中的 HtmlWebpackPlugin 插件
module、chunk、bundle的区别
module 一些源代码,没有经过编译的,webpack中一切皆模块
chunk 多模块合成的,如 entry import() splitChunk(下午中间分析部分)
bundle 最终输出的文件
module 是源码,能引用的都是模块,不管是什么类型,css、js、图片等都是模块,都是源码 chunk 是多模块合并成的,中不一定是一个文件,比如 index.js 中还有引入其他的文件 (chunk 是内存中的概念,还没有输出) bundle 就是最终输出的文件,一个 chunk 对应一个 bundle
Webpack构建速度优化_如何提高webpack的构建速度_gogo2027的博客-CSDN博客
一、构建速度
优化babel-loader
开启缓存(开启cacheDirectory) use:[babel-loader?cacheDirectory],
include或者exclude明确范围 eg.include:path.resolve(_dirname,'src')
IgnorePlugin
noParse
happyPack
ParallelUglifyPlugin
自动刷新
热更新
DllPlugin
1、babel-loader es6转到es5 2、IgnorePlugin 避免哪些 ? 3、noParse不去管哪些? 4、happyPack 多进程打包 5、parallelUglifyPlugin 开启多进程代码压缩 6、自动刷新 7、热更新-浏览器不用刷新代码生效 8、DllPlugin 第三方或者其他比较大的库事先打包好,作为引用,不用每次重新打包,
优化babel-loader开启缓存use:[babel-loader?cacheDirectory],es6代码没有改动直接使用缓存不再编译,指定打包范围缩小要处理的文件数量(include/exclude)
ignorePlugin避免引入无用模块(不引入,可以手动按需引入)
忽略moment下的/loacle目录, new webpackPlugin(/\.\/locale/,/moment/)
业务代码中动态引入需要的语言包,import 'moment/locale/zh-cn'
3 noParse避免重复打包(引入,不打包) 已经是压缩过的代码最小的代码
区别: IgnorePlugin 直接不引入,代码中没有(自己按需要来引入需要的部分) noParse 引入,但不打包
4 happyPack多进程打包
JS单线程,开启多进程打包
提高构建速度(特别是多核CPU)
5 ParallelUglifyPlugin 多进程压缩JS
webpack内置Uglify工具压缩js
JS单线程,开启多进程压缩更快
和happyPack同理
关于开启多进程
项目较大,打包较慢,开启多进程能提高速度
项目较小,打包很快,开启多进程会降低速度(进程开销)
按需使用
ParallelUglifyPlugin 的配置直接在 plugins 中 new 就可以, new 的时候要给 uglifyJS 传一些配置
6 配置热更新
自动刷新:
一般情况下,如果项目引入了devServer,那么就会默认把热更新这个功能开启
热更新:
热更新是有成本的,要在开发环境下自己注册哪些模块使用热更新 这里注册的范围是 math.js 文件中的内容使用热更新,回调函数部分是热更新之后执行的
在devServer里面配置 hot:true
7 Dllplugin 动态链接库插件
DllPlugin(仅为了开发频繁打包体验,用于 dev)
前端框架如vue react , 体积大,构建慢
较稳定,不常升级版本
同一个版本只构建一次即可,不用每次重新构建
一个库一个是索引
hard-source-webpack-plugin 为模块提供了中间缓存,重复构建时间大约可以减少 80%,但是在 webpack5 中已经内置了模块缓存,不需要再使用此插件
生成dll文件 - Dllplugin
创建一个webpack.dll.js 运行生成dll文件 和mainefest文件
使用dll文件 DllReferencePlugin
index.html中使用dll文件
DllReferencePlugin 指定mainefest文件地址
体积更小
合理分包,不重复加载
速度更快,内存使用更少
方案
小图片base64格式产出,避免网络请求
bundle+contenthash
懒加载,非核心代码异步加载
提取公共代码
IgnorePlugin减少代码
使用CDN加速,cdn前缀
使用production
Scope Hosting
开启 prodution 模式之后,就会自动开启 Tree-Shaking 没有用到的代码,在生产打包的时候删掉就是 tree-shaking 这里的 mult 函数就是没用到的代码,在生产打包时应该删掉
ES6 Module静态引入,编译时引入
CommonJs是动态引入,执行时引入(require可以放在if else里)
只有ES6 Module才能静态分析,实现tree-shaking
CommonJs动态引入:
ES6 Module静态引入:
Scope Hosting
把多个函数(每个模块可能一个函数)的内容,放到一个函数中
代码体积更小
创建函数作用域更少
代码可读性更好
babel 环境搭建和基本配置
Presets/env代表了很多常用的plugin配置,省去很多plugin的配置
babel-polyfill是core-js和regenerater的集合
core-js解决不了yield(generate), regenerater
babel7.4后babel-polyfill已经被弃用,推介使用core-js和regenerater
2 babel-polyfill 按需引入
.babelrc:
babel-runtime
babel-polyfull会污染全局环境
如何是打包第三方库,会影响用户的环境
babel-runtime : 防止babel-polyfill污染全局环境Promise等新特性取一个别名如)_promise。需要在.babelrc presets中配置
babel/runtime
babel/plugin-transform-runtime
前端为何要进行打包和构建?
体积更小(Tree-Shaking、压缩、合并),加载更快
编译高级语言或语法(TS、ES6+、模块化、scss)
兼容性和错误检查(Polyfill、postcss、eslint)
统一、高效的开发环境
统一的构建流程和产出标准
集成公司构建规范(提测、上线等)
module chunk bundle的区别
module-各个源码文件,webpack中一切皆模块
chunk-多模块合并成的,如entry import()splitChunk
bundle-最终的输出文件
loader和plugin的区别
loader模块转换器,如less->css
plugin扩展插件,如HtmlWebpackPlugin
常见的loader和plugin有哪些
babel和webpack的区别
babel-JS新语法编译工具,不关心模块化
webpack-打包构建工具,是多个loader plugin的集合
如何产出一个lib(第三方的类)
参考webpack.dll.js
output.library
babel-polyfill和babel-runtime的区别
babel-polyfill会污染全局
babel-runtime不会污染全局
产出第三方lib要用babel-runtime
webpack如何实现懒加载
import()
结合Vue React异步组件
结合Vue-router React-router 异步加载路由
为何Proxy不能被Profill?
如Class可以用function模拟
如Promise可以用callback来模拟
但Proxy的功能用Object.defineProperty无法模拟
没有任何能力能完全模拟出Proxy
Polyfill或者Polyfiller,是英国Web开发者 Remy Sharp 在咖啡店蹲坑的时候拍脑袋造出来的。当时他想用一个词来形容"用JavaScript(或者Flash之类的什么鬼)来实现一些浏览器不支持的原生API"。Shim这个已经有的词汇第一时间出现在他的脑海里。但是他回头想了一下Shim一般有自己的API,而不是单纯实现原生不支持的API。苦思冥想一直想不到合适的单词,于是他一怒之下造了一个单词Polyfill。除了他自己用这个词以外,他还给其他开发者用。随着他在各种Web会议演讲和他写的书《Introducing HTML5》中频繁提到这个词,大家用了都觉得很好,就一起来用。
Polyfill的准确意思为:用于实现浏览器并不支持的原生API的代码。
例如,querySelectorAll是很多现代浏览器都支持的原生Web API,但是有些古老的浏览器并不支持,那么假设有人写了库,只要用了这个库, 你就可以在古老的浏览器里面使用document.querySelectorAll,使用方法跟现代浏览器原生API无异。那么这个库就可以称为Polyfill或者Polyfiller。
好,那么问题就来了。jQuery是不是一个Polyfill?答案是No。因为它并不是实现一些标准的原生API,而是封装了自己API。一个Polyfill是抹平新老浏览器 标准原生API 之间的差距的一种封装,而不是实现自己的API。
已有的一些Polyfill,如 Polymer 是让旧的浏览器也能用上 HTML5 Web Component 的一个Polyfill。FlashCanvas是用Flash实现的可以让不支持Canvas API的浏览器也能用上Canvas的Polyfill。
分割线
---------------------------------------------------------------------------------------------------------------------------------
在配置 loader 的时候,我们需要更精确的去指定 loader 的作用目录或者需要排除的目录,通过使用 include 和 exclude 两个配置项,可以实现这个功能,常见的例如:
include:符合条件的模块进行解析
exclude:排除符合条件的模块,不解析,优先级更高
这样一来,一开始构建,我们就能去除一些选项,比如,在使用babel-loader的时候
{
test: /\.jsx?$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/react'],
plugins: [[require('@babel/plugin-proposal-decorators'), { legacy: true }]],
cacheDirectory: true, // 启用缓存
},
},
],
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
},
对于我们引入的一些第三方包,比如jQuery
,在这些包内部是肯定不会依赖别的包,所以根本不需要webpack去解析它内部的依赖关系,使用 noParse 进行忽略的模块文件中不会解析 import
、require
等语法
module:{
noParse:/jquery|lodash/
}
有很多的第三方包内部会做国际化处理,包含很多的语言包,而这些语言包对我们来说时没有多大用处的,只会增大包的体积,我们完全可以忽略掉这些语言包,从而提高构建效率,减小包的体积。
requestRegExp
表示要忽略的路径。contextRegExp
表示要忽略的文件夹目录。new webpack.IgnorePlugin({ resourceRegExp, contextRegExp });
//以moment为例,首先找到moment中语言包所在的文件夹,然后在webpack配置文件中添加插件
new webpack.IgnorePlugin(/./locale/, /moment/)
这时候moment使用默认语言英语,如果要使用别的语言,可以手动引入需要使用的语言包。
import moment from 'moment'
import 'moment/locale/zh-cn'
moment.locale('zh-CN')
alias 用的创建 import
或 require
的别名,用来简化模块引用,项目中基本都需要进行配置。
const path = require('path')
{
...
resolve:{
// 配置别名
alias: {
'~': resolve('src'),
'@': resolve('src'),
'components': resolve('src/components'),
}
}
}
配置完成之后,我们在项目中就可以
// 使用 src 别名 ~
import '~/fonts/iconfont.css'
// 使用 src 别名 @
import '@/fonts/iconfont.css'
配合上noParse,在使用的时候,就无须在构建一遍react