webpack工程化

概念

本质:通过编译打包是项目开发版和上线版完全分离

原理:模块打包,把模块接收并进行处理,最后生成几个静态资源文件,最后项目引入资源文件

强大的功能:懒加载,代码分割,Tree Shaking

webpack打包工具模块:打包过程中代码转换与项目代码与结构优化的一系列工具集合

  1. uglifyjs-webpack-plugin: 压缩混淆JS插件
  2. html-webpack-plugin:压缩HTML注入脚本插件
  3. autoprefixer:自动添加CSS兼容性前缀插件
  4. clean-webpack-plugin:清除多余文件插件
  5. babel-loader/babel-core/babel-preset-latestES6脚本代码转换工具模块
  6. ejs/ejs-loader:模板文件编译工具模块
  7. css-loader/postcss-loader/style-loader:编译CSS样式代码并放入html内部样式表的工具模块
  8. file-loader/url-loader/img-loader/image-webpack-plugin:对图片文件进行压缩及目录位置移动的工具模块与插件
  9. sass-loader/node-sass:编译sass文件

结构

  1. dist - 上线文件夹
  2. src - 打包配置文件夹
  3. webpack.config.js - 打包配置文件
  4. package-lock.json - 记录安装包版本与来源
  5. package.json - 记录项目所需要模块信息
  6. dist > css/fonts/js/scripts - 静态文件文件夹
  7. src > components - 组件文件夹
  8. src > css - 样式文件夹
  9. src > img - 图片文件夹
  10. src > js - 逻辑层脚本文件夹
  11. src > models - 模型层脚本文件夹
  12. src > utils - 工具模块文件夹
  13. src > index.html - 视图层HTML文件

组件化

组件化目录结构:对应页面的组件

  1. src > components
  2. > cart/detail/haader/index目录
  3. > list_item组件文件夹
  4. > index.tpl/index.js/index.scss

关于index.js入口文件:

  • 如果在组件文件里(src/components/header/list_item/index.js), 就为组件的入口文件,负责引入scss/tpl文件且导出一个函数返回一个带名字和模板的对象
  • 如果在项目JS目录下(src/js/index.js),就为逻辑层的主JS文件,负责每个页面的主入口,引入所有组件页面,引入数据模型,且对DOM进行操作,页面渲染
  • 如果在模型层目录下(src/models/index.js),每个页面对应的异步数据请求(ajax/axios),组合成html字符串

工具集合

  1. src > utils
  2. - config.js:配置API接口的地址
  3. - http.js:封装的ajax函数
  4. - tool.js:处理事件/正则等

模块

工程化 - 图1

webpack

好处:

  • 只加载一个js文件
  • 对引入文件的来源有记录import xx from './xxx'
  • 会翻译关键字import代码

缺点:

  • 只知道模块相关的事情(仅仅是模块打包工具)
  • 刚开始只支持js类型的模块文件
  • 后续其他模块类型需要配置

安装

  1. //安装webpack
  2. npm i -D webpack@4.45.0
  3. //安装webpack-cli 可以在命令行工具输入webpack相关命令
  4. npm i -D webpack-cli@3.3.10

使用

  1. //基础命令webpack
  2. //执行npx webpack文件翻译index.js
  3. npx webpack ./src/js/index.js
  4. //打包成功生成 dist/main.js(翻译后的代码)

配置

  1. //配置webpack.config.js
  2. //node只支持commonjs写法
  3. const path = require('path');
  4. module.exports = {
  5. entry: path.resolve(__dirname, 'src/js/index.js'),
  6. output: {
  7. //dist目录默认输出main.js,此时更改名为bundle.js
  8. filename: 'bundle.js',
  9. //出口目录为dist里面的bundle.js文件
  10. path: path.resolve(__dirname, 'dist')
  11. }
  12. }

更名

  1. //一般情况,webpack会自动寻找webpack.config.js配置文件
  2. //假如需要更改webpack.config.js => webpack.dev.config.js
  3. //1.更改名称为webpack.dev.config.js
  4. //2.脚本更改命令 dev => webpack --config webpack.dev.config.js

