Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

without __esModule property when format esm module cause load module error #1323

Closed
zhangyuang opened this issue May 27, 2021 · 13 comments · Fixed by #1338
Closed

without __esModule property when format esm module cause load module error #1323

zhangyuang opened this issue May 27, 2021 · 13 comments · Fixed by #1338

Comments

@zhangyuang
Copy link

from vite issue i think it's esbuild problem

Describe the bug

when the thirdparty module is esm format, esbuild manage it without add __esModule property. but webpack will add __esModule property.

for examle, the source code is

// swiper.esm.js
export { default as Swiper, default } from './esm/components/core/core-class';
export { default as Virtual } from './esm/components/virtual/virtual';
//...

After esbuild format ,will output

import {default as default2, default as default3} from "./esm/components/core/core-class";
import {default as default4} from "./esm/components/virtual/virtual";
export {
  default14 as A11y,
  default3 as default
};

without __esModule property.

it will be cause an error. if a module build by webpack, the source code as below

//  react-id-swiper sourceCode
import Swiper from 'swiper';
new Swiper()

after webpack build , output code will add helper function __importDefault

// react-id-swiper
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var swiper_1 = __importDefault(require("swiper"));
new swiper_1.default(swiperNodeRef.current, object_assign_1.default({}, props))

but because of __esModule is undefined, __importDefault function will add default property once again cause the return value __importDefault(require("swiper")).default is not the current object will be error

image
image

Reproduction

https://github.com/zhangyuang/vite-react-swiper-error

System Info

vite/2.3.2 darwin-x64 node-v12.18.3

additional

when i add __esModule property in source code manually, it can be executed succeed like

export { default as Swiper, default } from './esm/components/core/core-class';
export { default as Virtual } from './esm/components/virtual/virtual';
export const __esModule = true 

In this case,maybe vite can add __esModule in esbuild plugin . for example

build.onLoad({ filter: /.*/, namespace: 'swiper' }, ({ path: id }) => {
        return {
          loader: 'js',
          resolveDir: root,
          contents: `export * from "filepath"
          export {default} from "filePath"
          export const __esModule = true 
          `
        }
      })
@dravenww
Copy link

I am also experiencing the same problem

@Rainmen-xia
Copy link

Looking forward esbuild to solving this problem。

@daniel100097
Copy link

Any workaround ?

@lbwa
Copy link
Contributor

lbwa commented May 31, 2021

Maybe this isn't esbuild bug. No matter TypeScript compiler or babel compiler, any esm output wouldn't create __esModule flag in JS community practices. __esModule is a part of commonjs product, not esm product.

In your above code, esbuild output esm product, so it didn't included __esModule flag.

@zhangyuang
Copy link
Author

zhangyuang commented May 31, 2021

Babel and tsc will generate __esModule from esm to commonjs tell bundler tools which is an esm module。
Most of bundler tools will add _interopRequireDefault methods to load this obj。

function _interopRequireDefault(obj) {
  // 判断传入的对象是 ESModule 还是 CommonJS 模块
  return obj && obj.__esModule  // 这里就是之前说的为什么要加上 `__esModule` 属性
    ? obj                       // 如果是 ESModule,就直接返回传入的模块对象
    : { 'default': obj };       // 如果不是 ESModule,则将传入的 `module.exports` 放置在一个新对象 `default` 上,来模拟 ESModule
}

It cause an error, after vite use esbuild optimize vue@2.0 will output below code

 var _vue = (init_vue_runtime_esm(), vue_runtime_esm_exports);
    var _vue2 = _interopRequireDefault(_vue);
    function _interopRequireDefault(obj) {
      return obj && obj.__esModule ? obj : {default: obj};
    }

image

@lbwa
Copy link
Contributor

lbwa commented May 31, 2021

@zhangyuang
image

I said output syntax is es module, __esModule should be in commonjs product, not es module product. Your product is esm product, not commonjs. So __esModule isn't in it.

_interopRequireDefault only work with commonjs syntax js file, not esm file

Only file which is commonjs syntax should has a __esModule flag:

exports.default = function foo() {}

exports.__esModule = true

@lbwa
Copy link
Contributor

lbwa commented May 31, 2021

Babel and tsc will generate __esModule from esm to commonjs tell bundler tools which is an esm module。
Most of bundler tools will add _interopRequireDefault methods to load this obj。

function _interopRequireDefault(obj) {
  // 判断传入的对象是 ESModule 还是 CommonJS 模块
  return obj && obj.__esModule  // 这里就是之前说的为什么要加上 `__esModule` 属性
    ? obj                       // 如果是 ESModule,就直接返回传入的模块对象
    : { 'default': obj };       // 如果不是 ESModule,则将传入的 `module.exports` 放置在一个新对象 `default` 上,来模拟 ESModule
}

