webpack
webpack已是前端打包够贱的不二选择
每日必用,面试必考
成熟的工具,重点在于配置和使用,原理并不高优
面试题
-
前端代码为何要进行构建和打包
代码层面
体积更小(Tree-Shaking、压缩、合并)
编译高级语言或语法(TS、ES6+、模块化、scss)
兼容性和错误检查(Polyfill、postcss、eslint)
前端工程化、前端流程、团队效率层面
统一、高效的开发环境
统一的构建流程和产出标准
集成公司构建规范(提测、上线等) -
module chunk bundle分别什么意思,有何区别?
-
loader和plugin的区别
loader模块转换器,如less > css
plugin扩展插件,如HtmlWebpackPlugin -
常见loader和plugin有哪些
https://www.webpackjs.com/loaders/
https://www.webpackjs.com/plugins/
把此前示例中的loader和plugin答出来即可 -
webpack如何实现懒加载
import()
结合Vue React异步组件
结合Vue-router React-router异步加载路由 -
webpack常见性能优化
-
babel-runtime和babel-polyfill的区别
babel-polyfill会污染全局
babel-runtime不会污染全局
产出第三方lib要用babel-runtime -
babel和webpack的区别
babel - JS新语法编译工具,不关心模块化
webpack - 打包构建工具,是多个loader plugin的集合 -
如何产出一个lib
参考webpack.dll.js
output.library
-
为何Proxy不能被polyfill
如Class可以用function模拟
如Promise可以用callback来模拟
但Proxy的功能用Object.defineProperty无法模拟
基本配置
拆分配置和merge
const webpackCommonConf = require('./webpack.common.js')
const {
smart } = require('webpack-merge')
module.exports = smart(webpackCommonConf, {
})
启动本地服务
devServer: {
port: 8080,
progress: true, // 显示打包的进度条
contentBase: distPath, // 根目录
open: true, // 自动打开浏览器
compress: true, // 启动 gzip 压缩
// 设置代理
proxy: {
// 将本地 /api/xxx 代理到 localhost:3000/api/xxx
'/api': 'http://localhost:3000',
// 将本地 /api2/xxx 代理到 localhost:3000/xxx
'/api2': {
target: 'http://localhost:3000',
pathRewrite: {
'/api2': ''
}
}
}
}
处理ES6
{
test: /\.js$/,
loader: ['babel-loader'],
include: srcPath,
exclude: /node_modules/
},
//.babelrc
{
"presets": ["@babel/preset-env"],
"plugins": []
}
处理样式
// {
// test: /\.css$/,
// // loader 的执行顺序是:从后往前(知识点)
// loader: ['style-loader', 'css-loader']
// },
{
test: /\.css$/,
// loader 的执行顺序是:从后往前
loader: ['style-loader', 'css-loader', 'postcss-loader'] // 加了 postcss
},
{
test: /\.less$/,
// 增加 'less-loader' ,注意顺序
loader: ['style-loader', 'css-loader', 'less-loader']
}
// postcss-loader是为了处理兼容性,还要配置postcss.config.js才会生效
//postcss.config.js
module.exports = {
plugins: [require('autoprefixer')]
}
处理图片
// dev直接引入图片 url
{
test: /\.(png|jpg|jpeg|gif)$/,
use: 'file-loader'
}
//prod情况小于 5kb 的图片用 base64 格式产出,其他产出 url 格式放在img目录下
// 图片 - 考虑 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'
}
}
},
模块化
总结
//package.json
{
"name": "07-webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"devBuild": "webpack --config build-optimization/webpack.dev.js",
"dev": "webpack-dev-server --config build-optimization/webpack.dev.js",
"build": "webpack --config build-optimization/webpack.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.7.4",
"@babel/preset-env": "^7.7.4",
"autoprefixer": "^9.7.3",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.2.1",
"file-loader": "^5.0.2",
"happypack": "^5.0.1",
"html-webpack-plugin": "^3.2.0",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.8.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"style-loader": "^1.0.1",
"terser-webpack-plugin": "^2.2.2",
"url-loader": "^3.0.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0",
"webpack-merge": "^4.2.2",
"webpack-parallel-uglify-plugin": "^1.1.2"
},
"dependencies": {
"lodash": "^4.17.15",
"moment": "^2.24.0"
}
}
//paths.js
/**
* @description 常用文件夹路径
* @author 双越
*/
const path = require('path')
const srcPath = path.join(__dirname, '..', 'src')
const distPath = path.join(__dirname, '..', 'dist')
module.exports = {
srcPath,
distPath
}
//webpack.common.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {
srcPath, distPath } = require('./paths')
module.exports = {
entry: path.join(srcPath, 'index'),
module: {
rules: [
{
test: /\.js$/,
loader: ['babel-loader'],
include: srcPath,
exclude: /node_modules/
},
// {
// test: /\.vue$/,
// loader: ['vue-loader'],
// include: srcPath
// },
// {
// test: /\.css$/,
// // loader 的执行顺序是:从后往前(知识点)
// loader: ['style-loader', 'css-loader']
// },
{
test: /\.css$/,
// loader 的执行顺序是:从后往前
loader: ['style-loader', 'css-loader', 'postcss-loader'] // 加了 postcss
},
{
test: /\.less$/,
// 增加 'less-loader' ,注意顺序
loader: ['style-loader', 'css-loader', 'less-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(srcPath, 'index.html'),
filename: 'index.html'
})
]
}
//webpack.dev.js
const path = require('path')
const webpack = require('webpack')
const webpackCommonConf = require('./webpack.common.js')
const {
smart } = require('webpack-merge')
const {
srcPath, distPath } = require('./paths')
module.exports = smart(webpackCommonConf, {
mode: 'development',
module: {
rules: [
// 直接引入图片 url
{
test: /\.(png|jpg|jpeg|gif)$/,
use: 'file-loader'
}
]
},
plugins: [
new webpack.DefinePlugin