使用CRACO对CRA项目使用CDN导入

不少React项目都是用官方的 creat-react-app(CRA)创建的,这样方便专注于React本身,而不用去配置webpack,babel等,但是项目开发到了后期的时候想要做一些自定义优化又很困难,如果需要手动更改配置,可能需要一些方法和工具,本文主要讨论使用CRACO使用CDN导入体积较大的包,以一个使用了百度地图的项目为例。

安装配置CRACO

CRA本身就是将 webpackbabel 等依赖配置完成封装起来后得到的一个工具,我们可以使用 eject 可以将这些依赖导出至 package.json ,同时也会得到这些依赖的配置文件,但是eject 本身是不可逆的,也就是说执行之后会删除CRA这个包,改变项目结构,之后的各种配置都需要自己维护,并不推荐。

Create React App Configuration Override(CRACO)可以重写CRA配置而不会改变项目结构,是目前比较主流的一种方法之一。

  1. 安装CRACO
1
npm i -D @craco/craco
  1. 在项目根目录创建CRACO配置文件 craco.config.js

默认的配置文件位置为项目根目录,默认文件名为 craco.config.js

1
module.exports = {} // 当前留空即可
  1. 更新 package.json 中的 scripts
1
2
3
4
5
6
7
8
"scripts": {
- "start": "react-scripts start"
+ "start": "craco start"
- "build": "react-scripts build"
+ "build": "craco build"
- "test": "react-scripts test"
+ "test": "craco test"
}

完成以上步骤就已经配置完成CRACO了,执行 npm run start 测试一下,没有问题就可以开始配置webpack和babel了

分析打包情况

首先我们需要知道打包的大致情况才能知道从哪里下手,使用 webpack-bundle-analyzer 可以展示打包后各个bundle对应的大小以及包含的依赖包。

  1. 安装 webpack-bundle-analyzer
1
npm i -D webpack-bundle-analyzer
  1. 更改 craco.config.js 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

module.exports = {
webpack: {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',
analyzerPort: 8848,
openAnalyzer: true, // 构建完打开浏览器
}),
],
},
}
  1. 执行 npm run build 即可查看打包情况

使用CDN前的打包分析

可以看到这里的mapvgl这个依赖占了很大的体积,对于大体积的包可以考虑使用cdn导入的方式。

使用CDN导入依赖包

对于大体积的包,我们可以采用CDN导入的方式,可以减小打包体积,使用 webpackexternals 可以实现。

防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些*扩展依赖(external dependencies)*。

  1. 找到对应包的CDN链接(注意版本)
  2. 找到包对应externals中的key和value

简单来说key就是引入时的包名,value就是js文件执行后赋值给window的全局变量名称。,比如jQuery是这样引入的

1
import $ from 'jquery';

查看 jquery 包,可以看到导出全局变量名称为jQuery

1
2
//...
export = jQuery;

所以 externals 这样写

1
2
3
externals: {
jquery: 'jQuery',
},

我们需要去寻找代码中导入包的方式,比如我当前要找出的包是mapvgl,查找依赖关系之后发现是react-bmapgl的依赖,所以我们需要去react-bmapgl这个包中找。

在layers这个包中可以看到

1
2
3
4
5
6
//...
// @ts-ignore
var mapvgl = tslib_1.__importStar(require("mapvgl"));
// @ts-ignore
var mapvglThree = tslib_1.__importStar(require("mapvgl/dist/mapvgl.threelayers.min"));
//...

所以我们找到了对应的key,与jQuery一样,我们点击查看 mapvgl 这个包,发现是未格式化的js代码,使用在线格式工具格式化后,我们主要关注最前面的这段代码,有关模块规范知识可以自行搜索。

1
2
(function(z, ja) {
"object" === typeof exports && "undefined" !== typeof module ? ja(exports) : "function" === typeof define && define.amd ? define(["exports"], ja) : (z = z || self, ja(z.mapvgl = {}))

大致可以猜出 z 是window,写入了一个名为 mapvgl 的包,所以value值为 mapvgl ,同理找出 "mapvgl/dist/mapvgl.threelayers.min" 的value值也为 mapvgl

  1. 更改 craco.config.js 配置,在 webpack 中添加 externals ,填入CDN网址和包对应的 key 和 value

我们这里将 externals 的默认类型指定为 script ,可以直接在 webpack 配置中写入CDN网址,而不需要在 html 文件中写入 scipt 标签来导入包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module.exports = {
webpack: {
//...
configure: (webpackConfig, { env, paths }) => {
webpackConfig.externalsType = 'script'
webpackConfig.externals = {
mapvgl: [
'https://cdn.jsdelivr.net/npm/mapvgl@1.0.0-beta.170/dist/mapvgl.min.js',
'mapvgl',
],
'mapvgl/dist/mapvgl.threelayers.min': [
'https://cdn.jsdelivr.net/npm/mapvgl@1.0.0-beta.170/dist/mapvgl.threelayers.min.js',
'mapvgl',
]
}
return webpackConfig
},
},
}
  1. 优化结果

执行 npm run start,百度地图正常使用。

百度地图运行情况

执行 npm run build,分析打包体积,去掉了两个很大的包,体积明显下降。

使用CDN前的打包分析

之后也有需要也可以对 antdreactreact-dom等比较大的几个包使用CDN导入,不过并不是导入越多越好,过多的script标签也会造成请求过多,造成网络卡顿,使用CDN导入主要是可以减小打包体积,降低服务器带宽压力。


使用CRACO对CRA项目使用CDN导入
http://example.com/2023/01/10/使用CRACO对CRA项目使用CDN导入/
作者
Sonce
发布于
2023年1月10日
许可协议