如何消除无用代码;打包自己的私有js库;实现代码分割和动态import提升初次加载速度;配置eslint规范团队代码规范;打包异常抓捕你都get到了么?

摇树优化:Tree Shaking

webpack借鉴了rollup构建工具,从2.0就实现支持tree shaking,其中,到webpack4.0后 通过开启mode:'production'即默认开启。

tree shaking原理

DCE(Dead code elimination),即死码消除,编译器原理中,死码消除(Dead code elimination)是一种编译最优化技术,它的用途是移除对程序运行结果没有任何影响的代码。

其中死码的特点:

  • 代码不会被执行,不可到达

  • 代码执行的结果不会被用到

  • 代码只会影响死变量(只读不写)

其中,tree shaking就是借鉴了这个原理,利用了ES6模块的特点:

  • 其中import、exports只能作为模块顶层的语句出现

  • import 的模块名只能是字符串常量

  • import 的模块名是常量不能进行修改

tree shaking就是利用ES6的这一特点,本质就是对静态的模块代码进行分析,所以需要 在构建过程中确定哪些模块的代码能利用到,哪些模块不需要进行区分。通过标识不需要 使用的代码在uglify阶段删除无用代码。

tree shaking概念和使用

顾名思义,tree shaking摇树优化其中就是类似于摇晃树,过程会使一些枯枝枯叶掉落。

tree shaking就是通过在构建过程,如果一个模块存在多个方法,如果只有其中的某个方法 使用到,则将一些没有引用到的代码在这个打包过程移除,只把用到的方法打入bundle中。

通过开启mode:'production'即可。其中,只支持ES6的语法,commonjs的方式(即require方式)不支持使用。

作用域提升:Scope Hoisting

webpack的模块机制

我们可以了解到,webpack打包出来的是一个IIFE(立即调用函数表达式,也是常说的匿名闭包), 其中,modules数组的每一项是一个模块初始化函数,通过webpackrequire的方式来加载模块, 返回module.exports,并且通过webpackrequire_(0)的方式启动程序。

scope hoisting原理及使用

在没有开启scope hoisting前,这样构建后的代码会存在大量的闭包代码。

由于模块依赖,通过webpack打包后会转换成自执行匿名函数,这样, 由于大量函数闭包包裹代码,会导致体积增大(模块越多就越明显);运行代码 时创建的函数作用域变多,导致内存开销也变大。

其中,scope hoisting的概念也是借鉴了rollup的构建原理并在webpak3.0时候引入, 其原理就是将所有模块的代码按照引入顺序放到一个函数作用域里,然后适当的重命名 一些变量以防止变量名冲突。这样就可以实现减少函数声明代码和内存花销。

在webpack4中,也只需要把mode状态调整为production即默认开启,其中,需要注意的是 只支持ES6语法,commonjs的动态引入还不支持。

而webpack3中则需要配置插件 webpack.optimize.ModuleConcatenationPlugin

代码分割和动态import

对于一些大型的web应用,将代码打包到一个chunk是不够有效的,会导致加载的文件过大,导致页面加载慢,体验差等。所以需要通过代码分割成多个chunks,当代码运行到需要时候才进行加载。

一般通过抽离相同代码到一个共享块或者脚本懒加载使得初始下载的代码更小。
前面我们已经说到通过SplitChunksPlugin来进行通用的代码抽离,而懒加载脚本的方式我们需要条件判断等方式通过ES6的动态import的方式实现。
其中,动态import目前没有原生支持,需要babel转换。安装依赖并配置.babelrc

npm i @babel/plugin-syntax-dynamic-import -D

配置.babelrc

{
"plugins": [
"@babel/plugin-syntax-dynamic-import"
]
}

通过动态import,点击事件加载脚本,demo:

JavaScript语法规范:ESLint

ESLint 是一个插件化并且可配置的 JavaScript 语法规则和代码风格的检查工具,能够及早的发现代码错误并且帮助保持团队代码风格的统一。

其中比较有名的ESLint规范实践有:eslint-config-airbnb、eslint-config-alloy、eslint-config-ivweb等。

可通过基于eslint:recommend配置对规范进行改进。

eslint规则

规则名称 错误级别 说明
for-direction error for循环的方向要求必须正确
getter-return error getter必须有返回值,并且禁止返回值为undefined,比如return
no-await-in-loop off 允许在循环里面使用await
no-console off 允许在代码里面是有console
array-callback-return error 对于数据相关操作函数比如reduce、map、filter等,callback必须有return
accessor-pairs warn 在字符串里面出现(和)进行警告

更多规则可参考:https://eslint.org/docs/rules/

ESLint落地

具体ESLint落地的实施可以有两个方案,通过CI/CD(持续集成/持续交付)系统集成或者和webpack等构建工具集成

ESLint与CI/CD系统集成

gitlab集成lint的常用做法:

本地开发时可以通过增加precommit钩子实现开发环境的检查。
安装husky并配置package

npm i husky -D
"scripts":{
"precommit":"lint-staged"
},
"lint-staged":{
"linters":{
"*.js": ["eslint-fix","git add"]
}
}

webpack与ESLint集成

通过使用eslint-loader,构建时检查JS规范。这种做法比较适合新项目的使用。因为该方案会默认在开发构建时对所有文件进行规范的检查。

安装基于react的eslint的依赖包,eslint-config-alloy

npm install --save-dev eslint babel-eslint eslint-plugin-react eslint-config-alloy
npm i eslint-loader -D

配置.eslintrc.js parser使用babel-eslint,并继承eslint-config-airbnb

npm i eslint-config-airbnb -D
// .eslintrc.js
module.exports = {
"parser": "babel-eslint",
"extends": [
'alloy',
'alloy/react',
],
"rules": {
"indent": ["error",4]
},
"env": { // 当前生效环境
"browser": true,
"node": true
}
}

打包组件和基础库

webpack不仅可以用来打包应用,也可以用来打包js库来方便我们的日常开发。

实现大整数加法库的打包demo

1、确定打包需求:

  • 需要打包压缩版和非压缩版本

  • 支持script标签/AMD/CJS/ESM模块引入

2、js库的目录结构

.
├── dist // 打包输出文件夹
| ├── webpack-larger-number.js // 未压缩版输出文件
| └── webpack-larger-number.min.js //压缩版
├── package.json // 依赖包配置说明
├── webpack.config.js // 打包配置
├── index.js //
├── src // 源码
└── index.js

3、配置webpack

相对于一般打包应用,我们需要配置output参数实现将库暴露出去,其中,library可以指定库的名称

module.exports = {
output: {
filename: "[name].js",
library: "WebpackLargeNumber", // 指定库的全局变量
libraryExport: "default",
libraryTarget: "umd" // 支持库引入的方式,默认以libary指定的变量名
}
}

更多详情参数可参考:https://www.webpackjs.com/configuration/output/#output-library

配置webpack,指定.min文件压缩

module.exports  = {
mode: 'none',
optimization: {
minimize: true, // 默认为true,压缩js代码
minimizer: [
new TerserPlugin({ // terser-webpack-plugin支持es6语法压缩
include: /\.min\.js$/
})
]
}

更多optimization可参考:https://webpack.docschina.org/configuration/optimization/
然后设置入口文件,对于开发环境则引入未打包的js库,而生产环境则使用压缩后的库

4、设置package的入口文件并设置对应环境变量引入不同的库。

// package.js
"main": "index.js",
// index.js
if (process.env.NODE_ENV == 'production') {
module.exports = requier('./dist/webpack-large-number.min.js')
} else {
module.exports = require('./dist/webpack-large-number')
}

最后,我们也可通过npm publish发布到npm上(ps:需要npm账号),然后我们就可以通过npm下载依赖包 并且通过默认的导出名WebpackLargeNumber.add('99','2')方式直接使用函数。

大整数加法demo:https://github.com/PCAaron/blogCode/tree/master/webpack/webpack-large-number

优化构建命令行日志:stats + friendly-errors-webpack-plugin

使用webpack打包的时候,默认会将所有的打包构建信息打印出来,而stats选项则可以很好获取部分需要的bundle信息。

常见的stats值:

Preset Alternative Description
errors-only none 只在发生错误时输出
minimal none 只在发生错误或有新的编译时输出
none false 没有输出
normal true 标准输出
verbose none 全部输出

配置webpack,其中,需要注意的是,对于webpack-dev-server,stats需要放到devServer中。

module.exports = {
stats: 'errors-only'
}

通过设置stats为errors-only,我们可以看到dev和build的日志成功的话也没有一些bundle信息,这是,我们可以借助friendly-errors-webpack-plugin对命令行的日志进行优化。

安装friendly-errors-webpack-plugin并配置。

npm i friendly-errors-webpack-plugin -D

配置webpack

const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')
module.exports = {
plugins: [
new FriendlyErrorsWebpackPlugin()
]
}

构建异常和中断处理

如果打包时候存在一些构建异常和中断,需要捕获并做一些异常提示或者内容上报时候,我们可以通过compiler在每次构建结束后出发done的钩子实现异常的抓捕。

其中,我们需要借助node的process.exit抛出异常,默认情况下, process.exit抛出0表示成功,err为null;而非0则执行失败, 其中err为错误信息,code为对应的状态码。

配置webpack

module.exports = {
plugins: [
function () {
this.hooks.done.tap('done', stats => {
if (stats.compilation.errors && stats.compilation.errors.length &&
process.argv.indexOf('--watch') == -1) {
console.log('build err')
process.exit(1)
}
})
}
]
}

webpack系列

导读

webpack基础篇

webpack进阶篇

欢迎star关注更新:https://github.com/PCAaron/PCAaron.github.io

推荐阅读

代码demo:https://github.com/PCAaron/blogCode/tree/master/webpack/webpack-improveMore

Scope Hoisting优化Webpack输出:https://www.imweb.io/topic/5a43064fa192c3b460fce360

webpack进阶用法你都get到了么?的更多相关文章

  1. webpack进阶构建项目(一)

    webpack进阶构建项目(一) 阅读目录 1.理解webpack加载器 2.html-webpack-plugin学习 3.压缩js与css 4.理解less-loader加载器的使用 5.理解ba ...

  2. Django框架学习-Model进阶用法

    Model进阶用法 回顾 访问外键 访问多对多关系 更改数据库结构 当处理数据库结构改变时,需要注意到几点: 增加字段 首先在开发环境中: 再到产品环境中: 删除字段 删除多对多字段 删除model ...

  3. canvas图形处理和进阶用法

    前面的话 上一篇博客介绍了canvas基础用法,本文将更进一步,介绍canvas的图形处理和进阶用法 图形变换 图形变换是指用数学方法调整所绘形状的物理属性,其实质是坐标变形.所有的变换都依赖于后台的 ...

  4. 前端自动化测试神器-Katalon进阶用法

    前言 上一篇介绍了Katalon的基础用法,本篇继续介绍一些进阶的用法. Keyword 和 Method Call Statement Keyword Keyword就是自定义方法,该方法在当前项目 ...

  5. ASP.NET Core 6框架揭秘实例演示[14]:日志的进阶用法

    为了对各种日志框架进行整合,微软创建了一个用来提供统一的日志编程模式的日志框架.<日志的基本编程模式>以实例演示的方式介绍了日志的基本编程模式,现在我们来补充几种"进阶" ...

  6. Spring Data JPA系列3:JPA项目中核心场景与进阶用法介绍

    大家好,又见面了. 到这里呢,已经是本SpringData JPA系列文档的第三篇了,先来回顾下前面两篇: 在第1篇<Spring Data JPA系列1:JDBC.ORM.JPA.Spring ...

  7. webpack进阶--打包

    上一片博文主要让大家了解下究竟webpack是干什么的,明显它是专注于打包的. gulp  和  webpack  的区别 gulp,要求我们一步步写task(es6编译.css压缩.图片压缩.打包. ...

  8. SpringBoot进阶用法-随笔

    SpringBoot进阶用法 实现setApplicationContext //实现ApplicationContextAware接口,重写setApplicationContext方法 publi ...

  9. CocoaPods学习系列4——进阶用法

    这篇文章,记录一下CocoaPods的进阶用法. 进阶用法主要体现在.podspec文件和Podfile的配置上. .podspec文件的进阶配置 以官方的一个.podspec文件示例细说: Pod: ...

随机推荐

  1. 2018-7-31-C#-判断两条直线距离

    title author date CreateTime categories C# 判断两条直线距离 lindexi 2018-07-31 14:38:13 +0800 2018-05-08 10: ...

  2. linux 分配和释放设备编号

    在建立一个字符驱动时你的驱动需要做的第一件事是获取一个或多个设备编号来使用. 为 此目的的必要的函数是 register_chrdev_region, 在 <linux/fs.h>中声明: ...

  3. async和await的执行顺序问题

    说明 : 要了解执行顺序,所需要的知识是了解浏览器js运行机制,以及微任务和宏任务的先后顺序.如果你明白了宏任务.微任务,请往下看: async function async1 () { consol ...

  4. P1038 间谍入侵

    题目描述 爱丽丝魔法王国成立10周年,于是决定矩形国庆大阅兵. 在国庆大阅兵期间,为了防止暗黑王国的间谍乔装成平民混入,需要对每一个进城的人做检测. 因为暗黑王国的人长得和爱丽丝魔法王国的人长得很像, ...

  5. dotnet core 通过 frp 发布自己的网站

    很多时候写出来的网站只能自己内网访问,本文告诉大家如何通过 Frp 将自己的 asp dotnet core 网站发布到外网,让小伙伴访问自己的网站 通过 frp 的方式,可以解决自己的服务器性能太差 ...

  6. H3C 因特网域名结构树

  7. Git的使用--如何将本地项目上传到Github(两种简单、方便的方法..)

    https://blog.csdn.net/u014135752/article/details/79951802 总结:其实只需要进行下面几步就能把本地项目上传到Github 1.在本地创建一个版本 ...

  8. Node.js Windows Binary二进制文件安装

    1.下载文件 安装包的下载路径为:https://nodejs.org/en/download/ 选择你需要的版本,这里我选择了 Windows Binary 64-bit 版本. 2.配置npm安装 ...

  9. 【HTML/CSS】置换元素

    置换元素: 一个内容不受CSS视觉格式化模型控制,CSS渲染模型并不考虑对此内容的渲染,且元素本身一般拥有固有尺寸(宽度,高度,宽高比)的元素,被称之为置换元素. 行内级置换和非置换元素的宽度定义 对 ...

  10. I/O 端口和 I/O 内存

    每个外设都是通过读写它的寄存器来控制. 大部分时间一个设备有几个寄存器, 并且在连 续地址存取它们, 或者在内存地址空间或者在 I/O 地址空间. 在硬件级别上, 内存区和 I/O 区域没有概念上的区 ...