浏览器使用Commonjs加载UMD

浏览器使用Commonjs加载UMD

参考,一个简单的UMD实现,包含externals


(function(root, factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        console.log('是commonjs模块规范,nodejs环境')
        var depModule = require('./umd-module-depended')
        module.exports = factory(depModule);
    } else if (typeof define === 'function' && define.amd) {
        console.log('是AMD模块规范,如require.js')
        define(['depModule'], factory)
    } else if (typeof define === 'function' && define.cmd) {
        console.log('是CMD模块规范,如sea.js')
        define(function(require, exports, module) {
            var depModule = require('depModule')
            module.exports = factory(depModule)
        })
    } else {
        console.log('没有模块环境,直接挂载在全局对象上')
        root.umdModule = factory(root.depModule);
    }
}(this, function(depModule) {
    console.log('我调用了依赖模块', depModule)
    return {
        name: '我自己是一个umd模块'
    }
}))

开始

// 假设已经通过fetch拿到了js源代码
const jsStr = 'xxx';

// 构造 cmd default,babel在编译es6的时候会把模块挂在default下,所以要加一个default
const exports = {default: undefined};


// 构造module
const module = {exports};

// 构造reqire
const ModuleMapper = {
  react: 'React',
  'react-dom': 'ReactDOM',
  axios: 'Axios',
  redux: 'Redux',
};
const require = str => (window[ModuleMapper(str)]);

new Function('exports', 'require', 'module', jsStr)(exports, require, module);

// 拿到了module
module.exports.default

require函数是啥意思

require函数看起来很简单,首先把map如react的字符串,然后从window中取出并返回React Module;

假定react由CDN直接加载,那么它将可以通过window.React访问(实际上react也是由umd导出的)

webpack是这么处理externals依赖的:

function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory(require("react"), require("react-dom"));
	else if(typeof define === 'function' && define.amd)
		define("demo", ["react", "react-dom"], factory);
	else if(typeof exports === 'object')
		exports["demo"] = factory(require("react"), require("react-dom"));
	else
		root["demo"] = factory(root["React"], root["ReactDOM"]);
}

由于前面new Function传入了module,原本会走到

root["demo"] = factory(root["React"], root["ReactDOM"]);

但是现在会走到:

if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory(require("react"), require("react-dom"));

所以这里需要将require("react")转换成root["React"],root在浏览器环境即window