React原理探索- @providesModule 模块系统

前端之家收集整理的这篇文章主要介绍了React原理探索- @providesModule 模块系统前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

React原理探索- @providesModule 模块系统

@providesModule是什么

react抛出组件化的概念后,对于开发者而言,为了提高代码的可读性与结构性,通过文件目录结构去阐述组件嵌套关系无疑是一个很好的办法,但是目录级别的加深,同时让require的文件路径让人头疼。绝大多数公司会使用自己定制的alias工具,在脚手架入口配置文件中给相应的filePath赋予别名,pack时,进行统一替换。

  1. #ykit.config
  2.  
  3. ...
  4. alias:{
  5. 'Common':'./src/util/index.js','Component':'src/components/index.js'
  6. }
  7. ...

当然也可以在文件中写入唯一的标识位,pack时将该标识位与当前声明标识位的filePath建立联系,facebook提供的@providesModule的就是这一策略。使用方法如下:

  1. #a.js
  2. /**
  3. * @providesModule Common
  4. */
  5.  
  6. export const isArray = () => {
  7. ...
  8. }
  9.  
  10. export const isObject = () => {
  11. ...
  12. }
  13.  
  14. #b.js
  15.  
  16. import { isArray } from 'Common'
  17.  
  18. isArray([])

如何实现@providesModule

fbjs-script/gulp:

shared/provides-module.js中提供了这样一段正则,用于匹配文件中是否有类似@providesModule的标识符

  1. module.exports = {
  2. regexp: /\r?\n \* \@providesModule (\S+)(?=\r?\n)/,};

modules-map.js 中:

transform函数调用如上正则对读入文本进行解析,并将alias的别名与filePath建立映射关系

flush函数将前面拿到的映射表进行处理加上统一前缀,并导入到json文件

  1. function transform(file,enc,cb) {
  2. if (file.isNull()) {
  3. cb(null,file);
  4. return;
  5. }
  6.  
  7. if (file.isStream()) {
  8. cb(new gutil.PluginError('module-map','Streaming not supported'));
  9. return;
  10. }
  11.  
  12. // Get the @providesModule piece of out the file and save that.
  13. var matches = file.contents.toString().match(PM_REGEXP);
  14. if (matches) {
  15. var name = matches[1];
  16. if (moduleMap.hasOwnProperty(name)) {
  17. this.emit(
  18. 'error',new gutil.PluginError(
  19. PLUGIN_NAME,'Duplicate module found: ' + name + ' at ' + file.path + ' and ' +
  20. moduleMap[name]
  21. )
  22. );
  23. }
  24. moduleMap[name] = file.path;
  25. }
  26. this.push(file);
  27. cb();
  28. }
  29. function flush(cb) {
  30. // Keep it ABC order for better diffing.
  31. var map = Object.keys(moduleMap).sort().reduce(function(prev,curr) {
  32. // Rewrite path here since we don't need the full path anymore.
  33. prev[curr] = prefix + path.basename(moduleMap[curr],'.js');
  34. return prev;
  35. },{});
  36. fs.writeFile(moduleMapFile,JSON.stringify(map,null,2),'utf-8',function() {
  37. // avoid calling cb with fs.write callback data
  38. cb();
  39. });
  40. }

最后导出如下json(以fbjs build为例)

  1. {
  2. "BrowserSupportCore": "fbjs/lib/BrowserSupportCore","CSscore": "fbjs/lib/CSscore","CircularBuffer": "fbjs/lib/CircularBuffer","DOMMouseMoveTracker": "fbjs/lib/DOMMouseMoveTracker","DataTransfer": "fbjs/lib/DataTransfer","Deferred": "fbjs/lib/Deferred","ErrorUtils": "fbjs/lib/ErrorUtils","EventListener": "fbjs/lib/EventListener","ExecutionEnvironment": "fbjs/lib/ExecutionEnvironment","Heap": "fbjs/lib/Heap","IntegerBufferSet": "fbjs/lib/IntegerBufferSet","Keys": "fbjs/lib/Keys","Locale": "fbjs/lib/Locale","Map": "fbjs/lib/Map","PhotosMimeType": "fbjs/lib/PhotosMimeType","PrefixIntervalTree": "fbjs/lib/PrefixIntervalTree","Promise": "fbjs/lib/Promise","PromiseMap": "fbjs/lib/PromiseMap",}

而后该做什么大家也清楚了,要么node脚本去把文件里require 对应别名的进行路径替换,要么通过babel替换,当然,facebook是通过babel玩的

题外话

其实对于alias system目前提供的两种方法,各有利弊。fb提供的方法,使得使用上更加便利,但是由于alias遍地存在,声明冲突也变得家常便饭(当然可以通过统一前缀解决)。传统在脚手架配置文件中声明的方法,虽然能让你对alias的声明一目了然,但是使用上也繁琐很多

猜你在找的React相关文章