优化(学习)公司的webpack配置

2021年遇到的项目中,我遇到了一些特别难受的问题:

  1. webpack 编译慢,多达50多秒( 我觉得是文件结构深,很多文件冗余的原因)
  2. 打包体积大,优化过后还有90M
  3. CI/CD慢,一个小bug,因为CI/CD慢,甚至半天一天久过去了(当然也没有一把过的原因)
  4. 项目首屏加载慢
  5. node_module 体积超级大,达到惊人的1.4G

昨天,就是3.23号,我试着优化了node_module,经过一天的努力,我决定还是先不要搞这个问题,但是也不是一无所获。

导致node_module 过大的原因主要有几点
1、 循环依赖,比如module_A 依赖module_B,而module_B依赖module_C…

2、 npm 策略有缺陷,多个依赖都依赖module_A,但是在不同的层级中都下载了module_A,没有重复使用 module_A

尝试的解决方法:

使用pnpm:

​ pnpm 可以把依赖树扁平,使得多个依赖共同使用,不用重复下载。

结果:

成功把1.4G 的 module优化到了400多M, 大大的提高了项目的初次启动工作,减少了极其繁琐的pakege安装…在启动项目的时候,发现有些依赖没有下载到,所以项目根本启动不了。

2022.03.23结


今天,3.24号,我把目光放在了webpack的配置里面

背景:公司使用自己封装的webpack打包工具(可以理解为 webpack-tool),这个工具把根据公司通用的项目结构写的, 并把这个发布到了公司自己的npm 仓库中。这样有好处先不谈,缺点就是难于自定义配置。

原来的项目打包只需要

 "dev": "cross-env-shell NODE_OPTIONS=--max_old_space_size=4096 LANGUAGES_ENV=zhCN ENV=loc NODE_ENV=development npx webpack-tool run -m dev",

开始操作:

安装webpack 和 webpack-cli 并且运行

// 安装
npm install webpack webpack-cli –g
// 运行
npx webpack

因为没有设置webpack的mode,所有发生警告,但是问题不大,webpack 会默认按生产模式打包,同时人口文件默认是index.js ,默认输出打包文件在dist 目录下。

新建webpack.config.js

在根目录下,与src 同级别,新建一个webpack.config.js 文件(文件名规定这样),webpck运行的时候,会自动根据这个文件里的配置进行打包

webpack.config.js

