Use Vite with multiple entry points.

This case-study is based on a real life case years ago when we implemented Javascript modules and Vue 2 into a PHP based system. The PHP system was responsible for example routing and in those views we could use modern vanillajs or vue apps. So not your usual SPA project.

Webpack was used to import code from multiple sources, babelify it to accommondate Internet Explorer and then creating multiple bundles. Then the script files would be included into the PHP views with script tags as you would traditionally do.

So I thought that it's time to get rid of that old Webpack and progressively move on to the future with Vite 3! This article will follow those old requirements and do not follow the modern standards in everything. This is not a tutorial, take away what you will!

Create a Vite project

Start by creating a vanillajs Vite project following the official instructions and try to run npm run dev just to see it working.

You'll notice that all the example files are in the root folder so create a src folder and inside of that a counter folder. Move counter.js, main.js, whatever svg and css it might have but leave the index.html. We'll use the npm run dev command in the future but it doesn't work the same way as default, and it's fine because the aim is to load the script files with the PHP or whatever back-end system you might have.

From your index.html edit the default script src like:

<div id="app"></div>
<script type="module" src="/dist/counter-vanilla.js"></script>

Configuring Vite for multiple sources

Next create a new file in the root folder called vite.config.js and paste the following inside:

import path from 'path'
import sources from './sources.js'

const input = {}

Object.keys(sources)
.forEach(name => {
  const src = sources[name];

  input[name] = path.resolve(__dirname, `src/${ src }`)
})

export default {
  build: {
    rollupOptions: {
        input,
        output: {
            entryFileNames: () => '[name].js',
            dir: './dist'
        }
    }
  },
}

And then create a sources.js file that is imported in the vite.config.js. This could be a file outside of the Vite project like in another git project. You could use .env file to determine the location of the sources file when using on a git hook at a server or locally on your machine.

Example sources.js:

export default {
    'counter-vanilla': 'counter/main.js',
}

Now try running first npm run build and then npm run dev. It should load the js but personnally didn't get the css working. After all, css with vanillajs doesn't fit the scope here. We'll use Vue to package those.

Including Vue 2

We'll add Vue 2.7 for now. To use the latest Vue 3 is less work, but you are in the same situtation that jumping from 2 to 3 is not yet possible, I got you covered!

You'll need to install these packages as dev depedency: npm install -D @vitejs/plugin-vue vite-plugin-vue2 vue-template-compiler.

And then the Vue itself as a normal depedency: npm install vue@^2.7.7.

Then in the vite.config.js include the vue2 plugin:

import path from 'path'
import { createVuePlugin } from 'vite-plugin-vue2'
import sources from './sources.js'

const input = {}

Object.keys(sources)
.forEach(name => {
  const src = sources[name];

  input[name] = path.resolve(__dirname, `src/${ src }`)
})

export default {
  build: {
    rollupOptions: {
        input,
        output: {
            entryFileNames: () => '[name].js',
            dir: './dist'
        }
    }
  },
  plugins: [
    createVuePlugin(/* options */)
  ],
}

Now we can create Vue 2 projects!

Vue project

Create a new folder vue-test inside of the src folder. Then create main.js and App.vue files inside of that.

Example main.js:

import Vue from 'vue'
import App from './App.vue'

new Vue({
    render: h => h(App),
}).$mount('#appVue')

Example App.vue:

<template>
<div id="appVue">
    <h1>{{ message }}</h1>
</div>
</template>

<script>
export default {
    data: () => ({
        message: 'Hello Vue 2.7!'
    }),
}
</script>

Then add it to your sources file:

export default {
    'counter-vanilla': 'counter/main.js',
    'vue-test': 'vue-test/main.js',
}

Then edit into your index.html:

<div id="app"></div>
<div id="appVue"></div>
<script type="module" src="/dist/counter-vanilla.js"></script>
<script type="module" src="/dist/vue-test.js"></script>

Now run npm run build and npm run dev and you'll should see both apps working at the same time! This could also be an example of micro frontends.

Moving forwards

Doing this we can progressively move from Vue 2 to 3 and it is also even possible to use React too thanks to Vite's flexibility.

See full code at Github: @opiispanen/vite3-multiple-entries-example

Have something to say on this topic? Here's my Twitter: @opiispanen