vite icon indicating copy to clipboard operation
vite copied to clipboard

Undefined imports in production build with shared components

Open cuiqui opened this issue 4 years ago • 10 comments
trafficstars

Describe the bug

When building for production, several pages import from FontAwesome (import { faXXX } from '@fortawesome/sub/faXXX.js'). Some of those imports are shared between a lot of components. These shared imports in dist/assets are seen, after running npm run build, as a separate chunk of the form faXXX.hash.js, apparently empty. Example from the repo to reproduce issue:

$ cat faPlusCircle.ef7d87a6.js
var faPlusCircle = {};
export { faPlusCircle as f };
//# sourceMappingURL=faPlusCircle.ef7d87a6.js.map

Which produces following error in some pages:

Uncaught (in promise) TypeError: Cannot read property 'icon' of undefined
    at Object.$$self.$$.update (FaIcon.svelte:8)
    at init$1 (index.mjs:1671)
    at new FaIcon (FaIcon.svelte:12)
    at create_fragment (two.e78d4eea.js:8)
    at init$1 (index.mjs:1675)
    at new Two (two.svelte:8)
    at Array.create_default_slot (Route.svelte:114)
    at create_slot (index.mjs:61)
    at create_fragment$3 (index.js:174)
    at init$1 (index.mjs:1675)

Pages in which it does not result in error are those that concatenated the import code in its chunk as such:

import { f as faMinusCircle } from "./faMinusCircle.3d152943.js";
import { F as FaIcon } from "./FaIcon.2537ee2b.js";
(function(exports) {
  Object.defineProperty(exports, "__esModule", { value: true });
  var prefix = "fas";
  var iconName = "minus-circle";
  var width = 512;
  var height = 512;
  var ligatures = [];
  var unicode = "f056";
  var svgPathData = "M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zM124 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H124z";
  exports.definition = {
    prefix,
    iconName,
    icon: [
      width,
      height,
      ligatures,
      unicode,
      svgPathData
    ]
  };
  exports.faMinusCircle = exports.definition;
  exports.prefix = prefix;
  exports.iconName = iconName;
  exports.width = width;
  exports.height = height;
  exports.ligatures = ligatures;
  exports.unicode = unicode;
  exports.svgPathData = svgPathData;
})(faMinusCircle);

More information: https://github.com/cuiqui/vite-issue-repo#weird-bundling

Reproduction

https://github.com/cuiqui/vite-issue-repo

System Info

System:
    OS: Linux 4.15 Ubuntu 18.04.5 LTS (Bionic Beaver)
    CPU: (4) x64 Intel(R) Core(TM) i5-4300M CPU @ 2.60GHz
    Memory: 160.38 MB / 11.43 GB
    Container: Yes
    Shell: 4.4.20 - /bin/bash
  Binaries:
    Node: 14.16.0 - /usr/bin/node
    npm: 6.14.11 - /usr/bin/npm
  Browsers:
    Chrome: 89.0.4389.114
    Firefox: 87.0
  npmPackages:
    vite: ^2.3.8 => 2.3.8

Used Package Manager

npm

Logs

No response