入口

entry入口不设置名称情况下默认打包后名称为dist/main.js

  1. //entry可以同时配置多个入口 如主入口和子入口
  2. module.exports = {
  3. ...,
  4. entry: {
  5. main: path.resolve(__dirname, 'src/js/index.js'),
  6. sub: path.resolve(__dirname, 'src/js/index.js')
  7. },
  8. output: {
  9. //会根据main/sub.js生成
  10. filename: '[name].js',
  11. path: path.resolve(__dirname, 'dist')
  12. },
  13. }
  14. //此时,dist目录下生成main.js和sub.js

加载器

属于webpack模块里

  1. //配置模块规则
  2. //module对象 => rules数组 => 对象里配置

处理css, jpg, png, scss 需要loader处理相应的模块

图片处理

使用场景:

  • 如果图片较大,bundle.js文件里base64图片地址代码过长,造成bundle.js文件体积过大,影响页面加载速度,推荐用file-loader生成jpg文件
  • 如果图片较小,因为通过file-loader生成jpg文件时多发送一次HTTP请求,所以推荐url-loader生成base64地址

file-loader

  1. //处理图片
  2. //安装file-loader
  3. npm i -D file-loader@6.2.0
  4. //配置模块规则
  5. //module对象 => rules数组 => 对象里配置
  6. module.exports = {
  7. ...,
  8. module: {
  9. rules: [{
  10. test: /\.jpg|jpeg$/,
  11. use: {
  12. loader: 'file-loader',
  13. //对file-loader进行配置
  14. options: {
  15. //对生成后的图片名称改为指定的名称
  16. //如cat.jpg => cat.jpg
  17. name: '[name].[ext]',
  18. //将生成后图片文件放入指定的目录
  19. //如此一来,打包后图片将存放在dist/imgs/目录里
  20. outputPath: 'imgs/'
  21. }
  22. }
  23. }]
  24. }
  25. }
  1. //尝试引入图片 并打印
  2. import catImg from '../cat.jpg';
  3. console.log(catImg);
  4. //重新打包
  5. //浏览器控制台打印
  6. f4138709b57185fb12c8f07bbdbc38c1.jpg
  7. //并发现dist目录下生成名字为xxxxxxxxxx.jpg的图片
  8. //尝试插入图片到页面
  9. const img = new Image();
  10. img.src = '../dist/' + catImg;
  11. app.appendChild(img);
  12. //页面显示图片成功

url-loader

  1. //利用url-loader也可以处理图片
  2. //与file-loader相似,但是返回DataUrl,即base64格式图片地址
  3. //安装url-loader
  4. npm i -D url-loader@4.1.1
  5. //配置模块规则
  6. //module对象 => rules数组 => 对象里配置
  7. module.exports = {
  8. ...,
  9. module: {
  10. rules: [{
  11. test: /\.jpg|jpeg$/,
  12. use: {
  13. loader: 'url-loader',
  14. //对file-loader进行配置
  15. options: {
  16. //对生成后的图片名称改为指定的名称
  17. //如cat.jpg => cat.jpg
  18. name: '[name].[ext]',
  19. //将生成后图片文件放入指定的目录
  20. //如此一来,打包后图片将存放在dist/imgs/目录里
  21. outputPath: 'imgs/'
  22. }
  23. }
  24. }]
  25. }
  26. }
  27. //发现dist目录没有图片文件,但页面正常渲染图片
  28. //查看图片元素地址为data:image/jpeg;base64xxxxxx开头的地址

配置:灵活根据图片大小来选择加载器生成图片或生成图片地址

  1. module.exports = {
  2. ...,
  3. module: {
  4. rules: [{
  5. test: /\.jpg|jpeg$/,
  6. use: {
  7. loader: 'url-loader',
  8. //对file-loader进行配置
  9. options: {
  10. ...,
  11. //如图片大于2048字节,单独生成文件
  12. //如图片很小,生成base64地址
  13. limit: 20480
  14. }
  15. }
  16. }]
  17. }
  18. }

处理样式

