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

ERR_MODULE_NOT_FOUND : echarts\core only during SSG Build #201

Closed
snake-poison opened this issue Feb 22, 2022 · 29 comments
Closed

ERR_MODULE_NOT_FOUND : echarts\core only during SSG Build #201

snake-poison opened this issue Feb 22, 2022 · 29 comments

Comments

@snake-poison
Copy link

I'm having an issue integrating apache's echarts and vue-echarts specifically when building in SSG mode. Everything works under vite build and vite (dev mode) but ssg build fails. I'm pretty sure this is an issue with the echarts package format, but I don't know how to get this to work in my SSG build. Any hints or ideas would be appreciated!!

https://github.com/ecomfe/vue-echarts
https://github.com/apache/echarts

vite-ssg build

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '\node_modules\echarts\core' imported from \.vite-ssg-temp\main.mjs 
Did you mean to import echarts@5.3.0/node_modules/echarts/core.js?

If I try to add '.js' to the end of all the echarts imports the error changes to :

file:///C:/Users/***/.vite-ssg-temp/main.mjs:26
import { CanvasRenderer } from "echarts/renderers.js";
         ^^^^^^^^^^^^^^
SyntaxError: Named export 'CanvasRenderer' not found. The requested module 'echarts/renderers.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'echarts/renderers.js';
const { CanvasRenderer } = pkg;

other attempts at fixing this issue

  • ssgOptions: {format : 'cjs'}
  • wrapping the component in <client-only>

I have an SFC that looks like this and is being imported on a page:

<template>
  <v-chart class="chart" :option="option" />
</template>

<script>
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { PieChart } from "echarts/charts";
import {
  TitleComponent,
  TooltipComponent,
  LegendComponent
} from "echarts/components";
import VChart, { THEME_KEY } from "vue-echarts";
import { ref, defineComponent } from "vue";

use([
  CanvasRenderer,
  PieChart,
  TitleComponent,
  TooltipComponent,
  LegendComponent
]);

export default defineComponent({
  name: "HelloWorld",
  components: {
    VChart
  },
  provide: {
    [THEME_KEY]: "dark"
  },
  setup () {
    const option = ref({
      title: {
        text: "Traffic Sources",
        left: "center"
      },
      tooltip: {
        trigger: "item",
        formatter: "{a} <br/>{b} : {c} ({d}%)"
      },
      legend: {
        orient: "vertical",
        left: "left",
        data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"]
      },
      series: [
        {
          name: "Traffic Sources",
          type: "pie",
          radius: "55%",
          center: ["50%", "60%"],
          data: [
            { value: 335, name: "Direct" },
            { value: 310, name: "Email" },
            { value: 234, name: "Ad Networks" },
            { value: 135, name: "Video Ads" },
            { value: 1548, name: "Search Engines" }
          ],
          emphasis: {
            itemStyle: {
              shadowBlur: 10,
              shadowOffsetX: 0,
              shadowColor: "rgba(0, 0, 0, 0.5)"
            }
          }
        }
      ]
    });

    return { option };
  }
});
</script>

<style scoped>
.chart {
  height: 400px;
}
</style>

@snake-poison
Copy link
Author

@userquin
Copy link
Member

I've it working but we need to change a few dependencies:

imagen

@snake-poison
Copy link
Author

I've it working but we need to change a few dependencies:

imagen

Thanks for looking into this. Let me know if you could use any help testing anything.

@userquin
Copy link
Member

userquin commented Feb 23, 2022

@ElmoArmy these are the changes I made, you can see it here https://github.com/userquin/vitesse-apache-echarts using vitesse template (the changes on the dependencies should be done manually, not included on the repo):

  • package.json: add "type": "module"
  • vite.config.ts: changed the import for VueI18n and included some entries on optimizedDeps/include option
  • tsconfig.json: changed module to ESNext instead es2016
  • src/components/ChartComponent.vue using vue-echarts/dist/index.esm.js instead vue-echarts (maybe we need to also change the package.json of vue-echarts)
  • pnpm install: once dependencies installed you must modify the following dependencies (we can also apply something similar to echarts...):

