Use the Sass Compiler API
nex3 opened this issue · 2 comments
Description
We (the Sass team) have just released a proposal for a Compiler
API in Sass that shares resources between different compilations (see also sass/sass#3296). This is particularly useful when using the sass-embedded
package, which runs a very fast subprocess to compile Sass: within the lifetime of a single Compiler
, the subprocess will remain open, eliminating all the overhead of starting it and shutting it down that currently causes sass-embedded
to be slower than it could be.
For now, we're just seeking your feedback on the proposal. Once it lands, we hope you'll integrate it into Vite for substantially improved performance.
Suggested solution
Start a Compiler
when Vite's build initializes and uses that compiler to compile all Sass files, so that Sass users using the embedded host experience better performance.
Alternative
Runs a separate sass.compile()
call for each compilation, which has a large amount of overhead when using sass-embedded.
Additional context
No response
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
Thank you!
As the proposed API only supports the modern API, Vite needs to migrate to modern API first (#7116). Other than that, I guess the proposed API work for us.
Proposal -- do what sass-loader did (webpack-contrib/sass-loader#774). Create an 'api' flag on the options that lets uses opt-in to use the modern API, while still maintaining 100% backwards compatibility with others.
Could be as simple as this in the config:
export default defineConfig({
plugins: [react()],
css :{
preprocessorOptions : {
scss: {
api: "modern",
// Use the new Node loaders. Added as an example so that it performed functionality other than what is
// available today.
importers: [
new sass.NodePackageImporter()
]
}
}
}
})
Cutdown code will look something like this:
// this would be the new input type... either one.
type SassWorkerOptions = SassStylePreprocessorOptions & {additionalData: undefined} |
Sass.StringOptions<"sync"> & {api:"modern"};
if (options.api === "modern") {
// eslint-disable-next-line no-restricted-globals
const url = require('node:url');
// reshape this.
options.filename = url.pathToFileURL(options.filename);
return new Promise((resolve, reject) => {
try {
let out = {
stats: {
includedFiles: [] as string[]
}
};
const res = sass.compileString(data, options as Sass.StringOptions<"sync">);
out = Object.assign(out, res);
// rebuild stats.includedFiles, since they're wanted
// in some downstream process.
out.stats = {
includedFiles: res.loadedUrls.map( (item) => {
return item.pathname
})
}
resolve(out);
} catch (e) {
reject(e);
}
});
}