css-loader&style-loader

  1. //安装
  2. npm i -D css-loader@5.0.1
  3. npm i -D style-loader@2.0.0
  4. //配置
  5. module.exports = {
  6. ...,
  7. module: {
  8. rules: [
  9. ...,
  10. {
  11. test: /\.css$/,
  12. //loader执行顺序:从后往前/从下往上
  13. use: ['style-loader', 'css-loader']
  14. }]
  15. }
  16. }
  17. //打包后成功显示样式

sass-loader&node-sass

  1. //安装
  2. npm i -D sass-loader@10.1.1
  3. npm i -D node-sass@5
  4. //配置
  5. //将原来匹配css改变为匹配scss
  6. module.exports = {
  7. ...,
  8. module: {
  9. rules: [
  10. ...,
  11. {
  12. test: /\.scss$/,
  13. use: ['style-loader', 'css-loader', 'sass-loader']
  14. }]
  15. }
  16. }
  17. //打包后成功显示样式

处理前缀

postcss-loader&autoprefixer

  1. //低版本浏览器没有css3里面的transform: rotate(45deg);
  2. //如何兼容? postcss-loader结合autoprefixer
  3. //autoprefixer可以增加厂商前缀 如-webkit-tranform: rotate(45deg)
  4. //安装
  5. cnpm i -D postcss-loader@4.1.0
  6. cnpm i -D autoprefixer@10.2.3
  7. //配置
  8. module.exports = {
  9. ...,
  10. module: {
  11. rules: [
  12. ...,
  13. {
  14. test: /\.scss$/,
  15. use: [
  16. 'style-loader',
  17. 'css-loader',
  18. //webpack老版本写法 兼容4.x以下
  19. {
  20. loader: 'css-loader',
  21. options: {
  22. importLoaders: 2
  23. }
  24. }
  25. 'postcss-loader',
  26. 'sass-loader'
  27. ]
  28. }]
  29. }
  30. }
  31. //需要在项目根目录新建postcss.config.js且配置
  32. module.exports = {
  33. plugins: [
  34. //引入插件
  35. require('autoprefixer')
  36. ]
  37. }
  38. //package.json配置增加
  39. "browserslist": [
  40. //针对市场份额大于1%
  41. "> 1%",
  42. //最近两个版本
  43. "last 2 versions"
  44. ]
  45. //打包后成功显示样式

处理字体

iconfont字体库下载字体

将字体文件放入src/css/fonts

  1. module.exports = {
  2. ...,
  3. module: {
  4. rules: [
  5. ...,
  6. {
  7. test: /\.(svg|eot|ttf|woff|woff2)$/,
  8. use: {
  9. loader: 'file-loader',
  10. options: {
  11. name: '[name].[ext]',
  12. outputPath: 'fonts/',
  13. }
  14. }
  15. }]
  16. }
  17. }
  18. //将字体css样式放入index.scss里
  19. @font-face {
  20. font-family: "iconfont"; /* Project id 2738996 */
  21. src: url('../fonts/iconfont.woff2?t=1634310802163') format('woff2'),
  22. url('../fonts/iconfont.woff?t=1634310802163') format('woff'),
  23. url('../fonts/iconfont.ttf?t=1634310802163') format('truetype');
  24. }
  1. //渲染字体
  2. const app = document.getElementById('app');
  3. app.innerHTML = '<div class="iconfont iconaixin"></div>';
  4. //图标字体成功显示

插件

webpack里面的插件

  1. plugins: []

dist目录生成html文件

html-webpack-plugin

  1. //安装
  2. npm i -D html-webpack-plugin@4.5.1
  3. //配置
  4. const HtmlWebpackPlugin = require('html-webpack-plugin');
  5. module.exports = {
  6. ...,
  7. plugins: [
  8. new HtmlWebpackPlugin()
  9. ]
  10. }
  11. //打包完成时dist目录下自动创建除了引用bundle.js以外的空白的index.html文件
  12. //为了解决空白的index.html,可以提供模板scr/index.html
  13. //配置
  14. module.exports = {
  15. ...,
  16. plugins: [
  17. new HtmlWebpackPlugin({
  18. template: './src/index.html'
  19. })
  20. ]
  21. }
  22. //再打包后发现dist目录重新生成指定模板的index.html文件

