requirejs
是当前比较好的AMD规范的实现,所有的JS文件会被打包成一个js文件,减少请求数量,同时比较方便的实现了SPA的模式。但是随着项目的推进,SPA的首屏加载问题就会越来越明显。针对这个问题,webpack
在v1版本中通过require.ensure
,在v2版本中通过dynamic-imports来解决这个问题,不过实现最重要的就是在代码运行过程中动态加载其他的js文件(模块)。
在requirejs
的官方文档中,我们可以看到在模块中,也是可以随时使用require
来加载新的模块,如下
1 | require(["require", "alpha", "beta"], function(require, alpha, beta) { |
不过我们在上面的代码中看到了很常见的回调地狱的问题,同时也会有一些异常处理的问题,所以我们首先先使用promise
封装一下require
的文件加载
1 | /** |
上面有一段代码是path
的处理,主要是搭配require
来处理模块的路径:
1 | require.config({ baseUrl: 'js/', waitSeconds: 60}); |
我们再通过react来封装一个”模块加载器”:
1 | define([], () => class DynamicModuleLoader extends React.Component { |
接下来我们在代码中以如下方式使用即可
1 | define(['dynamic-module-loader'], (DynamicModuleLoader) => class PageHome extends React.Component { |
除了代码层面的修改,还需要针对构建工具做修改, 首先我们将需要动态加载的js文件加上.dynamic.js
的后缀,主要的问题在于,我们需要使用module1/index.dynamic.js
来加载,但是实际上,我们还需要考虑版本的问题,所以真实的加载文件的路径可能是module1/index-f37e86f666.dynamic.js
,所以需要考虑开发时的便利和生成环境的需求,这里我们使用了gulp
,:
1 | const gulp = require('gulp'); |
这里我们通过gulp-rev
来重命名模块,并且生成了manifest.json
。那我们只需要在上面function asyncModule()
中拿到manifest.json
,获取就可以查询得到真正的模块路径。
这里你可以通过ajax.get
来获取manifest.json
然后保存在全局变量。不过也可以通过gulp-repalce
,在构建的时候直接将整个json
插入到代码中,就不需要单独加载一个json
了。