如何使用 Babel 在 ES6 中编写与 CommonJS、AMD 和浏览器兼容的模块?

How do you author a module that is compatible with CommonJS, AMD and Browser in ES6 with Babel?

在普通的 ES5 中,如果我想编写一个可以在服务器端(通过 CJS、AMD、RequireJS)或浏览器使用的包,我会这样做:

(function(name, definition)){
   if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
       module.exports = definition();
   } else if (typeof define === 'function' && typeof define.amd === 'object') {
       define(definition);
   } else {
       this[name] = definition();
   }
}('foo', function foo(){
       'use strict';

        return 'foo';
})

在用 ES6 编写包时,我是如何实现这个功能的?

我尝试了什么:

if (typeof exports !== 'undefined' && typeof module !== 'undefined') export Foo;
else if (typeof define === 'function' && typeof define.amd === 'object') define(Foo);
else this['Foo'] = Foo;

在转译时,Babel 抛出一个错误:

SyntaxError: src/index.js: 'import' and 'export' may only appear at the top level (10:69)
   9 |
> 10 | if (typeof exports !== 'undefined' && typeof module !== 'undefined') export Foo;
     |                                                                      ^
  11 | else if (typeof define === 'function' && typeof define.amd === 'object') define(Foo);
  12 | else this['Foo'] = Foo;
  13 |

当我使用 module.exports 而不是 export 时确实有效,但是是否可以严格使用 ES6 来做到这一点?

所以没有真正的方法将 ES6 模块包含在通用模块定义中,因为 ES6 模块严格来说每个文件一个,所有导入和导出语句都必须位于顶层。

当加载器规范完成后,可能会有一种方法可以将模块添加到注册表中,这将是您将 ES6 模块包含在 UMD 中的方式,直到那时,因为没有浏览器真正支持 ES6 模块,您的唯一的目标是 AMD 和 CommonJS,但你应该使用许多编译器或 trnsspiler 之一,如 browserify 或 Babel 来为你做这件事。

您不会有一个通用输出,但 StealJS 可以将您的 Babel 转译 ES6 项目导出到 CommonJS、AMD 并作为一个独立项目。对于 CommonJS 和 AMD,您的原始模块结构将被保留,因此您仍然可以只加载您真正需要的依赖项。

project exporting 指南对其进行了更详细的解释,但在使用 NPM 工作流程时,这就是您的构建脚本的样子(如果包含,它还将构建 CSS/LESS/SASS 和其他依赖项):

{
    dist: {
        system: {
            config: "package.json!npm"
        },
        outputs: {
            "+cjs": {},
            "+amd": {},
            "+global-js": {},
            "+global-css": {}
        }
    }
}