Example of how to export a Vue project in library mode, so it can be integrated in any HTML page.
Don't create the App there, and not mount it. Just import it and export it.
// /src/main.ts
import './assets/main.css'
import App from './App.vue'
export { App }
Now the main.ts is very passive so we have to trigger the app creation and mounting it manually in our dev index.html
. This is also what have to be done when the lib is integrated in another app.
<!-- /index.html -->
<body>
<div id="app"></div>
<script type="module">
import { createApp } from 'vue';
import { App as VueLibExample } from '/src/main.ts';
createApp(VueLibExample).mount('#app');
</script>
</body>
We are using an alias to avoid conflict with another imported apps.
The main concept is "build your app using library mode". Here is the documentation to do this with Vite.
There is described how to set up your vite.config.js
and package.json
.
In summary this is how my vite.config.js
looks like at the end:
// vite.config.js
import { fileURLToPath, URL } from 'node:url'
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(__dirname, 'src/main.ts'),
name: 'VueLibExample',
// the proper extensions will be added
fileName: 'vue-lib-example',
},
rollupOptions: {
// make sure to externalize deps that shouldn't be bundled
// into your library
external: ['vue'],
output: {
// Provide global variables to use in the UMD build
// for externalized deps
globals: {
vue: 'Vue',
},
},
},
},
})
I am not sure about the external: ['vue']
, it may be a good idea to include the whole vue in your library to prevent possible dependencies version problems.
And this is my package.json
:
{
"name": "vue-lib-example",
"version": "0.0.0",
"private": true,
"type": "module",
"files": [
"dist"
],
"main": "./dist/vue-lib-example.umd.cjs",
"module": "./dist/vue-lib-example.js",
"exports": {
".": {
"import": "./dist/vue-lib-example.js",
"require": "./dist/vue-lib-example.umd.cjs"
}
},
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build --force"
},
"dependencies": {
"vue": "^3.4.15"
},
"devDependencies": {
"@tsconfig/node20": "^20.1.2",
"@types/node": "^20.11.10",
"@vitejs/plugin-vue": "^5.0.3",
"@vue/tsconfig": "^0.5.1",
"npm-run-all2": "^6.1.1",
"typescript": "~5.3.0",
"vite": "^5.0.11",
"vue-tsc": "^1.8.27"
}
}
We can build our lib:
> yarn build
yarn run v1.22.21
$ run-p type-check "build-only {@}" --
$ vite build
$ vue-tsc --build --force
vite v5.1.3 building for production...
✓ 10 modules transformed.
dist/style.css 2.65 kB │ gzip: 0.94 kB
dist/vue-lib-example.js 1.94 kB │ gzip: 0.92 kB
dist/style.css 2.65 kB │ gzip: 0.94 kB
dist/vue-lib-example.umd.cjs 1.83 kB │ gzip: 0.95 kB
✓ built in 198ms
✨ Done in 3.11s.
Once we have the exported files we can use them in any HTML web page like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My website</title>
<link rel="stylesheet" href="/dist/style.css">
</head>
<body>
<div id="the-div"></div>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.prod.js"
}
}
</script>
<script type="module">
import { createApp } from 'vue';
import { App as VueLibExample } from '/dist/vue-lib-example.js';
createApp(VueLibExample).mount('#the-div');
</script>
</body>
</html>
Special attention to the <link>
element importing the css style and <script type="importmap">
importing the vue
library undert the vue
name. It is like this how is expected in our library js
.