【问题标题】:Disadvantage of ES6 and CommonJS export conventionES6 和 CommonJS 导出约定的缺点
【发布时间】:2018-02-28 20:34:14
【问题描述】:

对于npm 模块的main 文件,由package.json 定义,我正在考虑这样的模式:

import Struct from './src/struct'

module.exports = Struct
module.exports.default = Struct

为了同时支持 CommonJS 和 ES6 导入:

const Struct = require('my-module')
// or
import Struct from 'my-module'

此约定是否有可能导致意外问题的缺点?

我试图解决的问题是不得不强迫包的消费者坚持使用 ES6 或 CommonJS,因为这两者似乎都令人讨厌:

const Struct = require('my-module').default
// or
import * as Struct from 'my-module'

在进一步考虑这一点后,像这样在/src/struct.js 中定义我的班级会更好吗?

export default class Struct {
  static get default () {
    return Struct
  }
  ...
}

【问题讨论】:

  • 这种情况下Struct是什么类型?一般来说,我建议避免将属性添加到未在同一文件中定义的对象上,但您可以根据实际情况来避免这种情况。此外,由于编译器通常会添加逻辑来自动使 CommonJS 模块与 import 一起工作,所以您特别想避免什么问题?
  • @loganfsmyth 好吧,Struct 只是一个具有我想打包为 npm 模块的功能的类,因此添加 default 静态属性似乎不是很有害。也许我应该使它不可枚举或避免意外枚举它?
  • 如果导入的模块是 CommonJS,Babel 将使用 module.exports 作为默认导出,所以我看不出 module.exports.default = Struct 有什么帮助。其他捆绑商不这样做吗?
  • @FelixKling 真的等吗?我以为 babel 在 v6 中停止这样做了
  • 我以为这是别的东西……我可能错了。你是说在这种情况下 Babel 只会导入 undefined 吗?我无法想象它确实如此。

标签: node.js import ecmascript-6 export commonjs


【解决方案1】:

default 导出在 Node.js 应用程序中不是很方便,因为

const Struct = require('my-module').default;
const { default: Struct } = require('my-module');

requires 比@s 更麻烦更难阅读

const Struct = require('my-module');

由于在当前 Babel、TypeScript(带有allowSyntheticDefaultImports 选项)和 Node 原生支持 ES 模块(.mjs 模块)中与 CommonJS 模块的互操作是如何工作的,建议导出如下函数:

module.exports = Struct

所以它可以被导入

import Struct from './src/struct';

在 ES 模块中,以及作为

const Struct = require('./src/struct');

在 CommonJS 模块中。

【讨论】:

  • 我知道这是一个旧线程,但我想知道您是否对此发表了评论。我最近读到一些实现将import * as Struct from 'my-module'; 更像const { ...Struct } = require('my-module'),它具有防止函数、构造函数和原语被导出为module 对象的效果。这是一个合理的担忧,还是只是迷信的编程?
  • @PatrickRoberts 您能否提供此声明的链接?我考虑到了 ES 模块实现的几个可能的问题,但不确定其中哪些可能是这里的问题。我希望 * 导入没有问题,它在实现中非常一致。
  • Here's one 请注意,在 commonjs 中如果你 module.exports = () => {} 而在 ES6 中你 import * as foo from '...' 那么 foo 是不可调用的。
  • @PatrickRoberts 我明白了,还检查了 Felix Kling 的答案,该答案是在我的之后发布的。我不记得为什么我会这样回答,可能是指早期的 Babel 版本。我想知道为什么没有人愿意否决这个答案。无论如何,如今情况有所不同,部分原因在于 Node 如何实现本机模块(AIK 它不像转译器那样关心 __esModule)。我更新了答案,以免混淆任何人。
【解决方案2】:

Lets look at what Babel does when you do import foo from 'bar';:

'use strict';

var _bar = require('bar');

var _bar2 = _interopRequireDefault(_bar);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

可以看到,根据导入模块的“类型”,Babel 要么导入default 导出,要么导入module.exports(因为require('bar') 返回module.exports

这意味着,为了让您的模块可以导入为

const Struct = require('my-module')
// and
import Struct from 'my-module'

你要做的就是

module.exports = Struct;

【讨论】:

    【解决方案3】:

    好吧,既然 nodejs 仍然没有对 ES6 模块的原生支持,那么现在它实际上只是代码可读性的问题。但是 IMO 不需要同时支持 CommonJS 和 ES6 模块。坚持一个。

    【讨论】:

    • 我意识到没有对 ES6 的原生支持,但这不是重点。消费者使用 babel、webpack、rollup、browserify 和其他捆绑服务的情况非常普遍,这些服务通过从未来规范中转换源代码来忽略本机支持的限制。我不想强迫使用这些配置的人使用我上面所说的尴尬 import * as Struct from 'my-module' 之一,因为这不是在 ES6 中使用 import 的一种非常传统或预期的方式。
    猜你喜欢
    • 2016-08-31
    • 2021-11-20
    • 2022-08-10
    • 2016-06-28
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    相关资源
    最近更新 更多