node_modules/echarts

  • package.json: add "type": "module", add also exports entry before main entry, the file should be like this:
{
  "name": "echarts",
  "version": "5.3.0",
  "description": "Apache ECharts is a powerful, interactive charting and data visualization library for browser",
  "license": "Apache-2.0",
  "type": "module",
  "keywords": [
    "echarts",
    "data-visualization",
    "charts",
    "charting-library",
    "visualization",
    "apache",
    "data-viz",
    "canvas",
    "svg"
  ],
  "exports": {
    ".": {
      "require": "./dist/echarts.js",
      "import": "./dist/echarts.esm.js",
      "types": "./index.d.ts"
    },
    "./core": {
      "require": "./core.js",
      "import": "./core.js",
      "types": "./core.d.ts"
    },
    "./renderers": {
      "require": "./renderers.js",
      "import": "./renderers.js",
      "types": "./renderers.d.ts"
    },
    "./charts": {
      "require": "./charts.js",
      "import": "./charts.js",
      "types": "./charts.d.ts"
    },
    "./components": {
      "require": "./components.js",
      "import": "./components.js",
      "types": "./components.d.ts"
    }
  },
  "main": "dist/echarts.js",

node_modules/vue-echarts

  • package.json add "type": "module"
  • dist/index.esm.js: replace import { addListener, removeListener } from 'resize-detector'; with import { addListener, removeListener } from 'resize-detector/esm/index.js';

node_modules/resize-detector

  • package.json add "type": "module"

@userquin
Copy link
Member

userquin commented Feb 23, 2022

@ElmoArmy we need also modify this another dependency:

node_modules/zrender

  • package.json add "type": "module"

@userquin
Copy link
Member

@ElmoArmy the chart component can also be included without the dynamic import, the vue-echart seems to be working with SSR/SSG.

have you tried my repro?

@snake-poison
Copy link
Author

@ElmoArmy the chart component can also be included without the dynamic import, the vue-echart seems to be working with SSR/SSG.

have you tried my repro?

Just got back to my office. Pulling it now and I'll let you know how it goes.

@userquin
Copy link
Member

userquin commented Feb 23, 2022

@ElmoArmy pushed changes, also included vue-echarts esm version on the optimizeDeps.include entry, I had the cjs version: I'll try to modify also the vue-echarts to include some entries to allow use the esm version without importing it.

@userquin
Copy link
Member

included exports on vue-echarts + updated dependencies con chart component and optimizeDeps.include entry

@snake-poison
Copy link
Author

@userquin

Your repo works like a charm after making those changes. Thanks for your help in figuring this out.

In order to fix this for others, would suggest I just start issues in the echarts, vue-echarts, resize-detector, zrender packages?

@userquin
Copy link
Member

@ElmoArmy here a good explanation about esm/cjs and why using "type": "module" instead using cjs/mjs extensions on third party libraries: https://v3.nuxtjs.org/concepts/esm

@snake-poison
Copy link
Author

@ElmoArmy here a good explanation about esm/cjs and why using "type": "module" instead using cjs/mjs extensions on third party libraries: https://v3.nuxtjs.org/concepts/esm

Great resource. Thanks again for your help.

@userquin
Copy link
Member

userquin commented Mar 1, 2022

@ElmoArmy update both issues since you're suggesting to only support esm: the type module are to make it working on the repro I've provided and so I don't need to rename esm and cjs files.

You need to exclude type module on both issues, and include the required module renaming:

  • cjs version should have .cjs extension but not required, if changed then should also update the main entry
  • esm version should have .mjs extension, also module entry
  • the repo should review if it would be necessary to add more entries to the exports, since I don't know if they need to include more modules: for example, inkline repo changes to esm support include ./*

@snake-poison
Copy link
Author

@ElmoArmy update both issues since you're suggesting to only support esm: the type module are to make it working on the repro I've provided and so I don't need to rename esm and cjs files.

You need to exclude type module on both issues, and include the required module renaming:

  • cjs version should have .cjs extension but not required, if changed then should also update the main entry
  • esm version should have .mjs extension, also module entry
  • the repo should review if it would be necessary to add more entries to the exports, since I don't know if they need to include more modules: for example, inkline repo changes to esm support include ./*

Oh I completely misunderstood that until you just explained this. I will update those issues. Thank you for further explaining this.

@userquin
Copy link
Member

userquin commented Mar 1, 2022

@ElmoArmy

FYI: just read again the second point here https://v3.nuxtjs.org/concepts/esm#library-author-guide, I change all the dependencies on my repro and so I don't need to change the esm modules with js extension; maybe it can also be done using the corresponding esm module on the import on my repo instead changing the package.json's dependencies

@userquin
Copy link
Member

userquin commented Mar 1, 2022

@ElmoArmy one last thing, the repo should also check the sideEffects entry:

EDIT: echarts is using sideEffects but vue-echartsno.

@snake-poison
Copy link
Author

@ElmoArmy

FYI: just read again the second point here https://v3.nuxtjs.org/concepts/esm#library-author-guide, I change all the dependencies on my repro and so I don't need to change the esm modules with js extension; maybe it can also be done using the corresponding esm module on the import on my repo instead changing the package.json's dependencies

So I just attempted to implement this in the PR for the vue-echarts ecomfe/vue-echarts#602

Seem right to you?

@ElmoArmy one last thing, the repo should also check the sideEffects entry:

EDIT: echarts is using sideEffects but vue-echartsno.

In regards to this comment, how would I evaluate whether or not this library ( or any library for that matter) should use sideEffects: False or specificy sideffects to make further bundling more efficient?

@userquin
Copy link
Member

userquin commented Mar 1, 2022

@ElmoArmy

  • you should add also the exports entry to the package.json
  • the library author should know the sideEffects, from outside you should read the entire codebase to figure it out

@userquin
Copy link
Member

userquin commented Mar 2, 2022

@ElmoArmy you should start fixing deps is reverse order, starting with zrender and resize-detector, then echarts and finally vue-echarts

@snake-poison
Copy link
Author

snake-poison commented Mar 2, 2022

@ElmoArmy

  • you should add also the exports entry to the package.json
  • the library author should know the sideEffects, from outside you should read the entire codebase to figure it out

Ok, I'll look for those. I think I see an example of at least one in the vue-charts library (an imported css file) that should be included. I also did some reading around the issue and I think I understand this optimization a bit more clearly. Thanks.

@ElmoArmy you should start fixing deps is reverse order, starting with zrender and resize-detector, then echarts and finally vue-echarts

Yea, this a great tip. Thanks.

One last thing:

Let's say I wanted to update a repo that depends on these libs with a workaround while changes make it upstream. Some options I'd consider would be :

  • Disable SSG for now. Not a big deal in my case, but obviously not ideal.
  • Fork and publish the repos. Takes a little time, but is pretty hacky and unmaintainable.
  • A post install script to patch the deps locally and on CI. I would think that this would be very hacky and likely to break, but I've got enough to go on from this thread to implement this.
  • Mess around with resolve aliases and/or a vite/rollup plugin. The issue you posted related to three.js gave me this idea as some handled an issue that way in this repo yushijinhun/three-minifier.

Any opinions on a preferable solution for a consumer that wants to sidestep mjs vs cjs issues in a less manual way than modifying the deps on install?

@userquin
Copy link
Member

userquin commented Mar 2, 2022

@ElmoArmy please send me an email here userquin@gmail.com, and if you have Discord account send me also your nick.

@snake-poison
Copy link
Author

@ElmoArmy please send me an email here userquin@gmail.com, and if you have Discord account send me also your nick.

Sent.

@userquin
Copy link
Member

userquin commented Mar 2, 2022

Sent.

no, check the address

@CyberNika
Copy link

is here something we can do to resolve this issue before echarts update it's package.json?

@userquin
Copy link
Member

@heynext create a patch script and apply it on postinstall script: see changes to apply #201 (comment)

@CyberNika
Copy link

@heynext create a patch script and apply it on postinstall script: see changes to apply #201 (comment)

thx. the changes work! i write a script to do the changes

import fs from 'fs'
import path from 'path'

const patchPkg = (name, data) => {
  const pkgPath = path.resolve('node_modules', name, 'package.json')

  const pkg = JSON.parse(fs.readFileSync(pkgPath))
  const patchedPkg = {
    ...pkg,
    ...data,
  }

  fs.writeFileSync(pkgPath, JSON.stringify(patchedPkg, null, 2))
}

patchPkg('echarts', {
  type: 'module',
  exports: {
    '.': {
      require: './dist/echarts.js',
      import: './dist/echarts.esm.js',
      types: './index.d.ts',
    },
    './core': {
      require: './core.js',
      import: './core.js',
      types: './core.d.ts',
    },
    './renderers': {
      require: './renderers.js',
      import: './renderers.js',
      types: './renderers.d.ts',
    },
    './charts': {
      require: './charts.js',
      import: './charts.js',
      types: './charts.d.ts',
    },
    './components': {
      require: './components.js',
      import: './components.js',
      types: './components.d.ts',
    },
  },
})

patchPkg('zrender', {
  type: 'module',
})


patchPkg('resize-detector', {
  type: 'module',
  exports: {
    '.': {
      require: './dist/index.js',
      import: './esm/index.js',
    },
  },
})

patchPkg('vue-echarts', {
  type: 'module',
  exports: {
    '.': {
      require: './dist/index.cjs.js',
      import: './dist/index.esm.js',
      types: './dist/index.d.ts',
    },
  },
})

@userquin
Copy link
Member

@heynext protect the patchPkg script function against multiple install, just check if the type is module and then omit the patch if already patched.

@Saganic
Copy link

Saganic commented Jul 24, 2022

Thanks @userquin, @heynext.
Just a note to whoever else comes across this, the changes to echarts may also require the ./features export.

Is there any non-public news about the offending packages?

patchPkg('echarts', {
  type: 'module',
  exports: {
    '.': {
      require: './dist/echarts.js',
      import: './dist/echarts.esm.js',
      types: './index.d.ts',
    },
    './core': {
      require: './core.js',
      import: './core.js',
      types: './core.d.ts',
    },
    './renderers': {
      require: './renderers.js',
      import: './renderers.js',
      types: './renderers.d.ts',
    },
    './charts': {
      require: './charts.js',
      import: './charts.js',
      types: './charts.d.ts',
    },
    './components': {
      require: './components.js',
      import: './components.js',
      types: './components.d.ts',
    },
    // here
    './features': {
      require: './features.js',
      import: './features.js',
      types: './features.d.ts',
    },
  },
})

@bigeye-boy
Copy link

bigeye-boy commented Jun 8, 2023

vite.config.json
defineConfig({ssr: { noExternal:['echarts', 'vue-echarts', 'resize-detector', 'zrender'] }})

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

No branches or pull requests

5 participants