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

Vite and SystemJS #1049

Closed
pbrzosko opened this issue Sep 17, 2022 · 11 comments
Closed

Vite and SystemJS #1049

pbrzosko opened this issue Sep 17, 2022 · 11 comments

Comments

@pbrzosko
Copy link

pbrzosko commented Sep 17, 2022

Describe the bug or question
I am trying to make a Vite build work in dev mode with single-spa. Since ES modules import maps are not widely supported yet, I wanted to make Vite to build a SystemJS bundle in dev mode and import it in single-spa.

To Reproduce
I have configured Vite this way:
worker: { rollupOptions: { output: { format: "system", entryFileNames: '[name].js' }, } }
but I am getting following error in single-spa:
app-errors.js:87 Uncaught Error: application 'app_name' died in status LOADING_SOURCE_CODE: undefined
From what I understand build module is missing lifecycle function exports?

Expected behavior
I would really like to use Vite with SystemJS. I don't want to have import maps from SystemJS and ES together in one setup. I have read docs about Vite and it is written there that desired way to work is to use ES modules in dev and SystemJS in production build. I would also like to avoid that, because there will be different configurations / sources between dev and prod and this is not good.
Is it the case that Vite always produces ES module and to make it work I would need to fallback to webpack to make it work? Will it work with Vue3?

@Takitaf
Copy link

Takitaf commented Sep 21, 2022

@pbrzosko It works, I am configuring the same technology stack as you have right now. The question is: how are you building your Vite+Vue3 app?

If you are using the npm run dev (or just vite) command, it will be served from dev server without building.

You need to run npm run build (or just vite build) to take the rollupOptions into account and then run npm run preview (or just vite preview) to serve those. you can run the vite build with --watch option, if you need the HMR.

Also, consider (if you are not using it already) the single-spa-vue package to create application compatible with single-spa - you can see an example of main.js here - https://github.com/Svelte-React-Vue-Angular-SPA/vue/blob/main/src/main.js


Additionally, if you want to develop your Vite + Vue3 microfrontend using vite and dev server, you can create main-independent.js next to the main.js file and link it in your index.html.

EDIT:
Oops, I misunderstood your question - you want the dev mode specifically. The only way I found is, unfortunately, to use dev mode for developing locally with different main.js + esm + local index.html, and switching to vite build --watch + systemjs + vite preview to check the integration.

@pbrzosko
Copy link
Author

pbrzosko commented Oct 11, 2022 via email

@FrazCake
Copy link

Hi @pbrzosko,

I'm more or less in your situation and I'm curious about the progress of this one.
Were you able to find a good way to deal with vite in dev mode?
I have some microfrontends using Vue2 and webpack and one new that I'm trying to add with Vite4 and Vue3.
In root config I'm registering the microfrontends in this way (using layout engine):

const layout = `<single-spa-router>
        <nav class="topnav">
          <application name="@organization/nav"></application>
        </nav>
       ...
        <footer>
          <application name="@organization/footer"></application>
        </footer>
      </single-spa-router>`
 
const routes = constructRoutes(layout, { loaders: {},props: {} });

const applications = constructApplications({
    routes,
    loadApp({ name }) {
      return System.import(name);
    },
  });
const layoutEngine = constructLayoutEngine({ routes, applications });
applications.forEach(registerApplication);

But this doesn't work for vite in dev as it serves native esm.
Did you find a good solution for your dev environment?
Also I'd like to mix Vuetify2 and Vuetify3, but I notice lot of issues trying that, have you dealt with anything like this?

@pbrzosko
Copy link
Author

pbrzosko commented Feb 28, 2023

Hi @FrazCake,

I actually ended up in two configurations - one for local dev and other for production. In local dev I am specifying url to the module in ES module import map:

<script type="importmap">
      {
        "imports": {
            ...
        }
      }
    </script>

which then works in dev mode by importing apps defined here as ES modules. And for production, I have a systemjs-importmap:

<script type="systemjs-importmap" src="/modules-importmap.json"></script>

and then in Vite configuration I am building systemjs module for production:

build: {
      cssCodeSplit: false,
      rollupOptions: {
        input: "src/main.ts",
        output: {
          entryFileNames: `[name].${hash}.js`,
          chunkFileNames: `[name].${hash}.js`,
          assetFileNames: `[name].${hash}.[ext]`,
          format: "system",
        },
        preserveEntrySignatures: "strict",
      },
    },

And sorry, I do not use vuetify anymore, so I didn't encounter any issues with mixing 2 and 3.

@juannn91
Copy link

juannn91 commented Apr 28, 2023

I was unable to get the import map working for my project, but the single-spa docs for Vite recommend using an MR on SystemJS related to this issue.

To get this working in my project, I added the following script to my HTML file and modified the original commit's code by adding #esm to the end of each module file name (only in testing environments). This change allowed the HRM of vue3 to work as expected. The only issue I haven't been able to solve yet is how to handle the base URL for public files on localhost.

        <script type="module">
            (function (global) {
                const systemJSPrototype = global.System.constructor.prototype;
        
                const originalCreateScript = systemJSPrototype.createScript;
                systemJSPrototype.createScript = function () {
                    return  Object.assign(originalCreateScript.apply(this, arguments),{ type: 'module' });
                };
                const originalInstantiate = systemJSPrototype.instantiate;
                systemJSPrototype.instantiate = function (url) {
        
                    return originalInstantiate
                    .apply(this, arguments)
                    .then(lastRegister => {
                    if (!url.match(/#esm$|\?esm$/))
                        return lastRegister;
        
                    // esm is the fallback
                    return import(url).then(m => [[], _export => (_export(m), {})]);
                    });
                };
        
            })(typeof self !== 'undefined' ? self : global);
        </script>

@webJose
Copy link

webJose commented Aug 20, 2023

Guys, I created vite-plugin-single-spa that will convert Vite + XXX projects to single-spa projects. They will work with native import maps, but ideally you can opt for SystemJS import maps. It is still experimental. I would love to have feedback to improve it further if needed. So far, it's been working excellently.

@MilanKovacic
Copy link
Contributor

Have you solved the issue?

@MilanKovacic
Copy link
Contributor

Closing this issue due to inactivity. Please reopen or create a new issue if the concern persists or if there are further details to provide.

@cpalmer-ft
Copy link

re-opening this

@MilanKovacic
Copy link
Contributor

Vite uses esbuild during development, and rollup for production build. Esbuild does not (and most likely never will) support SystemJS output format. In order to use Vite with single-spa, my personal recommendation is to use native modules . You can see an unofficial example of this here: https://github.com/MilanKovacic/single-spa-vite.

@miradnan
Copy link

I was running into the same issue. For me adding the below code to vite config inside build -> rollupOptions did the trick. Thanks to @pbrzosko !

preserveEntrySignatures: "strict",

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

8 participants