vitejs / vite

Next generation frontend tooling. It's fast!
http://vite.dev
MIT License
69k stars 6.24k forks source link

Named import umd module returns null when the module uses the `export let` syntax #14353

Open anyesu opened 1 year ago

anyesu commented 1 year ago

Describe the bug

I used the vue-amap library in my project. I found that when I imported it using import { lazyAMapApiLoaderInstance } from 'vue-amap' , the value of lazyAMapApiLoaderInstance was always null instead of the latest value.

The source code of lazyAMapApiLoaderInstance uses the export let syntax to delay initialization:

let lazyAMapApiLoaderInstance = null;
import AMapAPILoader from './lazy-amap-api-loader';
import Vue from 'vue';
export const initAMapApiLoader = (config) => {
  if (Vue.prototype.$isServer) return;
  // if (lazyAMapApiLoaderInstance) throw new Error('You has already initial your lazyAMapApiLoaderInstance, just import it');
  if (lazyAMapApiLoaderInstance) return;
  if (!lazyAMapApiLoaderInstance) lazyAMapApiLoaderInstance = new AMapAPILoader(config);
  lazyAMapApiLoaderInstance.load();
};
export { lazyAMapApiLoaderInstance };

ref: https://stackoverflow.com/a/32558929

Reproduction

https://stackblitz.com/edit/vitejs-vite-tdtcgx?file=src%2Fmain.js

Steps to reproduce

pnpm i
# run with Vite
pnpm run dev
# run with Vue CLI
pnpm run dev:vue-cli

Use Vite and Vue CLI to start the project respectively. You can see from the log that the result in Vite is null , while the result in Vue CLI is the expected object .

vite-bug

Then build and run in production mode :

pnpm run build && pnpm run preview

pnpm run build:vue-cli && pnpm run preview

vite-bug

You can see that the behavior in production mode is the same as running in Vue CLI .

The source code after Vite transform is as follows:

import __vite__cjsImport0_vueAmap from "/node_modules/.vite/deps/vue-amap.js?v=7da0ea0b"; const initAMapApiLoader = __vite__cjsImport0_vueAmap["initAMapApiLoader"]; const lazyAMapApiLoaderInstance = __vite__cjsImport0_vueAmap["lazyAMapApiLoaderInstance"];
initAMapApiLoader();
console.log(
  process.env.VITE_APP ? 'vite' : 'vue-cli',
  lazyAMapApiLoaderInstance
);

However, the source code after Webpack transform is as follows:

__webpack_require__.r(__webpack_exports__);
/* harmony import */ var vue_amap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue-amap */ "./node_modules/.pnpm/vue-amap@0.5.10/node_modules/vue-amap/dist/index.js");
/* harmony import */ var vue_amap__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(vue_amap__WEBPACK_IMPORTED_MODULE_0__);

Object(vue_amap__WEBPACK_IMPORTED_MODULE_0__["initAMapApiLoader"])();
console.log(
  Object({"NODE_ENV":"development","BASE_URL":"/"}).VITE_APP ? 'vite' : 'vue-cli',
  vue_amap__WEBPACK_IMPORTED_MODULE_0__["lazyAMapApiLoaderInstance"]
);

The difference is that Webpack will convert lazyAMapApiLoaderInstance to vue_amap__WEBPACK_IMPORTED_MODULE_0__["lazyAMapApiLoaderInstance"] , while Vite simply defines a local variable to take the value, so console.log cannot read the latest value.

So I think the behavior of Vite should be consistent with Webpack, at least the development mode and production mode should be consistent in Vite.

There are two ways to solve this problem:

System Info

System:
    OS: Windows 10 10.0.19045
    CPU: (16) x64 11th Gen Intel(R) Core(TM) i7-11700 @ 2.50GHz
    Memory: 26.00 GB / 47.81 GB
  Binaries:
    Node: 16.20.2 - ~\AppData\Local\pnpm\node.EXE
    Yarn: 1.22.18 - D:\software\nodejs\node_global\yarn.CMD
    npm: 8.19.4 - ~\AppData\Local\pnpm\npm.CMD
    pnpm: 8.6.12 - ~\AppData\Local\pnpm\pnpm.EXE
  Browsers:
    Edge: Spartan (44.19041.1266.0), Chromium (116.0.1938.69)
    Internet Explorer: 11.0.19041.1566

Used Package Manager

pnpm

Logs

No response

Validations

stackblitz[bot] commented 1 year ago

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

bluwy commented 1 year ago

This is hard to fix. We're only rewriting to const initAMapApiLoader = __vite__cjsImport0_vueAmap["initAMapApiLoader"] because vue-amap does not export ESM, so we have to access the APIs through the default import after prebundling. Rewriting it for each referenced variables in code instead would be expensive, but not impossible since we're already doing it for SSR.

anyesu commented 1 year ago

Waiting for you to have a better solution to fix this. I'm currently using this workaround since this case is used less in my projects.

import * as VueAMap from 'vue-amap';
VueAMap.initAMapApiLoader();
console.log(VueAMap.lazyAMapApiLoaderInstance);