Closed sudo349 closed 10 months ago
how to use scss/sass?
I looked at the example but didn't see how to use it
SASS我没有使用,但我使用了Less。原理一样,你可以参考一下:
<script src="https://unpkg.com/less@4.1.3/dist/less.min.js"></script>
const options = {
moduleCache: {
vue: Vue
},
async getFile(url) {
const res = await fetch(url);
if ( !res.ok )
throw Object.assign(new Error(res.statusText + ' ' + url), { res });
return {
getContentData: asBinary => asBinary ? res.arrayBuffer() : res.text(),
}
},
addStyle(textContent) {
// 将less的字符串转换后再添加到style标签
less.render(textContent, {}, (error, output)=>{
if (error) {
console.log("Less转换失败!")
} else {
const style = Object.assign(document.createElement('style'), { textContent: output.css });
const ref = document.head.getElementsByTagName('style')[0] || null;
document.head.insertBefore(style, ref);
}
})
},
}
const { loadModule } = window['vue3-sfc-loader'];
//...
I have worked out a way to do this, in particular including imports within the SCSS (e.g., to share variables). For context, I'm trying to use Vue for the output of content 'blocks' in a WordPress theme, so you'll see references to that scattered below but it's mostly file paths and naming conventions - this should be adaptable to a non-WordPress use case.
Important notes:
<style scoped>
does not work. (It's something I would like to look into but isn't a high priority at the moment so do not have an ETA on a solution.)snake-case
syntax when you call the component in JSX, even if you define it in PascalCase
as I have. I don't know why, but that's the only way it works.<head>
<script src="https://cdn.jsdelivr.net/npm/vue3-sfc-loader/dist/vue3-sfc-loader.js"></script>
<script type="module" src="path/to/vue-blocks.js"></script>
</head>
<body>
<div id="app">
<?php
// this is a shortened version for clarity;
// basically this is noting to load partials that are going to contain Vue components INSIDE #app
// If you aren't using PHP you would just put the Vue components straight in here
get_template_part('blocks/custom/call-to-action/index.php');
?>
</div>
</body>
// blocks/custom/call-to-action/index.php
// Example of a file where a component is called
// Props will also be passed into the `call-to-action` element when I complete it
// Must use snake-case for the component name
<div class="block__call-to-action">
<call-to-action></call-to-action>
</div>
// call-to-action.vue
// The actual Vue single-file component
// This is incomplete in terms of props/dynamic data, but you'll get the idea
<script lang="ts">
export default {
data() {
return {
};
},
};
</script>
<template>
<h2>Content to go here!</h2>
</template>
<style lang="scss">
@import '../../../scss/variables';
h2 {
color: map-get($colours, 'primary');
}
</style>
// vue-blocks.js
// This is the file that creates the Vue app, imports the components, and compiles their SCSS
import * as Vue from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
import * as sass from 'https://jspm.dev/sass';
const siteUrl = window.location.origin;
const themeUrl = '/wp-content/themes/starterkit-blocks/';
const sassDepImporter = {
load: async(url) => {
const file = await fetch(url.pathname);
const content = await file.text();
return {
contents: content,
syntax: 'scss',
};
},
canonicalize: (str) => {
const fileTree = str.split('/').filter((part) => part !== '..');
const fileName = `_${fileTree.pop()}.scss`;
return new URL(`${fileTree}/${fileName}`, `${siteUrl}${themeUrl}`);
},
};
const vueSfcLoaderOptions = {
moduleCache: {
vue: Vue,
sass,
},
async getFile(url) {
const res = await fetch(url);
if (!res.ok) {
throw Object.assign(new Error(res.statusText + ' ' + url), { res });
}
return {
getContentData: () => {
return res.text().then((content) => {
// Filter out the <style> tags from the component as they need to be processed separately
const dom = new DOMParser().parseFromString(content, 'text/html');
return Array.from(dom.head.children)
.filter((element) => element.tagName !== 'STYLE')
.map((element) => element.outerHTML)
.join('\n');
});
},
};
},
async addStyle(fileUrl) {
const res = await fetch(fileUrl);
if (!res.ok) {
throw Object.assign(new Error(res.statusText + ' ' + url), { res });
}
const dom = new DOMParser().parseFromString(await res.text(), 'text/html');
const rawScss = Array.from(dom.head.children).find((element) => element.tagName === 'STYLE');
const compiled = await sass.compileStringAsync(rawScss.textContent, {
importers: [sassDepImporter],
});
const style = document.createElement('style');
style.setAttribute('data-vue-component', fileUrl.split('/').pop());
style.type = 'text/css';
style.textContent = compiled.css;
document.body.appendChild(style);
},
// eslint-disable-next-line no-shadow
async handleModule(type, getContentData, path, options) {
if (type === '.vue') {
// Get and compile the SCSS from the component file
options.addStyle(path);
}
//throw new Error(`Tried to import a non-vue file at ${path}`);
},
};
const { loadModule } = window['vue3-sfc-loader'];
Vue.createApp({
components: {
CallToAction: Vue.defineAsyncComponent(() => loadModule(`${themeUrl}/blocks/custom/call-to-action/call-to-action.vue`, vueSfcLoaderOptions)),
// Add more components here
},
template: '',
}).mount('#app');
will be available in the next release. example: https://github.com/FranckFreiburger/vue3-sfc-loader/discussions/181
how to use scss/sass?
I looked at the example but didn't see how to use it