module.exports = {mode:'development', // development, productionentry:'./src/index.js' // 入口文件output: {// webpack 如何输出结果的相关选项path:path.resolve(__dirname, "dist"), // string (default)// 必须是绝对路径filename: "bundle.js" // string (default)}module:{ // 配置loaderrules:[]},resolve:{alias:{ // 设置别名}},plugins:[ // webpck 插件]

两个插件

webpack 打包过程中,会触发很多的钩子函数,webpack 的插件,本质上就是一个构造函数,并且在函数内部了定义了webpack 钩子函数触发时要对项目进行的处理,比如我们想要在 react.js 在生命周期componentDidMount里要做什么

介绍两个比较有用的插件

html-webpack-plugin

该插件将为你生成一个 HTML文件,会在 body 中使用 script 标签引入 webpack打包生成的 bundle.js。 只需添加该插件到你的 webpack 配置中,就不用手动添加。而且成都的html文件在内存中,减少了磁盘的读写。

webpack-dev-server

你启动webpack-dev-server后,
你在目标文件夹中是看不到编译后的文件的,实时编译后的文件都保存到了内存当中。因此很多同学使用webpack-dev-server进行开发的时候都看不到编译后的文件

npm install --save-dev html-webpack-plugin
npm install --save-dev webpack-dev-server

如果不使用HtmlWebpackPlugin,那么就需要在使用bundle.js(webpack打包好之后的js文件) 的html文件中使用src的方式引入

index.html

<script src="dist/bundle.js">

使用 HtmlWebpackPlugin之后,webpack 会自动把打包好的文件引入对应的html 模板文件,不需要手工操做,让我们的双手可以解决另外的问题

webpack-dev-serve 可以帮我们启动服务,不然我们就需要在每改一次代码,删掉dist 文件夹,重新打包,在打开index.html

使用webpack-dev-serve 之后,就可以设置端口,启动热更新等的

https://webpack.docschina.org/plugins/html-webpack-plugin/

https://webpack.docschina.org/api/webpack-dev-server/#Installation

webpack.config

// 配置 在webpack.config.js 的plugins 里面
plugins: [new webpack.HotModuleReplacementPlugin(), // 启动热更新第三步: new HtmlWebpackPlugin({template: './src/index.html', // 编译模板title:"会员经营平台", // 等等其他参数}),
]

新建文件 Serve.js

const Webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const webpackConfig = require('./webpack.config.js');const compiler = Webpack(webpackConfig);
const devServerOptions = {open: false,   // 打开浏览器port: 3001,    // 端口号static: './src/index.html',hot: true,        //启动热更新第一步compress: false,
};//  WebpackDevServer输入两个参数
const server = new WebpackDevServer(devServerOptions, compiler);server.startCallback(() => {console.log('Successfully started server on http://localhost:8080');
});

把pakage.json 文件中公司以前的命令修改为自己的

// 原来的
"dev": "cross-env-shell NODE_OPTIONS=--max_old_space_size=4096 LANGUAGES_ENV=zhCN ENV=loc NODE_ENV=development npx webpack-tool run -m dev",// 修改为
"dev": "NODE_ENV=development  LANGUAGES_ENV=zhCN ENV=loc NODE_ENV=development node ./Server.js",

那么以后的启动命令就可以是

npm run dev

总结:

  1. webpack-dev-server 给我们起了一个服务

  2. html-webpack-plugin 在内存中生成了一个html文件,并把打包的好的bundle.js 用script的str引入

  3. 在有服务,并且服务启动的前提下,才可以利用webpck本身的一个插件启用热更新。

    new webpack.HotModuleReplacementPlugin(),


超级磨人的 babel-loader

开始我们的第一个loader前:什么是loader?为什么要用loader?

因为webpack 会把入口文件(index.js),以及入口文件所有引用的文件,全部打包成一个js文件(出口文件bundle.js)。但是webpack 只能理解普通的js 文件,不能理解ES6 的语法,所以需要把高级语法,转为webpack 可以理解的es5语法的javascript.

babel-loader 这是一个很强大(磨人)的loader ,并且需要和其他的插件一起使用

// 安装babel以及其核心依赖 两者版本需要对应
npm install --save-dev babel-loader@^7.1.5 babel-core@^7.0.0-bridge.0 // @babel/preset-env  替换babel-preset-es2015,转译语法,const let 箭头函数等
npm install --save-dev  @babel/preset-env// @babel/plugin-proposal-class-properties 编译ES6 class类语法
npm install --save-dev @babel/plugin-proposal-class-properties// plugin-transform-runtime
npm install --save-dev plugin-transform-runtime// @babel/plugin-proposal-decorators  编译装饰器的语法
npm install --save-dev @babel/plugin-proposal-decorators//  @babel/preset-react 编译react的jsx 语法
npm install --save-dev  @babel/preset-react// babel-plugin-transform-imports 模块化导入 按需引入 预防变量全局污染
npm babel-plugin-transform-imports

配置

 module:{rules:[{test: /\.(js|jsx)$/,exclude: /(node_modules)/, // 编译的时候排除这个文件夹use: {loader: 'babel-loader',options: {presets: ["@babel/preset-env","@babel/preset-react",],plugins: [//执行的顺序是从右向左,所以基础插件要放在最后["@babel/plugin-proposal-decorators", { "legacy": true }],["@babel/plugin-proposal-class-properties"],["@babel/plugin-transform-runtime"],[require('babel-plugin-transform-imports'), {"my-component": {transform: function(importName, matches) {let newPath =`my-component/component/${importName}`return newPath},preventFullImport: true},lodash: {transform: "lodash/${member}",preventFullImport: true}}]]}}}]}

总结:

  1. babel-loader 依赖 babel-core,两者的版本很重要,即便搞过几次,但是在版本的不对的时候,还是花 了好写时间处理,所以在下载依赖的时候,还是把版本也加上吧

  2. babel/preset-env 可以对语法进行编译,编译成浏览器可以给理解的javaScript,可以指定浏览器和node的版本,制定兼容什么版本,也是一个可以减少代码体积的方案。

  3. babel/plugin-proposal-class-properties 可以对class类进行编译,{ loose: false },此参数默认false ,在编译class 累的时候,赋值声明等是用" = ",如果设置了false,那么就用使用 Object.defineProperty() 解析claas。

    babel https://babeljs.io/docs/en/assumptions#setpublicclassfields

  4. babel/plugin-proposal-decorators 是用装饰器的时候需要编译把装饰器语法编译为普通的语法

    // 案例一 antd 3.x,把from的api注入到组件中
    import { Form } from "antd";
    class DemoDetails extends React.Component {...something
    }
    export default Form.create()(DemoDetails);

    如果是只用装饰器那么就可以这样子写,并且我们可以把其他的方法也可以通过装饰器的方式主注入到组件的props中,如果没有装饰器语法,那么可以想象要嵌套多少层调用。

    虽然有点跑题,但是总的来说,如果要是用装饰器,那么就等是把装饰器语法编译为普通的语法,就需要使用这个插件

    import { Form } from "antd";
    import { withRouter } from 'react-router-dom';
    import { observer } from 'mobx-react';@Form.create() // 注入antd 的form的api
    @withRouter    // 注入后可以在props中拿到router 对象
    @observer  // 给组件添加订阅
    class DemoDetails extends Component {...something
    }
    export default DemoDetails
  5. plugin-transform-runtime 对引入的对象和全局变量是完全隔离。会把我们声明的变量前面加一个_比如_userName

  6. babel/preset-react把jsx 编译为classCreaat() 语法,就是处理react.js的

  7. babel-plugin-transform-imports 可以帮我们按需引入组件

    src\my-component\index.js

    module.exports = {}; // 只有空空的一个文件夹
    

    src\my-component\conponent文件夹下面有很多的组件

    src

    -my-component

    ​ -omponent

    ​ -MyButton

    ​ -MyForm

    ​ -MyTable

    ​ -inde.js

    那么如果要使用组件MyTable, 那么需要使用MyTabl组件就需要把完整的路径写完,但是我们可以使用babel-plugin-transform-imports帮我。

    // 使用前
    import MyTable from 'my-componet/component/MyTable'
    // 使用后
    import {MyTable } from 'my-componet'
    

    当Babel遇到import的时候会怎么样呢

    import { Grid, Row, Col } from 'react-bootstrap';
    

    babel 会简单的编译为下面的样子,这样就会把整个文件加载进来。

    var reactBootstrap = require('react-bootstrap');var Grid = reactBootstrap.Grid;
    var Row = reactBootstrap.Row;
    var Col = reactBootstrap.Col;
    

    这个babel 的插件可以帮我们自动把导入编译为一下模式,这样就可以大大的减少了打包体积了

    import Grid from 'react-bootstrap/lib/Grid';
    import Row from 'react-bootstrap/lib/Row';
    import Col from 'react-bootstrap/lib/Col';
    

    https://segmentfault.com/a/1190000010787241


第二个loader

webpack 只会处理的普通的js问价,是不能理解css,less 的,所以我们需要讲css编译成webpack 熟悉的js

安装

npm install --save-dev style-loader css-loader less-loader

配置

 module:{rules:[... other loader{test:/\.(js|jsx)$/,use:['style-loader','css-loader','less-loader']}]}

注意的是,当有多个loader 共同处理时,loader 是顺序是从右往左的:less-loader 处理完得到css文件,再经过css-loadr 处理,style-loader 就可以使用了

配置全局css变量,配置主题等

themes.less

// 部分代码
@yx_yxHd:  2px;
@primary-color: #1861F2;
// @primary-color: #000; // 全局主色
@success-color: #52c41a; // 成功色
@font-size-base: 14px; // 主字号
@heading-color: rgba(0, 0, 0, 0.85); // 标题色
@text-color-secondary : rgba(0, 0, 0, .45); // 次文本色

other.less

// 不需要导入既可以使用变量:@yx_yxHd
//圆点/Circle
.yx_yxCircle_sm{width: 4 * @yx_yxHd;height: 4 * @yx_yxHd;border: 1px;box-sizing: border-box;
}

安装,配置

// 安装 less-vars-to-js,可以把文件,转为js的对象形式
npm install --save-dev less-vars-to-js
/* 配置 */
const fs = require('fs')
const lessToJs = require('less-vars-to-js');// 读取less 文件
const paletteLess = fs.readFileSync(path.resolve(__dirname, "src/themes/themes.less"), 'utf8');// 转为js 对象
const baseLess = lessToJs(paletteLess, {resolveVariables: true,stripPrefix: false
});// 配置 webpack.config.jsmodule:{rules:[... other loader{test:/\.(js|jsx)$/,use:[{loader: 'style-loader',},{loader: 'css-loader',},{loader: 'less-loader',options: {lessOptions: {strictMath: true,modifyVars: lessVars,// less 变量javascriptEnabled: true,},},},]}]}

设置别名

resolve: {alias: {src: path.resolve(__dirname, 'src'),utils: path.resolve(__dirname, 'src/utils'),config: path.resolve(__dirname, 'src/config'),my-conponent: path.resolve(__dirname, 'src/conponent'),assets: path.resolve(__dirname, 'src/assets'),router: path.resolve(__dirname, 'src/router'),themes: path.resolve(__dirname, 'src/themes'),pages: path.resolve(__dirname, 'src/pages'),}
},

从开始把目光放在了node_module 文件上,到把精力投入到webpck 中,可以说,没有那一分钟事没有遇到过问题,都是在不断的看博客,找webpack 官网等,有的问题已经搞定,但是也有的花了很多的时间也没有处理好。

问题一

按照我的理解,如果我在运行一面的这一命令,那么我就可以在项目中根绝着几个变量,配置项目的

"dev": "NODE_ENV=development  LANGUAGES_ENV=zhCN ENV=loc NODE_ENV=development node ./Server.js",

而我在webpack .config.js 文件去没有拿到对应的变量

console.log("webpackConfigJs:",NODE_ENV,LANGUAGES_ENV,NODE_ENV); // ReferenceError: NODE_ENV is not defined
console.log("webpackConfigJs:",process.env);  // 没有发现对应的变量
console.log(process);  // 还是没有发现

webpack 还挺有趣,下周如果原型还没有出来的话,继续优化这个项目

优化(学习)公司的webpack配置(一)相关推荐

  1. js webpack 配置路径_Vue.js学习No.5(WebPack配置二)

    学习的内容如下 开始 当我们需要频繁的修改main.js 我们每次都需要去构建,这样显得很麻烦,webpack .srcmain.js -o .distbundle.js,通过配置文件去配置每次的打包 ...

  2. vue中webpack默认配置_Vue-cli 中 Webpack 配置优化(一)

    一.前言 最近一段时间在学习 Webpack 方面的知识.在学习的过程中主要配置的是 webpack.config.js 文件. 但是在 Vue-cli 3.x 下,已经对 Webpack 做了深度的 ...

  3. 六、Webpack详解学习笔记——webpack的安装、起步、配置、loader的使用、webpack中配置Vue、plugin的使用、搭建本地服务器、webpack配置的分离

    一.认识webpack 什么是webpack? 这个webpack还真不是一两句话可以说清楚的. 我们先看看官方的解释: At its core, webpack is a static module ...

  4. vue webpack 访问php,实例详解vue-cli优化的webpack配置

    最近的项目度过了开始忙碌的基建期,也慢慢轻松下来,准备记录一下自己最近webpack优化的措施,希望有温故知新的效果.本文主要介绍了详解基于vue-cli优化的webpack配置,小编觉得挺不错的,现 ...

  5. webpack打包生成的map文件_从这十几个方面优化你的 Webpack 配置

    目录 开发环境性能优化 生产环境性能优化 开发环境性能优化 优化打包构建速度 HMR 优化代码调试 source-map HMR ❝ 概念:「HMR:」 hot module replacement ...

  6. 基于vue-cli的webpack配置优化

    基于vue-cli优化的webpack配置 大概分为以下几点 通过 externals 配置来提取常用库,引用外链 配置CommonsChunkPlugin提取公用代码 (vue-cli已做) 善用a ...

  7. webpack配置与优化

    1.认识配置项 1.1.入口(entry) 入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始.进入入口起点后,webpack 会找出有哪些模块和库 ...

  8. webpack打包优化之外部扩展(Externals)配置

    基本使用 webpack可以使用externals配置,将某些模块不打包到输出文件中,从而使用用CDN引入外部模块 这样操作下来,不仅可以提高打包速度,还能优化网页加载性能. index.html & ...

  9. 干货! 快速上手typescript的学习笔记 (对比JS的新特性,环境搭建,webpack配置,ts编译配置)

    前提需要有js的基础 文章目录 TypeScript 产生背景 什么是TypeScript? TypeScript增加了什么 TypeScript开发环境搭建 基本类型 编译文件配置 tsconfig ...

最新文章

  1. springboot后台弹出前台对话框_基于springboot的精品小说网站
  2. LINQ中的Let关键字
  3. 富文本编辑器ckeditor的使用
  4. 反思赚钱:一定要动脑子 一定找发财点
  5. 前端公共库CDN加速
  6. 【STM32】Keil5支持包下载教程
  7. 面向对象程序设计 第六次作业
  8. 数据结构之判断一棵树是不是满二叉树
  9. idhttp.post方式 调用datasnap rest 远程方法
  10. TensorFlow学习之——checkpoints
  11. colspan会影响内部单元格宽度失效_冷轧轧辊失效原因分析及改进措施
  12. uni-app与java的交互且使用小米球Ngrok连接到手机微信小程序
  13. Python机器视觉--OpenCV入门--机器视觉与OpencCV用途简介
  14. Cisco交换机IOS升级
  15. 李沐-->深度学习计算
  16. python通过指定网卡发包_Python选择网卡发包及接收数据包
  17. LTspice快速上手--搭建简单RC电路
  18. 天融信AlphaFuzzer测试工具 使用教程
  19. android 中shape的使用
  20. js原生写时间日期选择

热门文章

  1. 形式与政策网课ZIP解压密码
  2. C语言规范:C89、C90、C95、C99
  3. 落单的数IV --- lintcode 824
  4. 深入浅出 “三门问题”
  5. 博途S7-1200 和 S7-1200之间PROFINET以太网S7通信教程
  6. 奇思妙想构造题 ARC145 D - Non Arithmetic Progression Set
  7. 一文解读广告投放全攻略,提升拓客效率
  8. 波形生成:均匀和非均匀时间向量
  9. Idea的k8s插件
  10. 4-20mA 电压控制电流输出电路浅析