Including Vuejs application in another web application (with vue-cli >3 and Vite)
Tags: vue, webdev
Published: 2021-02-05 17:15:29

##Update:
Scroll to the bottom of the page if you want to achieve the same with Vite.

Recently I've got a task at my current company to write a small vue application (1 page only) and inject it into an existing legacy project (JSP in that case - I know it's old and ugly, but sometimes it's part of the job...). 
I've been told that there is already a vue application that is being injected into the legacy application and it is working pretty nice, so I thought to my self 'Lets see how they configured it there, and use the same way to implement the new app'. 
And then I realized that's not gonna work because the existing vue application was created 2 years ago and it was probably created with `vue-cli` 1 or 2 with all the 'pure' webpack configurations, while I am using `vue-cli` 3 in the new application (which has the `vue.config.js` file instead all the previous webpack config, and the other app has too much custom webpack configuration that it became too messy).

After I've searched the web for a solution for this problem, I didn't found something that solved my problem. Finally I've managed to solve it and I wanted to share it so maybe it'll help to someone else.


###Overview
Vue is by default using the SPA ([What is SPA?](https://www.bloomreach.com/en/blog/2018/07/what-is-a-single-page-application.html)) approach which in this case is an advantage.
**This example is probably not gonna work with SSR approach** ([What is SSR?](https://ssr.vuejs.org)).

After running `npm run build` command, you'll have all the generated files inside the `dist` folder.
In our case the generated `index.html` **won't be used** because we are going to include our vue application in another html file.
The files that we **will use** are `app.[hash].js` and `chunk-vendors.[hash].js`.
These 2 files are enough for vue to work, the app file is gonna import all the others files (js/css/etc..) that the application needs in order to work properly.


###Including vue inside another app
#####1) Move the generated files:
As I mentioned before vue is by default using the SPA approach, so basically what we need to do is to take the content of the generated `dist` folder and put it somewhere in the existing app. (Don't forget to remove the `index.html`)
It is important to keep the content order as it (don't move the js files from the js folder or the css files because the `app` file will import the other files relative to his location).

#####2) Let the existing app to import vue app files:
Choose the html file in which you want the vue app to be included, and add the following:
```html
<div id="app"></div>
<script src="js/app.[hash].js"></script>
<script src="js/chunk-vendors.[hash].js"></script>
```
Make sure that the scripts will be loaded **after** vue's root div (`<div id="app"></div>`) - If the scripts will be loaded **before** the root div, the vue application won't work.

Basically this is it, if you run your existing application, your vue app will work inside the html page that you've chosen to include it in.

###Extras
####Running on local environment
Of course before building the vue app you'll want to develop and test your vue app on your local environment.
In order to do that, you just need to replace the path of the js files at the html file to:
```html
<script src="http://localhost:8080/js/app.js"></script>
<script src="http://localhost:8080/js/chunk-vendors.js"></script>
```
Notice that when running the vue app at dev mode it doesn't use the hash at the file name, the hash is being used only when building the app for production.

####Import the files from external source
In some cases you'll want to keep the build files of the vue app in a different location and configure your existing app to loaded it from an external source (your-domain.com, AWS S3, Azure Blob, etc...).
There is a great webpack plugin that will help you with that - 
[webpack-require-from](https://github.com/agoldis/webpack-require-from)
#####Example:
If you have some server that is running on the domain `your-cool-domain.com` and this server will hold the vue app files, you can add a global variable at your existing app:
```html
<script> window.vueAppSrc = "https://your-cool-domain.com/files/" </script>
```
Now in your vue app install the plugin `npm install webpack-require-from -D`.
Then in the `vue.config.js` file add the following:
```js
const WebpackRequireFrom = require('webpack-require-from')
module.exports = {
  chainWebpack: config => {
    config.plugin('require-from').use(WebpackRequireFrom, [{ variableName: 'vueAppSrc' }])
  }
}
```
Now all the files of your vue app will be loaded from the url you've set in the global variable. (`https://your-cool-domain.com/files/app.[hash].js`)

####Why there are 2 'base' files and not only 1?
Until webpack v4 we didn't had the `chunk-vendors.[hash].js` file, and all the third party modules were inside the app file, but since webpack v4 (vue-cli 3 is using webpack v4) webpack is splitting the app and the third party modules into different files by default for a better performance.

####Can I reduce it to 1 file only?
Yes, it is possible by adding the following option into your `vue.config.js` file:
```js
module.exports = {
  configureWebpack: config => {
    config.optimization.splitChunks = false
  }
}
```
This configuration will move the whole content of `chunk-vendors` file inside the `app` file (just like before webpack v4).
**This option will have effect on the performance, so take it in count.**


###Vite
I've wanted to achieve the same thing with Vite, but because Vite's production build is based on `rollup` (which works different from webpack - you can learn more about it [Here](https://dev.to/vbanditv/vite-a-short-overview-4p17)) I've created a plugin for the same issue:

`vite-plugin-loading-script` is a vite plugin for wrapping and loading the generated files/assets with a single script into the DOM instead of `index.html`.

You can learn about the plugin in the Docs [Here](https://github.com/fima-taf/vite-plugin-loading-script).

The generated file will appear in the app's `dist` folder - `app.[hash].js`.

###Conclution
It is pretty easy to include (or inject) a vue application into another web application.
But keep in mind that there might be some other problems that I didn't tackled in my case so it's not perfect, but still might be useful to someone else.

Hope it'll help you (at least partially) :)