Transpiles a vue-cli project into a non-bundled, non node-dependent project.
The purpose of this tool is compiling away Single File Components (SFCs) whilst making the resulting code look like it was written by hand.
This tool was build to ease development of a Vue project during the course "Web programming" at the Faculty of Technical Sciences.
Our professor forbids using Node.js, so in order to use SFCs and standard vue tooling I developed this tool.
Input:
src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './index.css'
const app = createApp(App)
app.use(router)
app.mount('#app')
Output:
dist/src/main.js
import { createApp } from '/modules/[email protected]'
import App from './App.js'
import router from './router/index.js'
const app = createApp(App)
app.use(router)
app.mount('#app')
dist/index.html
...
<head>
<script type="module" src="src/main.js"></script>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
...
Note: All style tags will be extracted into separate .css
files and eagerly injected into
the index.html
entrypoint as stylesheets:
<link rel="stylesheet" href="/src/Component.css">
Input:
src/Component.vue
<template>
<div>
<button
@click="changeColor()"
:style="{color: msg}"
>
{{ msg }}
</button>
<input
class="red"
v-model="msg"
:style="{color: msg}"
/>
<AcademicCapIcon/>
<CogIcon/>
<CameraIcon/>
</div>
</template>
<script>
import { ref, watch, onMounted } from 'vue'
import { AcademicCapIcon, CogIcon } from '@heroicons/vue/solid'
import { CameraIcon } from '@heroicons/vue/outline'
export default {
components: {
AcademicCapIcon,
CogIcon,
CameraIcon
},
setup() {
onMounted(() => console.log('Component Mounted'))
const counter = ref(0)
const msg = ref('red')
const setMsg = value => msg.value = value
const changeColor = () => (counter.value++ % 2 == 0) ? setMsg('yellow') : setMsg('red')
watch(
() => msg,
() => console.log(`Color changed to ${msg.value}`)
)
return {
msg,
changeColor
}
}
}
</script>
<style>
.red {
color:orange;
}
</style>
Output:
dist/src/Component.js
import { onMounted, ref, watch } from '/modules/[email protected]'
import CameraIcon from '/modules/@heroicons/vue/outline/CameraIcon.js'
import AcademicCapIcon from '/modules/@heroicons/vue/solid/AcademicCapIcon.js'
import CogIcon from '/modules/@heroicons/vue/solid/CogIcon.js'
export default {
template: `
<div>
<button
@click="changeColor()"
:style="{color: msg}"
>
{{ msg }}
</button>
<input
class="red"
v-model="msg"
:style="{color: msg}"
/>
<AcademicCapIcon/>
<CogIcon/>
<CameraIcon/>
</div>
`,
components: { AcademicCapIcon, CogIcon, CameraIcon },
setup() {
onMounted(() => console.log('Component Mounted'))
const counter = ref(0)
const msg = ref('red')
const setMsg = value => (msg.value = value)
const changeColor = () => counter.value++ % 2 == 0 ? setMsg('yellow') : setMsg('red')
watch(
() => msg,
() => console.log(`Color changed to ${msg.value}`)
)
return {
msg,
changeColor
}
},
}
dist/Component.css
.red {
color:orange;
}
- Not very modular
- File type loaders have to be changed in code
- Only vue@next
- Only SFC components with 'export default {}'
- Lazily loading components using import()
- Lazily injecting component styles on load
<script setup>
<style scoped>
- bindings in
<style>
With no module resolution algorithms or bundling available, we have to specify module replacements manually.
You can get npm modules off of CDNs such as
Example configuration (place this file in your project root):
imports.config.js
/*
Config for https://www.npmjs.com/package/babel-plugin-transform-imports
*/
const importOptions = {
'vue': {
transform: '/modules/[email protected]',
skipDefaultConversion: true
},
'@vue/devtools-api': {
transform: '/modules/[email protected]',
skipDefaultConversion: true
},
'vue-router': {
transform: '/modules/[email protected]',
skipDefaultConversion: true
},
'@headlessui/vue': {
transform: '/modules/[email protected]',
skipDefaultConversion: true
},
'@heroicons/vue\/[^\/]*$': {
transform: (importName, matches) => `/modules/${matches[0]}/${importName}.js`,
skipDefaultConversion: false
},
'date-fns': {
transform: '/modules/[email protected]',
skipDefaultConversion: true
}
}
/*
Specify modules to be excluded from import transforms.
These should be 'leaves' of the dependency graph.
They should have no dependencies themselves.
This is a performance optimization.
*/
const excludedLibraries = [
'[email protected]',
'[email protected]'
]
export {
importOptions,
excludedLibraries
}
Print usage:
>> node index.js --help
babel-transform-vue-ftn
Transpiles a vue-cli project into a non-bundled, non node-dependent project.
Options
-i, --input string The root directory of the project to transpile.
-o, --output string The output directory where the built files will be placed.
The default is /dist under the project root.
-h, --help Print this usage guide.
Transpile a project:
>> node index.js --input E:\Projects\web
[ Building... ]
[ Build finished ]: 759.051ms
DONE Build complete. The dist directory E:/Projects/web/dist is ready to be deployed.