JS模块化 -- CMD

CMD usage

    // sea.js
    define('a', function(require, exports, module){
        console.log('a load');
        exports.run = function (){ console.log('a run') }
    })

    define('b', function(require, exports, module){
        console.log('b load');
        exports.run = function (){ console.log('b run') }
    })

    define('main', function(require, exports, module){
        console.log('main run');
        var a = require('a');
        a.run();
        var b = require('b');
        b.run();
    })

    seajs.use('main');

    // main run
    // a load
    // a run
    // b load
    // b run

seajs简单实现

const modules = {};
const exports = {};

const sj = {}

// 获取地址
// dep -> a -> a.js -> http:xxx/xx/xx/a.js
const __getUrl = (dep) => {
    const p = location.pathname;
    return p.slice(0, p.lastIndexOf('/')) + '/' + dep + 'js';
}

// normal script
const __load = (url) => {
    return new Promise((resolve, reject) => {
        const header = document.getElementsByTagName("header")[0];
        const script = document.createElement('script');
        script.async = true;
        script.src = url;
        script.type = 'text/javascript';
        script.onload = resolve;
        script.onerror = reject;
        header.appendChild(script);
    }) 
}

const __getDepsFromFn = (fn) => {
    let matches = [];
    // require('a')
    // (?:require\() -> require( (?:) 非捕获性分组
    // (?:['"]) -> require(' 
    // ([^'"]+) -> a  避免回溯 -> 回溯 状态机
    let reg = /(?:require\()(?:['"])([^'"]+)/g
    let r = null;
    while((r = reg.exec(fn.toString())) !== null){
        reg.lastIndex;
        matches.push(r[1])
    }
    return matches;
}

// 依赖呢?
// 提取依赖:1. 正则表达式 2. 状态机
const define = (id, factory) => {
    const url = __getUrl(id);
    const deps = __getDepsFromFn(factory);
    if(!modules[id]){
        modules[id] = {url, id, factory, deps};
    }
}

const __exports = (id) => exports[id] || (exports[id] = {});
const __module = this;
// 这里才是加载模块地方
// 这个写法是promise的  所以在 var a = require('a') 时 需要加 async/await 方式
const __require = (id) => {
    return __load(__getUrl(id)).then(() => {
        // 加载之后
        const {factory, deps} = modules[id];
        if(!deps || deps.length == 0){
            factory(__require, __exports(id), __module);
            return __exports(id);
        }
    })
}

sj.use = (mods, callback) => {
    mods = Array.isArray(mods) ? mods : [mods];
    return new Promise((resolve, reject) => {
        Promise.all(mods.map(mod =>{
            return __load(__getUrl(mod)).then(() => {
                // 加载之后
                const {factory} = modules[mod];
                factory(__require, __exports(mod), __module);
                return __exports(mod);
            })
        })).then(resolve, reject);
    }).then(instance => callback && callback(...instance));
}

你可能感兴趣的