清理dist目录文件的插件

clean-webpack-plugin

  1. //安装
  2. npm i -D clean-webpack-plugin@3.0.0
  3. //引入且配置
  4. const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  5. module.exports = {
  6. ...,
  7. plugins: [
  8. new CleanWebpackPlugin()
  9. ]
  10. }
  11. //打包后发现dist目录先清除后被存入打包文件

sourceMap

帮助于调试代码

默认控制台错误会跟踪到dist/main.js 而不是src/js/index.js

利用sourcemap设置可以实现

  1. //配置项
  2. module.exports = {
  3. ...,
  4. //源文件 速度最快
  5. devtool: 'eval-source-map',
  6. //生成映射关系的map文件 dist/main.js.map 速度稍快
  7. //devtool: 'cheap-module-source-map',
  8. }

开发服务

webpack-dev-server

注意:使用webpackDevServer是不会生成dist打包文件,但会在内存里生成打包文件,提高效率

提供一个开发服务器实现实时网页更新,不需要频繁的输入打包命令

  1. //安装
  2. npm i -D webpack-dev-server@3
  3. //配置
  4. module.exports = {
  5. ...,
  6. devServer:{
  7. //指向dist目录
  8. contentBase: './dist'
  9. //指定端口
  10. prot: 3000
  11. }
  12. }
  13. //修改脚本命令
  14. "dev": "webpack-dev-server"

请求转发

使用指定的地址访问指定API地址

  1. //安装axios请求API数据
  2. import axios from 'axios';
  3. axios.get('http://study.jsplusplus.com/Yixiantong/getHomeDatas')
  4. .then(res => console.log(res));

一般来说,本地接口跟线上接口很有可能不在同一台服务器上,意味着上面的绝对路径接口地址就不好用了,所以一般会改为相对路径

  1. axios.get('/Yixiantong/getHomeDatas')
  2. .then(res => console.log(res));
  3. //报错:GET http://localhost:8080/Yixiantong/getHomeDatas 404 (Not Found)

但是改为相对路径会报错,所以这样的情况可以做相对接口的请求转发

  1. //当请求http://localhost:8080/Yixiantong时通过webpackDevServer帮助转发给http://study.jsplusplus.com/域名
  2. //配置
  3. module.exports = {
  4. ...,
  5. devServer:{
  6. //指向dist目录
  7. contentBase: './dist',
  8. open: true,
  9. proxy: {
  10. //一旦访问匹配到指定开头的路径
  11. //'/Yixiantong'
  12. //'api/Yixiantong'
  13. //以api开头
  14. '/api': {
  15. //转发到目标的域名地址
  16. target: 'http://study.jsplusplus.com/',
  17. //对源做了限制
  18. changeOrigin: true,
  19. //针对请求地址是https时
  20. secure: false,
  21. //如果有指定的写法 如api/Yixiantong
  22. //访问http://study.jsplusplus.com/api/Yixiantong
  23. //可以对其路径重写
  24. pathRewrite: {
  25. //去掉api
  26. '^/api': ''
  27. }
  28. }
  29. }
  30. }
  31. }
  32. //此时可以正常访问到API数据

自动刷新

页面刷新

WDS

webpackDevServer 提供一个配置可以定时的去刷新打包打包并刷新页面重新加载静态资源文件

注意:webpackDevServer都是针对开发环境来实现的,生产环境无法使用

  1. //自动刷新控制台提示
  2. [WDS]Live Reloading enabled.
  1. //配置
  2. module.exports = {
  3. ...,
  4. //监听源代码变化,如有变化重新打包
  5. watch: true,
  6. watchOption: {
  7. ignored: /node_modules/,
  8. //不想刷新的太快
  9. aggregateTimeout: 300,
  10. //每隔一定时间去询问系统,文件是否存在更改
  11. poll: 1000
  12. }
  13. }

热更新

热更新HMR提供实时数据跟新

问题:为什么需要HMR?

如点击或者输入事件时,不能实时更新内容,不会实时渲染

