(十)webpack 和 babel
webpack 和 babel
- webpack
- 面试题
- 基本配置
- 拆分配置和merge
- 启动本地服务
- 处理ES6
- 处理样式
- 处理图片
- 模块化
- 总结
- 高级配置
- 多入口
- 抽离css文件
- 抽离公共代码
- 懒加载
- 处理JSX
- 处理vue
- module chunk bundle的区别
- webpack性能优化
- 构建速度
- 优化babel-loader
- IgnorePlugin避免引入无用的模块
- noParse避免重复打包
- IgnorePlugin vs noParse
- happyPack多进程打包
- ParallelUglifyPlugin多进程压缩JS
- 关于开启多进程
- 自动刷新
- 热更新
- DllPlugin动态链接库插件
- 总结
- webpack优化构建速度(可用于生产环境)
- webpack优化构建速度(不用于生产环境)
- 优化产出代码
- 小图片base64编码
- bundle加hash
- 懒加载
- 提取公共代码
- IgnorePlugin使打出体积更小
- 使用CDN加速
- 使用production
- ES6 Module和commonjs的区别
- Scope Hosting
- babel
- 环境搭建 & 基本配置
- babel-polyfill
- 什么是Polyfill
- core-js和regenerator
- babel-polyfill即两者的集合
- babel-polyfill如何按需引入
- babel-runtime
- babel-polyfill的问题
- babel-runtime处理这个问题
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-runtimebabel和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({// window.ENV = 'development'ENV: JSON.stringify('development')})],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': ''}}}}
})
//webpack.prod.js
const path = require('path')
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpackCommonConf = require('./webpack.common.js')
const { smart } = require('webpack-merge')
const { srcPath, distPath } = require('./paths')module.exports = smart(webpackCommonConf, {mode: 'production',output: {filename: 'bundle.[contentHash:8].js', // 打包代码时,加上 hash 戳path: distPath,// publicPath: 'http://cdn.abc.com' // 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到},module: {rules: [// 图片 - 考虑 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'}}},]},plugins: [new CleanWebpackPlugin(), // 会默认清空 output.path 文件夹new webpack.DefinePlugin({// window.ENV = 'production'ENV: JSON.stringify('production')})]
})
//.babelrc
{"presets": ["@babel/preset-env"],"plugins": []
}
//postcss.config.js
module.exports = {plugins: [require('autoprefixer')]
}
高级配置
基本配置只能做demo,不能做线上项目
面试考察基本配置,只是为了快速判断你是否用过webpack
以下高级配置,也是通过面试的必要条件
多入口
//webpack.common.jsentry: {index: path.join(srcPath, 'index.js'),other: path.join(srcPath, 'other.js')},// 多入口 - 生成 index.htmlnew HtmlWebpackPlugin({template: path.join(srcPath, 'index.html'),filename: 'index.html',// chunks 表示该页面要引用哪些 chunk (即上面的 index 和 other),默认全部引用chunks: ['index'] // 只引用 index.js}),// 多入口 - 生成 other.htmlnew HtmlWebpackPlugin({template: path.join(srcPath, 'other.html'),filename: 'other.html',chunks: ['other'] // 只引用 other.js})
//webpack.prod.js
output: {// filename: 'bundle.[contentHash:8].js', // 打包代码时,加上 hash 戳filename: '[name].[contentHash:8].js', // name 即多入口时 entry 的 keypath: distPath,// publicPath: 'http://cdn.abc.com' // 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到},
抽离css文件
//webpack.prod.js
const path = require('path')
const webpack = require('webpack')
const { smart } = require('webpack-merge')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const TerserJSPlugin = require('terser-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const webpackCommonConf = require('./webpack.common.js')
const { srcPath, distPath } = require('./paths')module.exports = smart(webpackCommonConf, {mode: 'production',output: {// filename: 'bundle.[contentHash:8].js', // 打包代码时,加上 hash 戳filename: '[name].[contentHash:8].js', // name 即多入口时 entry 的 keypath: distPath,// publicPath: 'http://cdn.abc.com' // 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到},module: {rules: [// 图片 - 考虑 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'}}},// 抽离 css{test: /\.css$/,loader: [MiniCssExtractPlugin.loader, // 注意,这里不再用 style-loader'css-loader','postcss-loader']},// 抽离 less --> css{test: /\.less$/,loader: [MiniCssExtractPlugin.loader, // 注意,这里不再用 style-loader'css-loader','less-loader','postcss-loader']}]},plugins: [new CleanWebpackPlugin(), // 会默认清空 output.path 文件夹new webpack.DefinePlugin({// window.ENV = 'production'ENV: JSON.stringify('production')}),// 抽离 css 文件new MiniCssExtractPlugin({filename: 'css/main.[contentHash:8].css'})],optimization: {// 压缩 cssminimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],}
})
//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'},// {// 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 webpack.DefinePlugin({// window.ENV = 'production'ENV: JSON.stringify('development')})],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': ''}}}}
})
//webpack.common.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { srcPath, distPath } = require('./paths')module.exports = {entry: {index: path.join(srcPath, 'index.js'),other: path.join(srcPath, 'other.js')},module: {rules: [{test: /\.js$/,loader: ['babel-loader'],include: srcPath,exclude: /node_modules/}// css 处理]},plugins: [// new HtmlWebpackPlugin({// template: path.join(srcPath, 'index.html'),// filename: 'index.html'// })// 多入口 - 生成 index.htmlnew HtmlWebpackPlugin({template: path.join(srcPath, 'index.html'),filename: 'index.html',// chunks 表示该页面要引用哪些 chunk (即上面的 index 和 other),默认全部引用chunks: ['index'] // 只引用 index.js}),// 多入口 - 生成 other.htmlnew HtmlWebpackPlugin({template: path.join(srcPath, 'other.html'),filename: 'other.html',chunks: ['other'] // 只引用 other.js})]
}
抽离公共代码
//webpack.prod.js
const path = require('path')
const webpack = require('webpack')
const { smart } = require('webpack-merge')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const TerserJSPlugin = require('terser-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const webpackCommonConf = require('./webpack.common.js')
const { srcPath, distPath } = require('./paths')module.exports = smart(webpackCommonConf, {mode: 'production',output: {// filename: 'bundle.[contentHash:8].js', // 打包代码时,加上 hash 戳filename: '[name].[contentHash:8].js', // name 即多入口时 entry 的 keypath: distPath,// publicPath: 'http://cdn.abc.com' // 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到},module: {rules: [// 图片 - 考虑 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'}}},// 抽离 css{test: /\.css$/,loader: [MiniCssExtractPlugin.loader, // 注意,这里不再用 style-loader'css-loader','postcss-loader']},// 抽离 less{test: /\.less$/,loader: [MiniCssExtractPlugin.loader, // 注意,这里不再用 style-loader'css-loader','less-loader','postcss-loader']}]},plugins: [new CleanWebpackPlugin(), // 会默认清空 output.path 文件夹new webpack.DefinePlugin({// window.ENV = 'production'ENV: JSON.stringify('production')}),// 抽离 css 文件new MiniCssExtractPlugin({filename: 'css/main.[contentHash:8].css'})],optimization: {// 压缩 cssminimizer: [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, // 大小限制,多少kb才打包,为了防止比较小的包打包出来反而浪费资源minChunks: 1 // 最少复用过几次 引用了一次就单独抽离出},// 公共的模块common: {name: 'common', // chunk 名称priority: 0, // 优先级minSize: 0, // 公共模块的大小限制,多少kb才打包,为了防止比较小的包打包出来反而浪费资源minChunks: 2 // 公共模块最少复用过几次 引用了2次就单独抽离出}}}}
})
//webpack.common.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { srcPath, distPath } = require('./paths')module.exports = {entry: {index: path.join(srcPath, 'index.js'),other: path.join(srcPath, 'other.js')},module: {rules: [{test: /\.js$/,loader: ['babel-loader'],include: srcPath,exclude: /node_modules/}]},plugins: [// new HtmlWebpackPlugin({// template: path.join(srcPath, 'index.html'),// filename: 'index.html'// })// 多入口 - 生成 index.htmlnew HtmlWebpackPlugin({template: path.join(srcPath, 'index.html'),filename: 'index.html',// chunks 表示该页面要引用哪些 chunk (即上面的 index 和 other),默认全部引用chunks: ['index', 'vendor', 'common'] // 要考虑代码分割}),// 多入口 - 生成 other.htmlnew HtmlWebpackPlugin({template: path.join(srcPath, 'other.html'),filename: 'other.html',chunks: ['other', 'common'] // 考虑代码分割})]
}
懒加载
//引入动态数据 - 懒加载
setTimeout(() => {import('./dynamic-data.js').then(res=>{console.log(res.default.message) //注意这里的default})
},1500)
处理JSX
//.babelrc
{"presets": ["@babel/preset-react"],"plugins": []
}
//webpack配置
{test: /\.js$/,loader: ['babel-loader'],include: srcPath,exclude: /node_modules/},
处理vue
{test: /\.vue$/,loader: ['vue-loader'],include: srcPath},
module chunk bundle的区别
module - 各个源码文件,webpack中一切皆模块,所有引入都是模块,js、css、img都是模块
chunk - 多模块合并成的,如entry import() splitChunk
bundle - 最终的输出文件,一般来说一个chunk对应一个bundle
module chunk bundle分别对应图中的左中右
webpack性能优化
大厂必考 & 社区热议话题
优化打包构建速度 - 开发体验和效率
优化产出代码 - 产品性能
构建速度
优化babel-loader
开启缓存,es6代码没改的不会重新编译
IgnorePlugin避免引入无用的模块
import moment from ‘moment’
默认会引入所有语言JS代码,代码过大
如何只引入中文?
//webpack.prod.js// 忽略 moment 下的 /locale 目录new webpack.IgnorePlugin(/\.\/locale/, /moment/),//index.jsimport moment from 'moment'
import 'moment/locale/zh-cn' //手动引入中文语言
moment.locale('zh-cn')//设置语言为中文
console.log('locale',moment.locale)
console.log('data',moment().format('ll')) //2020年xx月xx日
noParse避免重复打包
min,js基本上已经采用模块化处理过的
IgnorePlugin vs noParse
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多进程压缩JS
webpack内置Uglify工具压缩JS
JS单线程,开启多进程压缩更快
和happyPack同理
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,}}
})
关于开启多进程
项目较大,打包较慢,开启多进程能提高速度
项目较小,打包更快,开启多进程会降低速度(进程开销)
按需使用
自动刷新
// watch: true, // 开启监听,默认为 false// watchOptions: {// ignored: /node_modules/, // 忽略哪些// // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高// // 默认为 300ms// aggregateTimeout: 300,// // 判断文件是否发生变化是通过不停的去询问系统指定文件有没有变化实现的// // 默认每隔1000毫秒询问一次// poll: 1000// }
//devServer会默认开启自动刷新devServer: {port: 8080,progress: true, // 显示打包的进度条contentBase: distPath, // 根目录open: true, // 自动打开浏览器compress: true, // 启动 gzip 压缩hot: true,// 设置代理proxy: {// 将本地 /api/xxx 代理到 localhost:3000/api/xxx'/api': 'http://localhost:3000',// 将本地 /api2/xxx 代理到 localhost:3000/xxx'/api2': {target: 'http://localhost:3000',pathRewrite: {'/api2': ''}}}},
热更新
自动刷新:整个网页全部刷新,速度较慢
自动刷新:整个网页全部刷新,状态会丢失
热更新:新代码生效,网页不刷新,状态不丢失
//webpack.dev.js
const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin');entry: {// index: path.join(srcPath, 'index.js'),index: ['webpack-dev-server/client?http://localhost:8080/','webpack/hot/dev-server',path.join(srcPath, 'index.js')]},plugins: [new HotModuleReplacementPlugin()],devServer: {port: 8080,progress: true, // 显示打包的进度条contentBase: distPath, // 根目录open: true, // 自动打开浏览器compress: true, // 启动 gzip 压缩hot: true,// 设置代理proxy: {// 将本地 /api/xxx 代理到 localhost:3000/api/xxx'/api': 'http://localhost:3000',// 将本地 /api2/xxx 代理到 localhost:3000/xxx'/api2': {target: 'http://localhost:3000',pathRewrite: {'/api2': ''}}}},
//index.js
// 引入 css
import './style/style1.css'
import './style/style2.less'import { sum } from './math'const sumRes = sum(10, 20)
console.log('sumRes', sumRes)// 增加,开启热更新之后的代码逻辑if (module.hot) {module.hot.accept(['./math'], () => {const sumRes = sum(10, 30)console.log('sumRes in hot', sumRes)})}
DllPlugin动态链接库插件
针对一些比较大的库,第三方插件,没有必要每次打包时都打包一遍,可以事先打包好以后作为dll.然后引用它
前端框架如vue React,体积大,构建慢
较稳定,不常升级版本
同一个版本只构建一次即可,不用每次都重新构建
webpack已内置DllPlugin支持
DllPlugin - 打包出dll文件
DllReferencePlugin - 使用dll文件
//package.json
{"name": "08-webpack-dll-demo","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev": "webpack-dev-server --config build/webpack.dev.js","dll": "webpack --config build/webpack.dll.js"},"keywords": [],"author": "","license": "ISC","dependencies": {"react": "^16.12.0","react-dom": "^16.12.0"},"devDependencies": {"@babel/core": "^7.7.5","@babel/preset-env": "^7.7.5","@babel/preset-react": "^7.7.4","babel-loader": "^8.0.6","html-webpack-plugin": "^3.2.0","webpack": "^4.41.2","webpack-cli": "^3.3.10","webpack-dev-server": "^3.9.0","webpack-merge": "^4.2.2"}
}
//webpack.dll.js
const path = require('path')
const DllPlugin = require('webpack/lib/DllPlugin')
const { srcPath, distPath } = require('./paths')module.exports = {mode: 'development',// JS 执行入口文件entry: {// 把 React 相关模块的放到一个单独的动态链接库react: ['react', 'react-dom']},output: {// 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,// 也就是 entry 中配置的 react 和 polyfillfilename: '[name].dll.js',// 输出的文件都放到 dist 目录下path: distPath,// 存放动态链接库的全局变量名称,例如对应 react 来说就是 _dll_react// 之所以在前面加上 _dll_ 是为了防止全局变量冲突library: '_dll_[name]',},plugins: [// 接入 DllPluginnew DllPlugin({// 动态链接库的全局变量名称,需要和 output.library 中保持一致// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值// 例如 react.manifest.json 中就有 "name": "_dll_react"name: '_dll_[name]',// 描述动态链接库的 manifest.json 文件输出时的文件名称path: path.join(distPath, '[name].manifest.json'),}),],
}
npm run dll后dist文件夹下会生成react.dll.js和react.manifest.json
//index.html<script src="./react.dll.js"></script>
//webpack.dev.js// 第一,引入 DllReferencePlugin
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');module: {rules: [{test: /\.js$/,loader: ['babel-loader'],include: srcPath,exclude: /node_modules/ // 第二,不要再转换 node_modules 的代码},]},
plugins: [// 第三,告诉 Webpack 使用了哪些动态链接库new DllReferencePlugin({// 描述 react 动态链接库的文件内容manifest: require(path.join(distPath, 'react.manifest.json')),}),
],
总结
webpack优化构建速度(可用于生产环境)
优化babel-loader
IgnorePlugin
noParse
happyPack
ParallelUglifyPlugin
webpack优化构建速度(不用于生产环境)
自动刷新
热更新
DllPlugin
优化产出代码
体积更小
合理分包,不重复加载
速度更快、内存使用更小
小图片base64编码
bundle加hash
懒加载
提取公共代码
IgnorePlugin使打出体积更小
使用CDN加速
//webpack.prod.js中配置cdn地址output: {publicPath: 'http://cdn.abc.com' // 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到},{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'}}
}
把静态文件上传至CDN
使用production
- 自动开启代码压缩
- Vue React等会自动删掉调试代码(如开发环境的warning)
- 启动Tree-Shaking,没有用到的方法不会加载,把没有用的的摇掉
// ES6 Module 才能让 tree-shaking 生效
// commonjs 就不行
ES6 Module和commonjs的区别
ES6 Module静态引入,编译时引入
Commonjs动态引入,执行时引入
只有ES6 Module才能静态分析,实现Rree-Shaking
Scope Hosting
一个函数就有一个作用域,很多文件就会产生很多函数,很多作用域
开启Scope Hosting之后,很多文件都放在一个函数里,作用域数量更少,内存占用更少,也不会频繁的去跨作用域调用,JS代码也会执行得快一些
代码体积更小
创建函数作用域更少
代码可读性更好
babel
前端开发环境必备工具
同webpack,需要了解基本的配置和使用
面试考察概率不高,但要求必会
环境搭建 & 基本配置
- 环境搭建
- .babelrc配置
- presets和plugins
//package.json
{"name": "09-babel-demo","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","devDependencies": {"@babel/cli": "^7.7.5","@babel/core": "^7.7.5","@babel/plugin-transform-runtime": "^7.7.5","@babel/preset-env": "^7.7.5"},"dependencies": {"@babel/polyfill": "^7.7.0","@babel/runtime": "^7.7.5"}
}
//.babelrc
{"presets": [["@babel/preset-env",{}]],"plugins": []
}
preset-env是一堆常用plugins的集合
//index.js
const sum = (a,b) => a + b
npx babel src/index.js
babel-polyfill
什么是Polyfill
浏览器补丁、兼容
core-js和regenerator
标准库,集成了ES6、ES7新语法的Polyfill
core-js不能处理generator函数,要用regenerator库
babel-polyfill即两者的集合
Babel7.4之后弃用babel-polyfill
推荐直接使用core-js和regenerator
但不影响面试会考察它
babel-polyfill如何按需引入
babel只关心语法,即便API不支持,只要语法符合规范,不管API,也不管模块化
文件较大
只有一部分功能,无需全部引入
配置按需引入
//babelrc
{"presets": [["@babel/preset-env",{"useBuiltIns": "usage","corejs": 3}]],"plugins": []
}
//index.js
const sum = (a, b) => a + b// 新的 API
Promise.resolve(100).then(data => data);// 新的 API
[10, 20, 30].includes(20)// 语法,符合 ES5 语法规范
// 不处理模块化(webpack)
没有使用babel-polyfill,直接引入core-js,babel-polyfill可以不用下载
babel-runtime
babel-polyfill的问题
- 会污染全局环境
- 如果做一个独立的web系统,则无碍
- 如果做一个第三方lib,则会有问题
// core.js要这样处理,会污染全局环境
// window.Promise1 = function() {}
// Array.prototype.includes1 = function () {}// 使用方可能这样用,会出现问题
// window.Promise = 'abc'
// Array.prototype.includes = 100
babel-runtime处理这个问题
devDependencies安装 “@babel/plugin-transform-runtime”: “^7.7.5”,
dependencies安装 “@babel/runtime”: “^7.7.5”
//.babelrc
{"presets": [["@babel/preset-env",{"useBuiltIns": "usage","corejs": 3}]],"plugins": [["@babel/plugin-transform-runtime",{"absoluteRuntime": false,"corejs": 3,"helpers": true,"regenerator": true,"useESModules": false}]]
}
配置后编译出来的promise和includes前面有_,就不会有污染全局作用域问题
(十)webpack 和 babel相关推荐
- webpack与babel的深奥,渣渣的我只能做个小笔记(持续更新)
最近公司封装的构建库用多了,感觉自己正在一步一步的变傻,所以趁还没下雪,手脚还没长冻疮,没事还是自己折腾一下吧. 本想记笔记,但没想到记笔记没法传图片.所以如果你看到了,就忽略了吧.o(╥﹏╥)o o ...
- 使用webpack、babel、react、antdesign配置单页面应用开发环境
这是Webpack+React系列配置过程记录的第一篇.其他内容请参考: 第一篇:使用webpack.babel.react.antdesign配置单页面应用开发环境 第二篇:使用react-rout ...
- React+Webpack+Eslint+Babel构建React脚手架
React+webpack+Eslint+Babel构建React脚手架 参考网上文章,说的不是很全,想自己写一篇来巩固知识点,脚手架源码参考阮一峰老师的Github 所用技术栈 React Babe ...
- 前端工资涨不上去?可能是你没掌握构建工具:关于 Webpack、Babel、esbuild、Vite、Rollup、Parcel、SWC......的那些事
每个前端都应该掌握构建工具 大概从 2019 年到现在的这三年多的时间里,构建工具几乎已经成为前端发展最快的一个部分. 构建工具,属于前端工程化领域.而前端工程化,是每一个高级前端开发人员都必须要去深 ...
- webpack 配置 babel
文章目录 根据 webpack 版本的不同,安装的 babel 依赖有些区别,下面的是 webpakc 4.2 及以上版本安装的依赖. 4.2 之前的是:babel-core.babel-pres ...
- Vue之webpack之Babel
现在想把es6的代码,转成es5的代码. 记录一下方法: 首先新建一个webpack_babel 然后执行 npm init -y 会自动生成一个package.json的文件 安装babel插件: ...
- webpack和babel的区别
webpack webpack是一个打包工具,打包js.css.图片.html等,它可以分析整个项目的文件结构,确认文件之间的依赖,将文件合成.压缩.加入hash等,生成最终项目文件. babel b ...
- webpack及babel配置
请先确认自己的电脑已经安装了 node 和 npm,没有安装的请先安装,以下操作需在安装了这两个的基础上操作 webpack配置 1. 创建一个空文件夹 2. 创建 package.json 文件- ...
- es6,es7,webpack 和 babel(爱前端)
npm install -g cnpm --registry=https://registry.npm.taobao.org 默认安装位置: 一 ES6, ES7 简介和调试方法 1.1 简介 ECM ...
最新文章
- linux空洞目录,学习笔记:linux之文件空洞
- 网工协议基础(2) TCP/IP四层模型
- highly dynamic working process is a great approach for learning
- SpringBoot 基础拦截器
- Android开发:4-2、不同Activity数据的传递
- 什么是分布式_什么是分布式系统,如何学习分布式系统?
- gimp 去掉一个颜色的背景_把拍出来的图片文件的背景阴影去掉——用GIMP色阶功能修图
- C#带参数线程的操作
- Spark的三种运行模式
- 反编译那些事儿(六)—所编译得.class文件带有$符号
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_4-2.微服务下登录检验解决方案 JWT讲解...
- 字节码指令之异常处理指令
- STM32F103C8T6在Arduino框架下驱动ssd1306 0.96“ IIC OLED显示
- 组合数学(2)——组合矩阵
- 数学计算机学具制作,《 用计算器计算》四年级数学
- mysql order by 排序技巧
- 基督教 犹太 新教 东正教 天主教
- Gather-Excite:Exploiting Feature Context in Convolutional Neural Networks
- 关于多线程中的面试题
- Unix操作系统历史