webpack
常见面试题
前端代码为何要进行构建和打包
- 体积更小(
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
- plugin 和 loader 的区别是,loader 是在 import 时根据不同的文件名,匹配不同的 loader 对这个文件做处理,
而 plugin, 关注的不是文件的格式,而是在编译的各个阶段,会触发不同的事件,让你可以干预每个编译阶段。
webpack
如何实现懒加载
import()
- 结合
Vue React
异步组件 - 结合
Vue-router React-router
异步加载路由
babel
和webpack
的区别
babel-js
新语法编译工具,不关心模块化webpack
-打包构建工具,是多个loader plugin
的集合
webpack
常见性能优化
babel-runtime
和babel-polyfill
的区别
babel-runtime
不会污染全局babel-polyfill
会污染全局- 产出第三方
lib
要用babel-runtime
为何
Proxy
不能被Polyfill
- 如
Class
可以用funcion
模拟 - 如
Promise
可以用callback
模拟 - 但是
Proxy
的功能用Object.defineProperty
无法模拟
webpack
性能优化-构建速度
-
优化
babel-loader
-
{ test: /\.js$/, loader: ['babel-loader?cacheDirectory'],//开启缓存 include: srcPath, // exclude: /node_modules/ },
-
IgnorePlugin
-
noParse
-
happyPack
JS
单线程,开启多进程打包- 提高构建速度(特别式多核
CPU
)
-
const HappyPack = require('happypack') { test: /\.js$/, // 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例 use: ['happypack/loader?id=babel'], include: srcPath, // exclude: /node_modules/ }, // happyPack 开启多进程打包 new HappyPack({ // 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件 id: 'babel', // 如何处理 .js 文件,用法和 Loader 配置中一样 loaders: ['babel-loader?cacheDirectory'] }),
-
ParallelUglifyPlugin
webpack
内置Uglify
工具压缩JS
现在webpack4
要换成terser-webpack-plugin
JS
单线程,开启多进程压缩更快
-
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin') // 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码 new ParallelUglifyPlugin({ // 传递给 UglifyJS 的参数 // (还是使用 UglifyJS 压缩,只不过帮助开启了多进程) uglifyJS: { output: { beautify: false, // 最紧凑的输出 comments: false, // 删除所有的注释 }, compress: { // 删除所有的 `console` 语句,可以兼容ie浏览器 drop_console: true, // 内嵌定义了但是只用到一次的变量 collapse_vars: true, // 提取出出现多次但是没有定义成变量去引用的静态值 reduce_vars: true, } } })
-
热更新
-
DLLPlugin
webpack
已经内置DLLPlugin
支持DLLPlugin
-打包出dll
文件DLLReferencePlugin
-使用dll
文件
webpack
性能优化-产出代码
- 体积更小
- 合理分包,不重复加载
- 速度更快哦,内存使用更少
小图片采用
base64
// 图片 - 考虑 base64 编码的情况
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
// 小于 5kb 的图片用 base64 格式产出
// 否则,依然延用 file-loader 的形式,产出 url 格式
limit: 5 * 1024,
// 打包到 img 目录下
outputPath: '/img1/',
// 设置图片的 cdn 地址(也可以统一在外面的 output 中设置,那将作用于所有静态资源)
// publicPath: 'http://cdn.abc.com'
}
}
},
bundle
加上hash
output: {
// filename: 'bundle.[contentHash:8].js', // 打包代码时,加上 hash 戳
filename: '[name].[contentHash:8].js', // name 即多入口时 entry 的 key
path: distPath,
// publicPath: 'http://cdn.abc.com' // 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到
},
懒加载
提取公共代码
optimization: {
// 压缩 css
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
// 分割代码块
splitChunks: {
chunks: 'all',
/**
* initial 入口chunk,对于异步导入的文件不处理
async 异步chunk,只对异步导入的文件处理
all 全部chunk
*/
// 缓存分组
cacheGroups: {
// 第三方模块
vendor: {
name: 'vendor', // chunk 名称
priority: 1, // 权限更高,优先抽离,重要!!!
test: /node_modules/,
minSize: 0, // 大小限制
minChunks: 1 // 最少复用过几次
},
// 公共的模块
common: {
name: 'common', // chunk 名称
priority: 0, // 优先级
minSize: 0, // 公共模块的大小限制
minChunks: 2 // 公共模块最少复用过几次
}
}
}
}
IngorePlugin
- 忽略
使用
CDN
加速
publicPath: 'http://cdn.abc.com' // 修改所有静态文件 url 的前缀(如 cdn 域名)
使用
production
- 自动开启代码压缩
Vue React
等会自动删掉调试代码(如开发环境得warning
)- 启动
Tree-Shaking
ES6 Module
才能让tree-shaking
生效commonjs
就不行
ES6 Module 和 Commonjs
区别
ES6 Module
静态引入,编译时引入Commonjs
动态引入,执行时引入- 只有
ES6 Module
才能静态分析,实现Tree-Shaking
Commonjs
let testXzt = require('../config/api.js')
if (isDev) {
//可以动态引入,执行时引入
testXzt = require('../config/api_dev.js')
}
ES6 Module
import testXzt from '../config/api.js'
if (isDev) {
//编译时报错,只能静态引入
import testXzt from '../config/api.js'
}
Scope Hosting
- 代码体积更小
- 创建函数作用域更少
- 代码可读性更好
babel
-
前端开发环境必备工具
-
同
webpack
,需要了解基本得配置和使用
babel-polyfill
Polyfill
是一块代码(通常是 Web 上的JavaScript
),用来为旧浏览器提供它没有原生支持的较新的功能- 推荐直接使用
core-js
和regenerator
babel-polyfill
即俩者得集合,现在已经被弃用