Validations

  • [X] Follow our Code of Conduct
  • [X] Read the Contributing Guidelines.
  • [X] Read the docs.
  • [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
  • [X] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to https://github.com/vuejs/vue-next instead.
  • [X] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.

cuiqui avatar Jul 02 '21 16:07 cuiqui

As a workaround to this issue, you can use

  import { faMinusCircle } from "@fortawesome/free-solid-svg-icons";
  import { faPlusCircle } from "@fortawesome/free-solid-svg-icons";

instead of

  import { faMinusCircle } from "@fortawesome/free-solid-svg-icons/faMinusCircle";
  import { faPlusCircle } from "@fortawesome/free-solid-svg-icons/faPlusCircle";

patak-dev avatar Aug 01 '21 21:08 patak-dev

@cuiqui it would be useful that you try to create a reproduction only using vanilla, so it is easier for others to check out.

patak-dev avatar Aug 01 '21 22:08 patak-dev

Thanks for the reply @patak-js, I ended up building the icon library instead of importing an icon in each component:

import { library } from "@fortawesome/fontawesome-svg-core";
import { faMinusCircle, faPlusCircle } from "@fortawesome/free-solid-svg-icons";

library.add(faMinusCircle, faPlusCircle);

Which in essence is your workaround. I'll try to make some time to create a vanilla reproduction, but I'm sorry I can't promise anything right now.

cuiqui avatar Aug 09 '21 19:08 cuiqui

This still seems to happen in Vite 2.8.6

bluwy avatar Mar 12 '22 15:03 bluwy

Hi ✋🏻 I have a the same problem.

import { DeviceUUID } from 'device-uuid'

DeviceUUID is undefined for after build. How can i solve this issue?

edisdev avatar Apr 12 '22 06:04 edisdev

Also facing the same problem with vite 3.0.9. Trying to import a class with static members from a private shared package, import is undefined in production build.

pietrofxq avatar Sep 01 '22 20:09 pietrofxq

I have code similar to this:

import {Session} from '@company/helpers'

export const mockUser = () => {
  Session.createEmptySession()
}

Session class:

export class Session {
  static createEmptySession() {
     //...
  }
}

I found a weird workaround: adding console.log(Session) in the file fixes it. So it looks like a tree shaking problem

pietrofxq avatar Sep 01 '22 21:09 pietrofxq

Facing this problem with Shopify Polaris library and Vite.

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

import { Provider } from '@shopify/app-bridge-react';

Provider component gets undefined in the production build.

awebartisan avatar Nov 11 '22 11:11 awebartisan

same issue with import { SelfieSegmentation, Results } from '@mediapipe/selfie_segmentation'; after build it's undefined, on dev server it's working perfectly fine

EDIT: here is reproduction code https://github.com/zbigniewstefaniuk/vite-lib-on-build-resolving-issue I've just scaffolded new project using yarn create vite with vue + typescirpt template, only installed this package @mediapipe/selfie_segmentation' and on dev server it's working however, prod import is undefined. Values are printed to the console as well as printed to the screen in <template />

zbigniewstefaniuk avatar Nov 23 '22 19:11 zbigniewstefaniuk

i am facing same issue while having 2 entries, both have imported faMultiply from @fortawesome/free-solid-svg-icons/faMultiply somewhere,

i read the compiled code and found something interesting, 3 js files generated ex: entry1.js, entry2.js, shared.js

the actual declaration of faMultiply is in the shared.js since both entry refer to it, how ever the actual definitions of faMultiply is only exists in entry2.js, so when entry1.js is loaded, the actual definitions of faMultiply will not be there.

i cant provide the actual code since it is a closed source project, but the below code is roughly how the compiled code will looks like

// shared.js
var faMultiply = {};
export { faMultiply };
// entry1.js
import { faMultiply } from "./shared.js";
console.log(faMultiply.faMultiply); // <= undefiend since faMultiply is just empty object in shared.js
// entry2.js
import { faMultiply } from "./shared.js";
(function(exports){
   /* actual definition is here */
})(faMultiply);
console.log(faMultiply.faMultiply); // <= the definitions of the icon is logged properly

the actual definitions is not compiled into the shared library, i hope this info is useful and i will try to see whether i can replicate it in a clean vanilla vite project or not when i am free

eslym avatar Feb 01 '23 20:02 eslym

Maybe you can use vite-plugin-mediapipe:https://github.com/Spencer17x/arca/tree/main/packages/vite-plugin/vite-plugin-mediapipe

spencer17x avatar Jun 20 '23 15:06 spencer17x

I believe this is fixed as of v3.0.0-alpha5, or, secifically 909cf9c01bcd2561a00fcc6df1006b65eec0d47e from #8280. At least, a bisect using https://github.com/cuiqui/vite-issue-repo points to that commit.

I'm unable to reproduce any of the other examples as of either main or latest (4.5.0).

@zbigniewstefaniuk it seems that @mediapipe/selfie_segmentation is a commonjs module. The following seems to work as expected:

import selfieSegmentation from "@mediapipe/selfie_segmentation";
const { SelfieSegmentation, VERSION } = selfieSegmentation;

I'm not familiar enough with mediapipe to say whether or not there's a better way.

clarkf avatar Oct 24 '23 17:10 clarkf

Thanks for triaging this. Yeah I can also see that it's fixed now. I'll close this for now.

Regarding @mediapipe/selfie_segmentation, that's a separate issue which is tracked at https://github.com/vitejs/vite/issues/10612

bluwy avatar Oct 25 '23 06:10 bluwy