自动刷新和热更新区别:

自动刷新只是重新加载静态文件刷新页面,会导致状态丢失,如输入文本的内容丢失,变量声明的丢失等,热更新则保留状态

  1. //热更新控制台提示
  2. [HMR]Waiting for update signal from WDS...
  1. //引入插件
  2. //webpack内置的HotModuleReplacementPlugin
  3. const webpack = require('webpack');
  4. //配置
  5. module.exports = {
  6. ...,
  7. devServer:{
  8. ...,
  9. //开启HMR
  10. hot: true
  11. },
  12. plugins: [
  13. new webpack.HotModuleReplacementPlugin()
  14. ]
  15. }
  16. //控制台显示(说明热更新启动成功)
  17. [HMR] Waiting for update signal from WDS...
  18. [WDS] Hot Module Replacement enabled.
  19. [WDS] Live Reloading enabled.
  1. //webpack-dev-server3.9.0版本 配置写法
  2. //引入热更新插件
  3. const WebpackCommonConfig = require('./webpack/lib/HotModuleReplacementPlugin');
  4. module.exports = {
  5. ...,
  6. entry: {
  7. index: path.join(srcPath, 'index.js'),
  8. index:[
  9. 'webpack-dev-server/client?http://localhost:8080/',
  10. 'wepack/hot/dev-server',
  11. path.join(srcPath, 'index.js')
  12. ]
  13. },
  14. devServer:{
  15. ...,
  16. //开启HMR
  17. hot: true
  18. },
  19. plugins: [
  20. new webpack.HotModuleReplacementPlugin()
  21. ]
  22. }

如果是样式刷新,热更新是会生效的,且保留状态(style.loader底层有代码实现)

如果是逻辑代码刷新,热更新会失效,不保留状态,需要继续配置

  1. //逻辑代码里
  2. //如果开启了 热更新
  3. if(module.hot){
  4. //参数1: 热更新监测范围
  5. //参数2: 热更新后回调自定义的代码内容
  6. //只有修改math.js里的代码会触发热更新
  7. module.hot.accept(['./math.js'], ()=>{
  8. console.log('hello');
  9. });
  10. }

es6

处理es6代码

babel-loader&@babel/core&@babel/preset-env

  1. //安装
  2. npm i -D babel-loader@8.2.2
  3. npm i -D @babel/core@7.12.10
  4. npm i -D @babel/preset-env@7.12.11
  5. //配置
  6. module.exports = {
  7. ...,
  8. module: {
  9. rules: [
  10. ...,
  11. {
  12. test: /\.js$/,
  13. loader: 'babel-loader',
  14. options: {
  15. presets: ['@babel/preset-env']
  16. },
  17. exclude: /node_modules/
  18. }
  19. ]
  20. }
  21. }

@babel/polyfill

解决promise和map方法的实现(早期es3没有)

关于:corejs

一个标准的库,提供polyfill es6 es7等方法实现

  1. //安装
  2. npm i -D @babel/polyfill@7.12.1
  3. //引入
  4. import '@babel/polyfill';
  5. const promiseArray = [
  6. new Promise(()=>{}),
  7. new Promise(()=>{})
  8. ];
  9. promiseArray.map(promise => {
  10. console.log('promise', promise);
  11. });
  12. //使用了polyfill后 打包后 体积更大
  13. //实现了es6新特性 箭头函数等
  14. //按需加载新特性配置
  15. module.exports = {
  16. ...,
  17. module: {
  18. rules: [
  19. ...,
  20. {
  21. test: /\.js$/,
  22. loader: 'babel-loader',
  23. options: {
  24. presets: [
  25. ['@babel/preset-env'], {
  26. useBuiltIns: 'usage'
  27. //版本号:3
  28. corejs: 3
  29. }
  30. ]
  31. },
  32. exclude: /node_modules/
  33. }
  34. ]
  35. }
  36. }

babel/plugin-transform-runtime开发依赖

babel/runtime生存依赖

帮助polyfill改变内库,内部插件 造成的全局污染问题

  1. //安装
  2. npm i -D @babel/plugin-transform-runtime@7.15.8
  3. npm i -S @babel/runtime@7.15.4
  4. //配置
  5. module.exports = {
  6. ...,
  7. module: {
  8. rules: [
  9. ...,
  10. {
  11. test: /\.js$/,
  12. loader: 'babel-loader',
  13. options: {
  14. plugins: [
  15. ['@babel/plugin-transform-runtime', {
  16. "absoluteRuntime": false,
  17. "corejs": 3,
  18. "helpers": true,
  19. "regenerator": true,
  20. "useESModules": false,
  21. "version": "7.0.0-beta.0"
  22. }]
  23. ]
  24. },
  25. exclude: /node_modules/
  26. }
  27. ]
  28. }
  29. }

.babelrc

专属配置babel的文件

主要写两个配置项presets/plugins数组

  1. {
  2. "presets": [
  3. [
  4. "@babel/preset-env",
  5. {
  6. "useBuiltIns": "usage",
  7. "corejs":3
  8. }
  9. ]
  10. ],
  11. "plugins": [
  12. [
  13. "@babel/plugin-transform-runtime",
  14. {
  15. "absoluteRuntime": false,
  16. "corejs": 3,
  17. "helpers": true,
  18. "regenerator": true,
  19. "useESModules": false,
  20. "version": "7.0.0-beta.0"
  21. }
  22. ]
  23. ]
  24. }

Tree Shaking

使用tree shaking概念智能的去除没有使用的代码再打包

注意:只支持ES Module规范,不支持CommonJS规范

  1. //只需要配置生产模式即可触发tree shaking打包不引用的代码
  2. mode: 'production'

关于ES Module 和 CommonJS:

  • ES Module 是静态引入 编译时引入 import xxx from 'xxx' 只能写在首行 不能嵌套在if语句或函数内
  • CommonJS 是动态引入 执行时引入 const xxx = require('xxx')

chunks

将处理过的css/js/scss文件处理成块 再处理变成静态文件供网页加载

代码分割

splitChunks分割出一个个的chunks,无论同步引入还是异步引入分割

  1. //场景:默认情况会依次打包,所以lodash会被打包2次
  2. //a.js(lodash + a业务代码 + 公共代码a)
  3. //b.js(lodash + b业务代码 + 公共代码a)
  4. //如何实现代码分割?
  5. //将lodash提取并单独打包成为一个叫vendor.js文件
  6. //将公共代码a提取并单独打包成为一个叫common.js文件
  7. //最终,并再需要的时候引入vendor.js或common.js文件
  8. //实现代码体积减少
  9. optimization: {
  10. splitChunks: {
  11. chunks: 'all'
  12. }
  13. }

babel

babeljs.io

JavaScript的编译器

转码前(es5 -> es6)需要插件plugins, 预设presets将包含所有的插件

  1. {
  2. "presets": [
  3. [
  4. "@babel/preset-env"
  5. ]
  6. ],
  7. "plugins": [
  8. ]
  9. }

关于babel-polyfill(7.4已废弃)已经包含corejs 和 regenerator,废弃后直接可以用babel直接引用

babel 集成了corejs 和 regenerator,corejs包含了ES6 新语法特性 polyfill(实现),多人维护,比较可靠

缺点:不支持ES6特性的实现(generator 函数)

  1. //关于generator函数
  2. function* test(){
  3. console.log('settle a');
  4. yield 'a';
  5. console.log('settle b');
  6. yield 'b';
  7. }
  8. let res = test();
  9. console.log(res.next());
  10. console.log(res.next());
  11. console.log(res.next());

需要另外的库去实现generator函数,叫regenerator, 帮助定义generator函数,如何实现方法

  1. //安装并引入@babel/polyfill
  2. import '@babel/polyfill';
  3. //编译代码
  4. npx babel ./src/index.js
  5. //编译后的代码可以在浏览器内运行了

优化

