本文主要讲述require.js在IDEA中路径智能感知的办法和探索中遇到的问题。
测试使用的目录结构:一种典型的thinkphp 6的目录结构,如下图。
现在我通过在 vue-a.js 中运用不同的方式引用 ../td/data.js 文件。其中,data.js 的内容如下:
define([], function () { let idx = 0; console.log('data.js') return 'data' + (++idx); });
方法1:使用相对路径
优点:
- 不用配置 require.config
缺点:
- 调用不同的模块的js时,路径文本长
- 在不同模块间调用时极易发生相对位置错误
方法2:使用require.config配置paths
require.config({ paths: { 'data': '../../../../public/static/admin/td/data', }, })
再在vue-a.js中使用paths中定义的短名进行引用。
define(['data'], function (data1, data2) { let vueTemplate = { data: function () { let data = { str: data1 + data2 }; return data; }, template: `<div>{{str}}</div>` }; return vueTemplate; });
优点:
- 名字短
缺点:
- 需要配置require.config
- 在输入时无法智能感知,如上图。
- 无法很友好的识别导出的对象,参见:https://www.cnblogs.com/zhongchengyi/p/12982228.html
方法3:使用绝对路径
使用绝对路径时需要注意,必须使用require.config配置根目录地址的别名(代码如下), 否则在运行时会找不到文件(如下图中的路径,最终require可能会去找文件:src/public/static/admin/src/public/static/admin/td/data.js)。
require.config({ paths: { 'src': '../../../..', }, })
优点:
- 不用纠结当前的路径在哪里。
- 配置相对少(只配置了根目录)
- 输入时完美智能感知
缺点:
- 需要配置require.config
- 路径文本长
特别注意:同一个文件不能混用引用方式
混用绝对路径和短名
此种混用绝对不能用,会导致严重后果。代码如下:
define(['src/public/static/admin/td/data', 'data'], function (data1, data2) { let vueTemplate = { data: function () { let data = { str: data1 + data2 }; return data; }, template: `<div>{{str}}</div>` }; return vueTemplate; });
后果:
- 界面无法正常显示
- require.js的代码报异常,无法进入 require后的代码。
- 无法加载短名代表的文件,一直卡住,直到超时(超时时间是 require.config中配置的waitSeconds)
混用相对路径和绝对路径、混用相对路径和短名
代码如下:
define(['../td/data', 'data'], function (data1, data2) { let vueTemplate = { data: function () { let data = { str: data1 + data2 }; return data; }, template: `<div>{{str}}</div>` }; return vueTemplate; });
define(['src/public/static/admin/td/data', '../td/data'], function (data1, data2) { let vueTemplate = { data: function () { let data = { str: data1 + data2 }; return data; }, template: `<div>{{str}}</div>` }; return vueTemplate; });
这两种混用方式都不会导致网页卡住,但是,会导致被引用的文件被调用两次。如图,控制台输出了两次 'data.js'。
调用两次有时会导致意想不到的问题。比如有些 js 会有事件注册的逻辑,被调用两次后,会导致事件被注册两次。后期会非常难定位。
我的最佳实践
- 模块内部的相互引用,可以直接用相对路径
- 模块间的引用,使用绝对路径
- 外部模块(三方库)使用短名
- 模块间尽量保持层级一致
PS:检查require的文件是否被调用两次
在 require.config 中配置 onNodeCreated 回调。
require.config({ paths: {}, shim: {}, onNodeCreated: function (node, config, moduleName, url) { if (!this.nodes) { this.nodes = {}; } if (!this.nodes[node.src]) { this.nodes[node.src] = {node, moduleName, url}; } else { console.warn('重复的模块,如下:'); console.log(this.nodes[node.src]); console.log({node, moduleName, url}); } }, });
效果,在控制台中输出重复的模块的信息。