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

Not possible to use svelte/register server-side builds with a Svelte component exported from an esm module? #5185

Closed
mhkeller opened this issue Jul 22, 2020 · 24 comments

Comments

@mhkeller
Copy link

mhkeller commented Jul 22, 2020

I'm not sure if this is a bug or an unsupported pattern. I'm trying to use svelte/register to do server-side rendering of a Svelte component. Here are the files. Basically I'm importing a Svelte component via .mjs file that exports it. These files are also up at this reproduction repo.

// index.js
require('svelte/register');
const App = require("./src/App.svelte").default;

const data = App.render({});

console.log(data);
<!-- App.svelte -->
<script>
  import { Test } from './components/test.mjs';
</script>

<Test/>
// ./components/test.mjs
export { default as Test } from './Test.svelte';
<!-- ./components/Test.svelte -->
Test

When running node index.js I get the following error:

> node index.js

internal/modules/cjs/loader.js:1038
    throw new ERR_REQUIRE_ESM(filename);
    ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: path/to/project/lc-ssr-test/src/components/test.mjs
    at Module.load (internal/modules/cjs/loader.js:1038:11)
    at Function.Module._load (internal/modules/cjs/loader.js:929:14)
    at Module.require (internal/modules/cjs/loader.js:1080:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Object.<anonymous> (path/to/project/lc-ssr-test/src/App.svelte:5:18)
    at Module._compile (internal/modules/cjs/loader.js:1176:30)
    at Object.require.extensions.<computed> [as .svelte] (path/to/project/lc-ssr-test/node_modules/svelte/register.js:49:17)
    at Module.load (internal/modules/cjs/loader.js:1040:32)
    at Function.Module._load (internal/modules/cjs/loader.js:929:14)
    at Module.require (internal/modules/cjs/loader.js:1080:19) {
  code: 'ERR_REQUIRE_ESM'
}

I also tried running it with node -r esm index.js but that doesn't fix it. When I run this code in dev mode, however, the components load fine. Is this a limitation of svelte/register or do I have to do bring in some other third-party solution to smooth over the esm import? I would think that if the normal dev mode can handle it, there would be parity in server-side mode.

Thanks for taking a look.

@katalonne
Copy link

I think this is not related to svelte.
You need to opt-in to the esm (previous @std/esm) loader by making it a dep or by adding its options object to the package.json.
So after doing npm i --save esm, try adding
"esm": { "cjs":true } to your package.json

Please tell me if it helped.

@mhkeller
Copy link
Author

Thanks. If I run node index.js or node -r esm index.js after adding that to package.json, I get the same errors. I pushed that configuration to the esm branch of the reproduction repo. I agree this isn't exactly svelte but it seems like something svelte/register should be able to handle since this kind of file structure works when compiled normally. Or adding some info to the docs about what kind of extra tooling is required would also be a good solution.

@katalonne
Copy link

hmm... I'll try doing some research on this.

@mhkeller
Copy link
Author

Here's the same example working in the REPL: https://svelte.dev/repl/47e73637efe44b3e87962343b08adf77?version=3.24.0

@mhkeller
Copy link
Author

Same issue with some discussion: Rich-Harris/pancake#7

@tanhauhau
Copy link
Member

Well, svelte/register uses require.extension which is not supported in ES Module. See https://nodejs.org/api/esm.html#esm_no_require_extensions

@Conduitry
Copy link
Member

Yeah it sounds like there's not a corresponding feature in Node's ESM support yet, which would be required for this.

@mhkeller
Copy link
Author

mhkeller commented Jul 24, 2020

@Conduitry thanks for taking a look. Do you think there is any build remedy (either through some combination of using the esm package or adding any other files to package.json)? Or, for the moment, is the best workaround to bypass the index.mjs file and import the svelte components directly?

@mhkeller
Copy link
Author

@Rich-Harris put together a solution for this involving bundling into CommonJS. Linking it here: mhkeller/lc-ssr-test#1

@asvsfs
Copy link

asvsfs commented Aug 3, 2020

@mhkeller For this case i've used @babel/plugin-transform-modules-commonjs inside the svelte/register

function compileES6(code) {
	try {
		return require("@babel/core").transform(code, {
			plugins: ["@babel/plugin-transform-modules-commonjs"],
		});
	} catch (error) {
		console.log(`error compiling esm file ${error}`);
	}
}

Registering the extension , all ES6 modules should follow this convention

require.extensions[".mjs"] = function (module, filename) {
	try {
		let code = compileES6(fs.readFileSync(filename, "utf-8")).code;
		return module._compile(code, filename);
	} catch (error) {
		console.log(`error ${error}`);
	}
};

Also a dirty one here to just make it work :

function validate_component(component, name) {
	if (component.default) component = component.default;
	...
	return component;
}

My case was simple and it solved all the problems i had with svelte/register.
final register.js register.js gist

@mhkeller
Copy link
Author

My problem with this was solved by compiling it ahead of time per the above link. @Conduitry unless you think this should be handled inside of svelte/register, feel free to close this issue.

@Conduitry
Copy link
Member

If/When Node's ESM implementation adds the loader hooks mentioned in their docs, maybe we can revisit this, but for now it doesn't seem like there's anything for Svelte to do here,

@gamelaster
Copy link

@Conduitry looks like it is possible now:
https://nodejs.org/api/esm.html#esm_transpiler_loader

@dummdidumm
Copy link
Member

It's in stage 1 (experimental), so nothing that can be relied on I'd say

@Conduitry
Copy link
Member

Conduitry commented May 5, 2021

There's a note on the page you linked to which explicitly says that the API will change, so no, we don't want to use that.

@gamelaster
Copy link

Yes, just I wanted to point out, that the feature will be probably available to be used soon (after experimental stage). For now, we need just wait.

@tonyrewin
Copy link

import { createRequire } from "module"

const require = createRequire(import.meta.url)
const props = {}
const App = require("./src/App.svelte").default
const { html, css, head } = App.render(props)
...

unfortunately import doesn't work inside required

any svelte-to-cjs transpiller middleware?

@malindsay
Copy link

What is a working solution? not sure I saw one.

@bluwy
Copy link
Member

bluwy commented Nov 30, 2021

@malindsay As mentioned above, there is no solution until Node officially supports loaders, which is the equivalent of register in CJS.

@malindsay
Copy link

So we really don't have a svelte ssr solution, or can someone point me into a solution that works at moment? if not resolved, why was this closed?

@mhkeller
Copy link
Author

@malindsay this was my solution but this was before svelte kit #5185 (comment). im not sure if this is a current problem using svelte kit though. i put together a demo with my library and ssr worked without a problem https://github.com/mhkeller/layercake-template-sveltekit-test

@bluwy
Copy link
Member

bluwy commented Dec 1, 2021

So we really don't have a svelte ssr solution, or can someone point me into a solution that works at moment? if not resolved, why was this closed?

There are many ways to achieve Svelte SSR, svelte/register is just one of the ways if you're working with CJS. SvelteKit and Sapper both have SSR today using a different technique, by applying SSR transformations using a bundler. I'd recommended checking out vite-ssr-esm if you'd like to see how that's done.

@gamelaster
Copy link

@malindsay I implemented this functionality on esm module by experimental esm transpiler loader. It worked, but anyway, I decided to dig into how Sapper works, look various already implemented SSRs, and find out it's not that hard to do it by yourself, it just need some research. Although, I would love some more SSR documentation, due I can't use SvelteKit or Sapper.

@krishnaTORQUE
Copy link

krishnaTORQUE commented May 6, 2023

I am facing the same issue.
is there any plan to support svelte/register mjs ?
Or is there anyone who resolve this issue by any other way, please let me know?
Thanks

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