如何提高webpack性能优化?(开发模式)

  • 优化打包构建速度

    • 优化babel-loader编译范围(越少越好)
    • IgnorePlugin避免不必要的模块
    • noParse避免打包已经打包过的模块
    • happyPack/ParalelUglifyPlugin多进程打包
    • 自带刷新,热更新
    • DllPlugin预先打包一次
  • 优化打包文件体积

    • 图片较少时,采用base64编码格式
    • 哈希值
    • 懒加载
    • 代码分割

忽略插件

IgorePlugin()

  1. plugins: [
  2. //忽略moment时间地区插件里除了中国地区以外的时间和地区语言包代码
  3. new webpack.IgorePlugin(/.\/locale/, /moment/)
  4. ]

不打包

noParse

不做打包,但打包生成的代码里有相关代码

  1. noParse: [/vue\.min\.js/],
  2. mode: ...

多线程打包

NodeJS 基于JS 单线程

Webpack 基于 NodeJS 单线程 开启多线程打包 提高打包速度

happyPack帮助开启多进程打包

  1. //安装
  2. npm i -D happypack@5.0.1
  3. //引入和配置
  4. const HappyPack = require('happypack');
  5. module.exports = {
  6. ...,
  7. module: {
  8. rules: [
  9. ...,
  10. {
  11. test: /\.js$/,
  12. use: ['happypack/loader?id=babel']
  13. }
  14. ]
  15. },
  16. plugins: [
  17. new HappyPack({
  18. id: 'babel',
  19. loaders: ['babel-loader?cacheDirectory']
  20. })
  21. ]
  22. }

代码压缩

UglifyjsWebpackPlugin

压缩js代码

  1. //安装
  2. npm i -D webpack-parallel-uglify-plugin@1.1.2
  3. //引入和配置
  4. const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
  5. module.exports = {
  6. ...,
  7. plugins: [
  8. new ParallelUglifyPlugin({
  9. uglifyJS: {
  10. beautify: false,
  11. comments: false
  12. }
  13. })
  14. ]
  15. }

动态连接库

DLLPlugin

提高打包构建速度

预先打包一次 存放某一个地方 使用的时候引用,类似vue/react,优化打包构建速度

  1. //针对dll的配置
  2. //webpack.dll.conf.js
  3. //引入webpack自带的dll插件
  4. const DllPlugin = require('webpack/lib/DLLPlugin');
  5. module.exports = {
  6. mode: 'development',
  7. entry: {
  8. //当项目引入react/react-dom的时候会打包到/dist/react.js文件里
  9. react: ['react', 'react-dom']
  10. },
  11. output: {
  12. //打包生成 bundle 的名字 react.dll.js
  13. filename: '[name].dll.js',
  14. //distPath
  15. path: path.join(__dirname, '..', 'dist'),
  16. //srctPath
  17. //path: path.join(__dirname, '..', 'src'),
  18. //定义全局变量 _dll_react 在react.dll.js文件里
  19. library: '_dll_[name]'
  20. },
  21. plugins: [
  22. new DllPlugin({
  23. name: '_dll_[name]',
  24. //mainfest.json 是一个映射的文件 把相关不同的js文件做不同的映射
  25. path: path.join(distPath, '[name].mainfest.json')
  26. }),
  27. new DllReferencePlugin()
  28. ]
  29. }
  1. //脚本
  2. "dll": "webpack --config build/webpack.dll.conf.js"
  1. //webpack.dev.conf.js
  2. //引入DllReferencePlugin
  3. const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
  4. module.exports = {
  5. ...,
  6. plugins: [
  7. new DllReferencePlugin({
  8. //使用dist/react.mainfest.json文件
  9. mainfest: require(path.join(distPath, 'react.mainfest.json'))
  10. })
  11. ]
  12. }

处理顺序:

当逻辑代码里引入import React from 'react';/importReactDOM from 'react-dom';会打包成相应的配置和映射文件

减少代码体积的目的:

  • 减少代码体积
  • 合理分包,不重复加载
  • 内存占用更少

哈希值

利用output设置哈希值实现唯一文件内容加载,避免浏览器缓存加载

  1. output: {
  2. filename: '[name].[contentHash:8].js',
  3. path: distPath
  4. }

懒加载

  1. setTimeout(()=>{
  2. import('./test.js');
  3. }, 3000);