关于webpack动态import的一点探索

简介: 关于webpack动态import的一点探索

640.jpg


写在前面


最近在搞一个通过配置生成页面的项目,遇到了这样一个问题


for (let i = 0, len = pageData.selectSection.length; i < len; i++) {    const sectionName = pageData.selectSection[i].section_name;    import(`./template/${pageData.template_name}/${sectionName}/index`).then(item => {      const module = item.default;      ...    });  }


我需要读取后台下发的配置文件,然后去动态import对应的组件。最终使用webpack打包后,每一个组件都会产出一个chunk。那么问题来了,我的组件引用路径是在运行时才能确定的,webpack是怎么在本地静态打包的时候,就找到我的组件的呢?


webpack的动态引用


查看webpack的文档,有以下的描述:


完全动态的语句(如import(foo)),因为 webpack 至少需要一些文件的路径信息,而foo可能是系统或项目中任何文件的任何路径,因此foo将会解析失败。import()必须至少包含模块位于何处的路径信息,所以打包应当限制在一个指定目录或一组文件中。



调用import()时,包含在其中的动态表达式 request,会潜在的请求的每个模块。例如,import(./locale/${language}.json)会导致./locale目录下的每个.json文件,都被打包到新的 chunk 中。在运行时,当计算出变量language时,任何文件(如english.jsongerman.json)都可能会被用到。


从文档可以看出,动态import,是会根据代码里面的给出的路径信息去查找文件的,并且会将所有满足这个路径信息的文件都打成一个chunk,以备后续使用。

对于运行时才能确定的路径,webpack到底是怎么处理的呢?


6c1061f5926382561e7c9611fb0506a9.jpg

以上是在webpack打包过程中的一个对象。

可以看到,webpack其实是把

./template/${pageData.template_name}/${sectionName}/index

这个路径中的变量直接全部忽略了,直接使用了一个正则/^\.\/.*\/index$/request字段来表示最终的资源路径。

这个正则是怎么生成的呢?

在webpack源码的ContextDependencyHelpers.js里面,有下面的代码:


// ContextDependencyHelpers.js
...let prefixRaw =  param.prefix && param.prefix.isString() ? param.prefix.string : "";let postfixRaw =  param.postfix && param.postfix.isString() ? param.postfix.string : "";const valueRange = param.range;const { context, prefix } = splitContextFromPrefix(prefixRaw);const { postfix, query } = splitQueryFromPostfix(postfixRaw);
// 重点关注这行代码。拿到ast分析后的prefix和postfix,中间加上一个字符串,生成一个正则const regExp = new RegExp(  `^${quotemeta(prefix)}${options.wrappedContextRegExp.source}${quotemeta(    postfix  )}$`);
...


其中,wrappedContextRegExp这个字段的值,默认是被webpack写死的,就是一个正则表达式:


// WebpackOptionDefaulter.js
this.set("module.wrappedContextRegExp", /.*/);


webpack通过loader(babel)拿到js代码的AST后,会对AST进行分析,获取到动态import的路径参数后,进行上述处理,并且把本地满足上述正则的路径里面的文件全都拆出来,生成chunk。所以,为了避免打出无用的chunk,在使用动态import的时候,尽可能使用准确的静态路径,减少变量的影响范围。一般可以像下面这样使用:


import('./components/'+ ComponentName).then(module => { ... })


这里需要注意,在动态import的时候,路径不能只使用一个变量表示,这样的话,webpack没有办法找到对应的文件。


// 🚫下面代码是无效的const a = 'temp';import(a).then(module => {  console.log(module.default);});
// Critical dependency: the request of a dependency is an expression

写在后面


本文对webpack的动态import进行了一定的研究,对于webpack的动态import的策略有了进一步的认识,也为以后的使用扫除了一些坑,符合预期。

相关文章
|
7月前
|
前端开发
【专栏】`webpack` 的 `DefinePlugin` 插件用于在编译时动态定义全局变量,实现环境变量差异化、配置参数动态化和条件编译
【4月更文挑战第29天】`webpack` 的 `DefinePlugin` 插件用于在编译时动态定义全局变量,实现环境变量差异化、配置参数动态化和条件编译。通过配置键值对,如 `ENV: JSON.stringify(process.env.NODE_ENV)`,可以在代码中根据环境执行相应逻辑。实际应用包括动态加载资源、动态配置接口地址和条件编译优化代码。注意变量定义的合法性和避免覆盖,解决变量未定义或值错误的问题,以提升开发效率和项目质量。
358 3
|
JavaScript 前端开发
vue+webpack项目动态设置页面title的方法
vue+webpack项目动态设置页面title的方法
|
前端开发
webpack优化篇(五十):使用动态 Polyfill 服务
webpack优化篇(五十):使用动态 Polyfill 服务
352 0
webpack优化篇(五十):使用动态 Polyfill 服务
|
JavaScript
webpack进阶篇(二十三):代码分割和动态import
webpack进阶篇(二十三):代码分割和动态import
271 0
webpack进阶篇(二十三):代码分割和动态import
|
JavaScript API 索引
Webpack 4 动态切割JS注入文件名
昨天重新把我们公司的引流页做了二重封装,遇到一个问题。 webpack 切割的时候如何加个可以跟随文件名变化的前缀。
119 0
|
3月前
|
JavaScript
webpack打包TS
webpack打包TS
138 60
|
2月前
|
缓存 前端开发 JavaScript
Webpack 打包的基本原理
【10月更文挑战第5天】
|
2月前
|
前端开发 JavaScript
ES6模块化和webpack打包
【10月更文挑战第5天】
|
2月前
|
缓存 前端开发 JavaScript
深入了解Webpack:模块打包的革命
【10月更文挑战第11天】深入了解Webpack:模块打包的革命
|
3月前
|
JavaScript 测试技术 Windows
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)
本文介绍了如何使用vue-cli和webpack为Vue项目配置不同的生产和测试环境,包括修改`package.json`脚本、使用`cross-env`处理环境变量、创建不同环境的`.env`文件,并在`webpack.prod.conf.js`中使用`DefinePlugin`来应用这些环境变量。
175 2
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)