zoukankan      html  css  js  c++  java
  • React原理探索- @providesModule 模块系统

    @providesModule是什么

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

    #ykit.config
    
    ...
    alias:{
    'Common':'./src/util/index.js',
    'Component':'src/components/index.js'
    }
    ...
    
    
    

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

    #a.js
    /**
    * @providesModule Common
    */
    
    export const isArray = () => {
    ...
    }
    
    export const isObject = () => {
    ...
    }
    
    #b.js
    
    import { isArray } from 'Common'
    
    isArray([])
    
    
    

    如何实现@providesModule

    fbjs-script/gulp:

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

    
    module.exports = {
    regexp: /
    ?
     * @providesModule (S+)(?=
    ?
    )/,
    };
    

    modules-map.js 中:

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

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

    
    
    function transform(file, enc, cb) {
    if (file.isNull()) {
    cb(null, file);
    return;
    }
    
    if (file.isStream()) {
    cb(new gutil.PluginError('module-map', 'Streaming not supported'));
    return;
    }
    
    // Get the @providesModule piece of out the file and save that.
    var matches = file.contents.toString().match(PM_REGEXP);
    if (matches) {
    var name = matches[1];
    if (moduleMap.hasOwnProperty(name)) {
    this.emit(
    'error',
    new gutil.PluginError(
    PLUGIN_NAME,
    'Duplicate module found: ' + name + ' at ' + file.path + ' and ' +
    moduleMap[name]
    )
    );
    }
    moduleMap[name] = file.path;
    }
    this.push(file);
    cb();
    }
    
    function flush(cb) {
    // Keep it ABC order for better diffing.
    var map = Object.keys(moduleMap).sort().reduce(function(prev, curr) {
    // Rewrite path here since we don't need the full path anymore.
    prev[curr] = prefix + path.basename(moduleMap[curr], '.js');
    return prev;
    }, {});
    fs.writeFile(moduleMapFile, JSON.stringify(map, null, 2), 'utf-8', function() {
    // avoid calling cb with fs.write callback data
    cb();
    });
    }
    
    

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

    
    {
    "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的声明一目了然,但是使用上也繁琐很多

  • 相关阅读:
    VS2005调试问题与解决方法集锦
    [转]在.net 2005中,将数据集序列化成二进制,提高远程传输效率
    DotNet 网上相关资源
    NeHE中文学习网址
    Aspx页上设置客户端的缓存时间
    动态调用Win32 Function(API)
    PB调用COM组件
    字段绑定的效率问题
    三维向量类
    用DataTable绑定TreeView的方法
  • 原文地址:https://www.cnblogs.com/natureless/p/8435037.html
Copyright © 2011-2022 走看看