It cause an error, after vite use esbuild optimize vue@2.0 will output below code

 var _vue = (init_vue_runtime_esm(), vue_runtime_esm_exports);
    var _vue2 = _interopRequireDefault(_vue);
    function _interopRequireDefault(obj) {
      return obj && obj.__esModule ? obj : {default: obj};
    }

image

Those output codes have __esModule because they are commonjs syntax, not esm.

@zhangyuang
Copy link
Author

__esModule generated for compatible cjs and esm。In fact, in esbuild@0.9.7 will generate __esModule property
With esbuild@0.9.7 format vue2.0 to esm will output below code which is true.

var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});

var require_vue_runtime_esm = __commonJS((exports) => {
  __markAsModule(exports);
  __export(exports, {
    default: () => vue_runtime_esm_default
  });

@lbwa
Copy link
Contributor

lbwa commented May 31, 2021

  1. I know what __esModule and _interopRequireDefault done.
  2. We have a misunderstanding between you and me. I said your js product format is esm syntax, so it never has __esModule flag, unless commonjs synatx.

I have used the latest version esbuild(v0.12.5). It works very well if output format is cjs and esm, and it has an expected behavior you want.

~/codes/demo ❱❱❱ ls
a.js         index.js     node_modules package.json yarn.lock
[15:33:18] [cost 0.212s] ls                                                                                                       

~/codes/demo ❱❱❱ cat a.js                          
export default function a () {}
[cost 0.182s] cat a.js                                                                                                 

~/codes/demo ❱❱❱ yarn esbuild index.js --format=esm
yarn run v1.22.10
warning package.json: No license field
$ /xxxxxx/xxxxxx/codes/demo/node_modules/.bin/esbuild index.js --format=esm
import a from "./a.js";
a();
✨  Done in 0.10s.
[cost 0.488s] yarn esbuild index.js --format=esm                                                                       

~/codes/demo ❱❱❱ yarn esbuild index.js --format=cjs
yarn run v1.22.10
warning package.json: No license field
$ /xxxxx/xxxxxx/codes/demo/node_modules/.bin/esbuild index.js --format=cjs
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
+ var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __reExport = (target, module2, desc) => {
  if (module2 && typeof module2 === "object" || typeof module2 === "function") {
    for (let key of __getOwnPropNames(module2))
      if (!__hasOwnProp.call(target, key) && key !== "default")
        __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
  }
  return target;
};
var __toModule = (module2) => {
  return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
};
var import_a = __toModule(require("./a.js"));
(0, import_a.default)();
✨  Done in 0.07s.
[cost 0.437s] yarn esbuild index.js --format=cjs                                                                       

~/codes/demo ❱❱❱ yarn esbuild --version            
yarn run v1.22.10
warning package.json: No license field
$ /Users/xxxxxx/codes/demo/node_modules/.bin/esbuild --version
0.12.5
✨  Done in 0.10s.
[cost 0.504s] yarn esbuild --version    

@zhangyuang
Copy link
Author

-.- yes, i know __esModule only be generated in commonjs module in the persent.

here is the issue repo
when lock vite version in 2.2.4 which use esbuild version 0.9.7 can output the true code in node_modules/.vite directory

@zhangyuang
Copy link
Author

@lbwa see #1333

@haoqunjiang
Copy link

FYI, the __importDefault helper is from TypeScript.

@dravenww
Copy link

dravenww commented Jun 1, 2021

demo:https://github.com/tnfe/vite-vue2-pro
use vite and esbuild-plugin-vite-element-ui is running ok.

lbwa added a commit to lbwa/esbuild that referenced this issue Jun 1, 2021
fix evanw#1333 evanw#1323

Signed-off-by: Liu Bowen <mr_lbw@outlook.com>
lbwa added a commit to lbwa/esbuild that referenced this issue Jun 1, 2021
fix evanw#1333 evanw#1323

Signed-off-by: Liu Bowen <mr_lbw@outlook.com>
lbwa added a commit to lbwa/esbuild that referenced this issue Jun 1, 2021
fix evanw#1333 evanw#1323

Signed-off-by: Liu Bowen <mr_lbw@outlook.com>
lbwa added a commit to lbwa/esbuild that referenced this issue Jun 1, 2021
fix evanw#1333 evanw#1323

Signed-off-by: Liu Bowen <mr_lbw@outlook.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants