2020年疫情期间无聊,研究从零搭建一个React开发环境。
React 开发必不可少工程化,所以打包工具是必须的,我们使用 webpack 。
-
处理
.js|.jsx
文件 [✔] -
处理兼容性
2.1 css兼容(post-cssnext)[✔]
2.2 js兼容 babel-polyfill [❌] -
按需加载/文件分离
css分离了,js分离还需要继续优化
-
处理
.css|.less
文件 [✔] -
自动添加浏览器前缀
postcss
[✔] -
文件分离 [✔]
-
处理模板文件 [✔]
-
模板文件变量 [❌]
-
图片资源处理 [✔]
-
fontIcon [❌]
-
按需加载 [✔]
-
分离文件 [✔]
-
分析打包 [✔]
-
代码规范(es-lint) [✔]
-
jsconfig [✔]
-
热重载 [✔]
-
代码提示 [✔]
-
包引入 [❌](仍有问题)
--registry https://registry.npm.taobao.org/
- webpack webpack 核心
- webpack-dev-server webpack服务器,热重载等
- webpack-cli webpack 集成命令
- webpack-merge webpack配置文件合并
- webpackbar webpack大包进度条
- happypack 多线程打包
- style-loader 把css文件插入到HTML文件内
- css-loader 编译css文件
- postcss-loader 编译css
- less-loader 编译less
- mini-css-extract-plugin(尽在prod环境有效) css文件抽离出js,默认是加入到js文件中的
- postcss-cssnext postcss使用的加载器,用于添加前缀,兼容等操作
- cssnano 对css文件进行操作,去重,压缩,优化等等
- less less语法解析
babel是一个解析器,把高版本ES的待吗转为低版本的代码,但是默认只会转化语法,而不会新增API,比如:Object.prototype.includes
等等方法。
因此需要一些垫片,常见的就是polyfill
和 babel-runtime
- 二者都可以添加高级语法API
-
polyfill
添加的新api会对全局进行污染方法例如:if(!Object.prototype.includes){ Object.prototype.includes=XXX }
而
babel-runtime
则会var _includes = XXX;
在使用的时候也会把使用的方法改为
_includes
,由于打包都是使用自执行函数区分模块和作用域,所以并不会影响到其他的代码造成污染,同样其他的方法也无法使用!
一般 babel-runtime
是一些类库开发着开发的时候使用的打包方法,这样保证了类库自身的执行,而不会影响到使用着的环境。同时,它还有提取冗余工具函数的功能,比如:在webpack
中babel引入此方法可以减少引入多个相同的工具方法,减少打包体积。
现在打包会变成
var _includes = XXX;
var Object.includes = _includes;
多加了,一步
由于 babel-runtime
的升级,只需要在 @babel/preset-env
的 options
中像 babel/polyfill
以这样配置即可,不需要再,安装 babel/polyfill
,但是必须保证core-js@3
和 regenerator-runtime
存在于 node_modules
中。
事实上 babel/polyfill,就是这两个包的集成。
在[email protected],之前,我们使用 babel-runtime
(提取公共助手方法) 和 babel/polyfill
(解决不兼容) 联合,起来(注意是要用在项目开发,如果你要开发类库,最好还是不要污染全局变量!会对使用者造成无法预料的问题,参考antd事件)。打包文件相对小一点。
在@[email protected]之后,大可以全交给 babel-runtime
处理,这样打包下来文件相对会比较大。
我们首先要知道,webpack 打包的机制。
一般情况下,类库的作者,会使用 babel-runtime
来兼容自己在写类库的时候用到的一些高级API,并且不会污染全局。这是非常好的。我们一般会把他们当成一个独立的个体,而在webpack打包的时候,会把这部分代码直接拷贝过来,不进行任何处理!在webpack配置的时候,我们总会提到 include
和 exclude
用来排除 node_modules
里面的文件文件,增快编译时间,这就导致了一个问题,我们可以看一下,在 antd
这类的UI框架中,除了暴漏给我们打包好的 xx.js
文件之外(独立个体文件),还会给我们打包程度不高(划分打包)的或者未打包的 es
文件,对的,就是我们常常说的 “按需加载” 。
如果恰好,你引入的某个组件,使用了高级语法(现在一般都使用了),并且,你项目中 src
下,也就是你写的业务代码,没有使用到这些高级语法,那么 babel-polyfill
就不会添加相对应的垫片,导致 “无效”。
对于直接使用 vue-cli@3+
的 在 vue.config.js
中有一个 transpileDependencies
选项
transpileDependencies
Type: Array <string | RegExp>
Default: []
默认情况下 babel-loader 会忽略所有 node_modules 中的文件。如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来。
可以排除
对于 vue-cli@2
的,由于我没用过所以不太了解,但是观察文件目录,应该集成度不如 @3
高,可以参考下文 纯 webpack 解决方案。
对于 webpack
的,只需要在 babel-loader的配置中把 include
和 exclude
的设置中排除相应的 UI包即可。
VueCli@3的
transpileDependencies
,应该是对应生成了正则去改变webpack babel-loader 的include
和exclude
的配置,达到排除屏蔽。
我并没有发现,babel-loader 和相关的配置中,有关于显式转译的配置项。