ElMassimo / iles

🏝 The joyful site generator
https://iles.pages.dev
MIT License
1.06k stars 31 forks source link

Issue resolving esm export in vite plugin during build #241

Closed JonathanLorimer closed 1 year ago

JonathanLorimer commented 1 year ago

Description πŸ“–

pnpm build does not work with vite-plugin-svg-sprite.

Reproduction 🐞

Repro repo

I just did a simple pnpm create iles@next and added the vite-plugin-svg-sprite dep.

Note that I needed to add shamefully-hoist to the .npmrc in order for iles to find "vue/server-renderer", otherwise I get this error:

vite]: Rollup failed to resolve import "vue/server-renderer" from "src/pages/about.vue".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
βœ– building client + server bundles
build error:
 Error: [vite]: Rollup failed to resolve import "vue/server-renderer" from "src/pages/about.vue".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
    at onRollupWarning (file:///home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/node_modules/.pnpm/vite@3.2.5/node_modules/vite/dist/node/chunks/dep-5605cfa4.js:45832:19)
    at onwarn (file:///home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/node_modules/.pnpm/vite@3.2.5/node_modules/vite/dist/node/chunks/dep-5605cfa4.js:45603:13)
    at Object.onwarn (file:///home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/node_modules/.pnpm/rollup@2.79.1/node_modules/rollup/dist/es/shared/rollup.js:23263:13)
    at ModuleLoader.handleResolveId (file:///home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/node_modules/.pnpm/rollup@2.79.1/node_modules/rollup/dist/es/shared/rollup.js:22158:26)

You can reproduce by cloning the repo and running pnpm build

Dependencies Info ``` Ξ» pnpm list Legend: production dependency, optional only, dev only iles-app@0.0.0 /home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro devDependencies: iles 0.8.7 typescript 4.9.5 vite-plugin-svg-sprite 0.3.1 vue-tsc 0.38.9 Ξ» pnpm iles:info > iles-app@0.0.0 iles:info /home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro > iles info iles v0.8.7 vite v3.2.5 ```

Logs πŸ“œ

If not providing a reproduction:

Output ``` > iles-app@0.0.0 build /home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro > iles build iles v0.8.7 vite v3.2.5 iles:config loaded config at /home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/iles.config.ts +0ms iles:config { iles:config root: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro', iles:config modules: [ iles:config { iles:config name: 'iles:base-config', iles:config debug: true, iles:config drafts: false, iles:config turbo: false, iles:config jsx: undefined, iles:config root: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro', iles:config base: '/', iles:config siteUrl: '', iles:config prettyUrls: true, iles:config ssg: [Object], iles:config configPath: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/iles.config.ts', iles:config assetsDir: 'assets', iles:config pagesDir: 'pages', iles:config srcDir: 'src', iles:config outDir: 'dist', iles:config layoutsDir: 'layouts', iles:config tempDir: '.iles-ssg-temp', iles:config modules: [], iles:config namedPlugins: [Object], iles:config resolvePath: undefined, iles:config vitePlugins: [Array], iles:config vite: [Object], iles:config vue: [Object], iles:config extendFrontmatter: [AsyncFunction: extendFrontmatter], iles:config extendRoute: [Function: extendRoute], iles:config extendRoutes: [Function: extendRoutes], iles:config markdown: [Object], iles:config components: [Object] iles:config }, iles:config { iles:config name: '@islands/mdx', iles:config markdown: [Object], iles:config configResolved: [Function: configResolved] iles:config }, iles:config { iles:config name: 'user-config', iles:config vite: [Object], iles:config configPath: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/iles.config.ts' iles:config }, iles:config { iles:config name: '@islands/pages', iles:config configResolved: [Function: configResolved] iles:config } iles:config ], iles:config debug: true, iles:config drafts: false, iles:config turbo: false, iles:config base: '/', iles:config siteUrl: '', iles:config prettyUrls: true, iles:config ssg: { sitemap: true }, iles:config configPath: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/iles.config.ts', iles:config assetsDir: 'assets', iles:config pagesDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/src/pages', iles:config srcDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/src', iles:config outDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/dist', iles:config layoutsDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/src/layouts', iles:config tempDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/.iles-ssg-temp', iles:config namedPlugins: { iles:config components: { iles:config name: 'unplugin-vue-components', iles:config enforce: 'post', iles:config api: [Object], iles:config transformInclude: [Function: transformInclude], iles:config transform: [Function (anonymous)], iles:config vite: [Object], iles:config webpack: [Function: webpack], iles:config configResolved: [Function: configResolved], iles:config configureServer: [Function: configureServer] iles:config }, iles:config vue: { iles:config name: 'vite:vue', iles:config handleHotUpdate: [Function: handleHotUpdate], iles:config config: [Function: config], iles:config configResolved: [Function: configResolved], iles:config configureServer: [Function: configureServer], iles:config buildStart: [Function: buildStart], iles:config resolveId: [AsyncFunction: resolveId], iles:config load: [Function: load], iles:config transform: [Function: transform] iles:config }, iles:config pages: { iles:config name: 'iles:pages', iles:config enforce: 'pre', iles:config api: [Getter], iles:config configResolved: [AsyncFunction: configResolved], iles:config configureServer: [AsyncFunction: configureServer], iles:config buildStart: [AsyncFunction: buildStart], iles:config resolveId: [AsyncFunction: resolveId], iles:config load: [AsyncFunction: load], iles:config transform: [AsyncFunction: transform] iles:config } iles:config }, iles:config vitePlugins: [ iles:config { iles:config name: 'iles:mdx:compile', iles:config configResolved: [AsyncFunction: configResolved], iles:config transform: [AsyncFunction: transform] iles:config }, iles:config { name: 'iles:mdx:sfc', transform: [AsyncFunction: transform] }, iles:config { iles:config name: 'iles:mdx:hmr', iles:config apply: 'serve', iles:config transform: [Function: transform] iles:config }, iles:config { iles:config name: 'iles:pages', iles:config enforce: 'pre', iles:config api: [Getter], iles:config configResolved: [AsyncFunction: configResolved], iles:config configureServer: [AsyncFunction: configureServer], iles:config buildStart: [AsyncFunction: buildStart], iles:config resolveId: [AsyncFunction: resolveId], iles:config load: [AsyncFunction: load], iles:config transform: [AsyncFunction: transform] iles:config } iles:config ], iles:config vite: { iles:config root: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro', iles:config resolve: { alias: [Array], dedupe: [Array] }, iles:config server: { fs: [Object] }, iles:config build: { cssCodeSplit: false, assetsDir: 'assets' }, iles:config define: { 'import.meta.env.DISPOSE_ISLANDS': false }, iles:config optimizeDeps: { include: [Array], exclude: [Array] }, iles:config plugins: [ [Object] ], iles:config base: '/' iles:config }, iles:config vue: { iles:config reactivityTransform: true, iles:config template: { compilerOptions: [Object] } iles:config }, iles:config extendFrontmatter: [AsyncFunction (anonymous)], iles:config extendRoute: [AsyncFunction (anonymous)], iles:config extendRoutes: [AsyncFunction (anonymous)], iles:config markdown: { iles:config jsxRuntime: 'automatic', iles:config jsxImportSource: 'iles', iles:config providerImportSource: 'iles', iles:config rehypePlugins: [ [Array] ], iles:config remarkPlugins: [ [Array], [Array], [Array], [Array] ], iles:config recmaPlugins: [ [Function: recmaVueResolveComponents], [Function (anonymous)] ] iles:config }, iles:config components: { iles:config dts: true, iles:config extensions: [ 'vue', 'jsx', 'tsx', 'js', 'ts', 'mdx', 'svelte' ], iles:config include: [ /\.vue$/, /\.vue\?vue/, /\.mdx?/ ], iles:config dirs: 'src/components', iles:config resolvers: [ [Function: IlesComponentResolver], [Function (anonymous)] ], iles:config transformer: 'vue3' iles:config } iles:config } +0ms iles:config { iles:config root: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro', iles:config modules: [ iles:config { iles:config name: 'iles:base-config', iles:config debug: true, iles:config drafts: false, iles:config turbo: false, iles:config jsx: undefined, iles:config root: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro', iles:config base: '/', iles:config siteUrl: '', iles:config prettyUrls: true, iles:config ssg: [Object], iles:config configPath: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/iles.config.ts', iles:config assetsDir: 'assets', iles:config pagesDir: 'pages', iles:config srcDir: 'src', iles:config outDir: 'dist', iles:config layoutsDir: 'layouts', iles:config tempDir: '.iles-ssg-temp', iles:config modules: [], iles:config namedPlugins: [Object], iles:config resolvePath: undefined, iles:config vitePlugins: [Array], iles:config vite: [Object], iles:config vue: [Object], iles:config extendFrontmatter: [AsyncFunction: extendFrontmatter], iles:config extendRoute: [Function: extendRoute], iles:config extendRoutes: [Function: extendRoutes], iles:config markdown: [Object], iles:config components: [Object] iles:config }, iles:config { iles:config name: '@islands/mdx', iles:config markdown: [Object], iles:config configResolved: [Function: configResolved] iles:config }, iles:config { iles:config name: 'user-config', iles:config vite: [Object], iles:config configPath: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/iles.config.ts' iles:config }, iles:config { iles:config name: '@islands/pages', iles:config configResolved: [Function: configResolved] iles:config } iles:config ], iles:config debug: true, iles:config drafts: false, iles:config turbo: false, iles:config base: '/', iles:config siteUrl: '', iles:config prettyUrls: true, iles:config ssg: { sitemap: true }, iles:config configPath: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/iles.config.ts', iles:config assetsDir: 'assets', iles:config pagesDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/src/pages', iles:config srcDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/src', iles:config outDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/dist', iles:config layoutsDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/src/layouts', iles:config tempDir: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/.iles-ssg-temp', iles:config namedPlugins: { iles:config components: { iles:config name: 'unplugin-vue-components', iles:config enforce: 'post', iles:config api: [Object], iles:config transformInclude: [Function: transformInclude], iles:config transform: [Function (anonymous)], iles:config vite: [Object], iles:config webpack: [Function: webpack], iles:config configResolved: [Function: configResolved], iles:config configureServer: [Function: configureServer] iles:config }, iles:config vue: { iles:config name: 'vite:vue', iles:config handleHotUpdate: [Function: handleHotUpdate], iles:config config: [Function: config], iles:config configResolved: [Function: configResolved], iles:config configureServer: [Function: configureServer], iles:config buildStart: [Function: buildStart], iles:config resolveId: [AsyncFunction: resolveId], iles:config load: [Function: load], iles:config transform: [Function: transform] iles:config }, iles:config pages: { iles:config name: 'iles:pages', iles:config enforce: 'pre', iles:config api: [Getter], iles:config configResolved: [AsyncFunction: configResolved], iles:config configureServer: [AsyncFunction: configureServer], iles:config buildStart: [AsyncFunction: buildStart], iles:config resolveId: [AsyncFunction: resolveId], iles:config load: [AsyncFunction: load], iles:config transform: [AsyncFunction: transform] iles:config } iles:config }, iles:config vitePlugins: [ iles:config { iles:config name: 'iles:mdx:compile', iles:config configResolved: [AsyncFunction: configResolved], iles:config transform: [AsyncFunction: transform] iles:config }, iles:config { name: 'iles:mdx:sfc', transform: [AsyncFunction: transform] }, iles:config { iles:config name: 'iles:mdx:hmr', iles:config apply: 'serve', iles:config transform: [Function: transform] iles:config }, iles:config { iles:config name: 'iles:pages', iles:config enforce: 'pre', iles:config api: [Getter], iles:config configResolved: [AsyncFunction: configResolved], iles:config configureServer: [AsyncFunction: configureServer], iles:config buildStart: [AsyncFunction: buildStart], iles:config resolveId: [AsyncFunction: resolveId], iles:config load: [AsyncFunction: load], iles:config transform: [AsyncFunction: transform] iles:config } iles:config ], iles:config vite: { iles:config root: '/home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro', iles:config resolve: { alias: [Array], dedupe: [Array] }, iles:config server: { fs: [Object] }, iles:config build: { cssCodeSplit: false, assetsDir: 'assets' }, iles:config define: { 'import.meta.env.DISPOSE_ISLANDS': false }, iles:config optimizeDeps: { include: [Array], exclude: [Array] }, iles:config plugins: [ [Object] ], iles:config base: '/' iles:config }, iles:config vue: { iles:config reactivityTransform: true, iles:config template: { compilerOptions: [Object] } iles:config }, iles:config extendFrontmatter: [AsyncFunction (anonymous)], iles:config extendRoute: [AsyncFunction (anonymous)], iles:config extendRoutes: [AsyncFunction (anonymous)], iles:config markdown: { iles:config jsxRuntime: 'automatic', iles:config jsxImportSource: 'iles', iles:config providerImportSource: 'iles', iles:config rehypePlugins: [ [Array] ], iles:config remarkPlugins: [ [Array], [Array], [Array], [Array] ], iles:config recmaPlugins: [ [Function: recmaVueResolveComponents], [Function (anonymous)] ] iles:config }, iles:config components: { iles:config dts: true, iles:config extensions: [ 'vue', 'jsx', 'tsx', 'js', 'ts', 'mdx', 'svelte' ], iles:config include: [ /\.vue$/, /\.vue\?vue/, /\.mdx?/ ], iles:config dirs: 'src/components', iles:config resolvers: [ [Function: IlesComponentResolver], [Function (anonymous)] ], iles:config transformer: 'vue3' iles:config } iles:config } +6ms iles:detect +0ms iles:detect +11ms βœ” building client + server bundles done in 1.5s (node:635346) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension. (Use `node --trace-warnings ...` to show where the warning was created) Error while fetching 'default' layout. /home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/node_modules/.pnpm/vite-plugin-svg-sprite@0.3.1/node_modules/vite-plugin-svg-sprite/es/runtime.js:15 export default function addSymbol(symbol, id) { ^^^^^^ SyntaxError: Unexpected token 'export' at Object.compileFunction (node:vm:360:18) at wrapSafe (node:internal/modules/cjs/loader:1088:15) at Module._compile (node:internal/modules/cjs/loader:1123:27) at Module._extensions..js (node:internal/modules/cjs/loader:1213:10) at Module.load (node:internal/modules/cjs/loader:1037:32) at Module._load (node:internal/modules/cjs/loader:878:12) at ModuleWrap. (node:internal/modules/esm/translators:169:29) at ModuleJob.run (node:internal/modules/esm/module_job:193:25) at async Promise.all (index 0) at async ESMLoader.import (node:internal/modules/esm/loader:530:24) at async resolveLayout (file:///home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/.iles-ssg-temp/app.mjs:4677:54) βœ– resolving static paths build error: /home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/node_modules/.pnpm/vite-plugin-svg-sprite@0.3.1/node_modules/vite-plugin-svg-sprite/es/runtime.js:15 export default function addSymbol(symbol, id) { ^^^^^^ SyntaxError: Unexpected token 'export' at Object.compileFunction (node:vm:360:18) at wrapSafe (node:internal/modules/cjs/loader:1088:15) at Module._compile (node:internal/modules/cjs/loader:1123:27) at Module._extensions..js (node:internal/modules/cjs/loader:1213:10) at Module.load (node:internal/modules/cjs/loader:1037:32) at Module._load (node:internal/modules/cjs/loader:878:12) at ModuleWrap. (node:internal/modules/esm/translators:169:29) at ModuleJob.run (node:internal/modules/esm/module_job:193:25) at async Promise.all (index 0) at async ESMLoader.import (node:internal/modules/esm/loader:530:24) at async resolveLayout (file:///home/jonathanl/Code/iles-vite-plugin-svg-sprite-repro/.iles-ssg-temp/app.mjs:4677:54)  ELIFECYCLE  Command failed with exit code 1. ```
JonathanLorimer commented 1 year ago

Upon further research I think it has something to do with the plugin dynamically injecting an esm import.

https://github.com/meowtec/vite-plugin-svg-sprite/blob/main/src/index.ts#L63-L67

ElMassimo commented 1 year ago

Hi Jonathan!

Based on the error message:

vite-plugin-svg-sprite@0.3.1/node_modules/vite-plugin-svg-sprite/es/runtime.js:15
export default function addSymbol(symbol, id) {
^^^^^^

SyntaxError: Unexpected token 'export'

it seems to be failing on this line with a SyntaxError.

ElMassimo commented 1 year ago

Since vite-plugin-svg-sprite is not "type": "module", vite-plugin-svg-sprite/es/runtime.js should have the mjs extension instead, otherwise export is not a valid keyword.

To workaround this, you could force Vite not to externalize this package in SSR with:

ssr: { noExternal: ['vite-plugin-svg-sprite'] },

Then, the problem becomes that the runtime of this library assumes window is defined, which is not true for SSR.

After reading how the library works, I don't think vite-plugin-svg-sprite is compatible with SSR, and you might need to look for alternatives.

JonathanLorimer commented 1 year ago

Since vite-plugin-svg-sprite is not "type": "module", vite-plugin-svg-sprite/es/runtime.js should have the mjs extension instead, otherwise export is not a valid keyword.

To workaround this, you could force Vite not to externalize this package in SSR with:


ssr: { noExternal: ['vite-plugin-svg-sprite'] },

Then, the problem becomes that the runtime of this library assumes window is defined, which is not true for SSR.

After reading how the library works, I don't think vite-plugin-svg-sprite is compatible with SSR, and you might need to look for alternatives.

Thanks for digging in. I hadn't even considered that it wouldn't work with SSR!