Vue3 Single File Component loader
Load .vue files directly from your html/js. No node.js environment, no (webpack) build step.
<html>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>
<script src="https://cdn.jsdelivr.net/npm/vue3-sfc-loader"></script>
<script>
const { loadModule } = window['vue3-sfc-loader'];
const options = {
moduleCache: {
vue: Vue
},
getFile(url) {
return fetch(url).then(response => response.ok ? response.text() : Promise.reject(response));
},
addStyle(styleStr) {
const style = document.createElement('style');
style.textContent = styleStr;
const ref = document.head.getElementsByTagName('style')[0] || null;
document.head.insertBefore(style, ref);
}
}
const app = Vue.createApp({
components: {
'my-component': Vue.defineAsyncComponent( () => loadModule('./myComponent.vue', options) )
},
template: '<my-component></my-component>'
});
app.mount('#app');
</script>
</body>
</html>
https://codepen.io/franckfreiburger/project/editor/AqPyBr
latest minified version:
loadModule(path
: string, options
: Options): Promise<Module>
webpack --config ./build/webpack.config.js --mode=production --env targetsBrowsers="> 1%, last 2 versions, Firefox ESR, not dead, not ie 11"
see package.json
“build” script
vue3-sfc-loader.js
= Webpack
( @vue/compiler-sfc
+ @babel
)
.vue
file@vue/compiler-sfc
)@babel
)@babel/traverse
)see https://github.com/FranckFreiburger/http-vue-loader
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>
<script src="https://cdn.jsdelivr.net/npm/vue3-sfc-loader"></script>
<script>
// window.localStorage.clear();
const options = {
moduleCache: {
vue: Vue,
},
getFile(url) {
return fetch(url).then(response => response.ok ? response.text() : Promise.reject(response));
},
addStyle(styleStr) {
const style = document.createElement('style');
style.textContent = styleStr;
const ref = document.head.getElementsByTagName('style')[0] || null;
document.head.insertBefore(style, ref);
},
log(type, ...args) {
console.log(type, ...args);
},
compiledCache: {
set(key, str) {
// naive storage space management
for (;;) {
try {
// doc: https://developer.mozilla.org/en-US/docs/Web/API/Storage
window.localStorage.setItem(key, str);
break;
} catch(ex) {
// handle: Uncaught DOMException: Failed to execute 'setItem' on 'Storage': Setting the value of 'XXX' exceeded the quota
window.localStorage.removeItem(window.localStorage.key(0));
}
}
},
get(key) {
return window.localStorage.getItem(key);
},
},
additionalModuleHandlers: {
'.json': (source, path, options) => JSON.parse(source),
}
}
// <!--
const source = `
<template>
<div class="example">{{ msg }}</div>
</template>
<script>
export default {
data () {
return {
msg: 'Hello world!'
}
}
}
</script>
<style scoped>
.example {
color: red;
}
</style>
`;
// -->
const { createSFCModule } = window["vue3-sfc-loader"];
const myComponent = createSFCModule(source, './myComponent.vue', options);
// ... or by file:
// const { loadModule } = window["vue3-sfc-loader"];
// const myComponent = loadModule('./myComponent.vue', options);
const app = Vue.createApp({
components: {
'my-component': Vue.defineAsyncComponent( () => myComponent ),
},
template: 'root: <my-component></my-component>'
});
app.mount('#app');
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>
<script src="https://pugjs.org/js/pug.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue3-sfc-loader@latest/dist/vue3-sfc-loader.js"></script>
<script>
/* <!-- */
const sfcSontent = `
<template lang="pug">
ul
each val in ['p', 'u', 'g']
li= val
</template>
`;
/* --> */
const options = {
moduleCache: {
vue: Vue,
pug: require('pug'),
},
getFile(url) {
if ( url === './myPugComponent.vue' )
return Promise.resolve(sfcSontent);
return fetch(url).then(response => response.ok ? response.text() : Promise.reject(response));
},
addStyle: () => {},
}
const { loadModule } = window["vue3-sfc-loader"];
Vue.createApp(Vue.defineAsyncComponent(() => loadModule('./myPugComponent.vue', options))).mount('#app');
</script>
</body>
</html>
see at vuejs/rfcs
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>
<script src="https://cdn.jsdelivr.net/npm/vue3-sfc-loader"></script>
<script>
const sfcSontent = /* <!-- */`
<template>
Hello <span class="example">{{ msg }}</span>
</template>
<script>
export default {
data () {
return {
msg: 'world!',
color: 'blue',
}
}
}
</script>
<style scoped>
.example {
color: v-bind('color')
}
</style>
`/* --> */;
const options = {
moduleCache: {
vue: Vue,
},
getFile(url) {
if ( url === './myComponent.vue' )
return Promise.resolve(sfcSontent);
return fetch(url).then(response => response.ok ? response.text() : Promise.reject(response));
},
addStyle(styleStr) {
const style = document.createElement('style');
style.textContent = styleStr;
const ref = document.head.getElementsByTagName('style')[0] || null;
document.head.insertBefore(style, ref);
},
}
const { loadModule } = window["vue3-sfc-loader"];
Vue.createApp(Vue.defineAsyncComponent(() => loadModule('./myComponent.vue', options))).mount('#app');
</script>
</body>
</html>
Author: FranckFreiburger
Source Code: https://github.com/FranckFreiburger/vue3-sfc-loader
#vue #vuejs #javascript