From 4948f86927fae8ff0c371ecf89530fce6c16f885 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 20 Jul 2024 15:41:38 +0900 Subject: [PATCH 01/54] feat: support sass modern api --- packages/vite/src/node/plugins/css.ts | 65 ++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 200262ffdd0427..1c7f5723753438 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2099,6 +2099,12 @@ const makeScssWorker = ( } } + type ScssWorkerResult = { + css: string + map?: string | undefined + stats: Pick + } + const worker = new WorkerWithFallback( () => async ( @@ -2112,6 +2118,59 @@ const makeScssWorker = ( // eslint-disable-next-line no-restricted-globals const path = require('node:path') + // https://github.com/vitejs/vite/pull/7170 + // https://github.com/vitejs/vite/issues/14689#issuecomment-2095118836 + // TODO: modern-compiler? + // https://github.com/vitejs/vite/issues/14689 + // https://github.com/webpack-contrib/sass-loader?tab=readme-ov-file#api + if (options.api === 'modern') { + const { fileURLToPath, pathToFileURL } = + // eslint-disable-next-line no-restricted-globals + require('node:url') as typeof import('node:url') + + const sassOptions = { ...options } as Sass.StringOptions<'async'> + sassOptions.url = pathToFileURL(options.filename) + sassOptions.sourceMap = options.enableSourcemap + + if (typeof sassOptions.syntax === 'undefined') { + const ext = path.extname(options.filename) + if (ext && ext.toLowerCase() === '.scss') { + sassOptions.syntax = 'scss' + } else if (ext && ext.toLowerCase() === '.sass') { + sassOptions.syntax = 'indented' + } else if (ext && ext.toLowerCase() === '.css') { + sassOptions.syntax = 'css' + } + } + + // https://github.com/sass/sass/issues/3247 + const _internalImporter: Sass.Importer<'async'> = { + canonicalize(url, context) { + if (context.containingUrl) { + const importer = fileURLToPath(context.containingUrl) + return internalImporter(url, importer, options.filename) + } + return null + }, + load(_canonicalUrl) { + return null + }, + } + sassOptions.importers ??= [] + sassOptions.importers.push(_internalImporter) + + const result = await sass.compileStringAsync(data, sassOptions) + return { + css: result.css, + map: result.sourceMap + ? JSON.stringify(result.sourceMap) + : undefined, + stats: { + includedFiles: result.loadedUrls.map((url) => fileURLToPath(url)), + }, + } satisfies ScssWorkerResult + } + // NOTE: `sass` always runs it's own importer first, and only falls back to // the `importer` option when it can't resolve a path const _internalImporter: Sass.LegacyAsyncImporter = ( @@ -2144,11 +2203,7 @@ const makeScssWorker = ( } : {}), } - return new Promise<{ - css: string - map?: string | undefined - stats: Sass.LegacyResult['stats'] - }>((resolve, reject) => { + return new Promise((resolve, reject) => { sass.render(finalOptions, (err, res) => { if (err) { reject(err) From 0fea9c4008d397d09c5fac2aba3f0975cd1575e0 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 20 Jul 2024 16:07:50 +0900 Subject: [PATCH 02/54] test: add playground --- packages/vite/src/node/plugins/css.ts | 13 +------------ playground/css-sass-modern/css-dep/index.scss | 3 +++ playground/css-sass-modern/css-dep/package.json | 8 ++++++++ playground/css-sass-modern/import.scss | 1 + playground/css-sass-modern/index.html | 7 +++++++ playground/css-sass-modern/main.js | 3 +++ playground/css-sass-modern/package.json | 15 +++++++++++++++ playground/css-sass-modern/test.sass | 2 ++ playground/css-sass-modern/test.scss | 4 ++++ playground/css-sass-modern/vite.config.js | 16 ++++++++++++++++ pnpm-lock.yaml | 8 ++++++++ 11 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 playground/css-sass-modern/css-dep/index.scss create mode 100644 playground/css-sass-modern/css-dep/package.json create mode 100644 playground/css-sass-modern/import.scss create mode 100644 playground/css-sass-modern/index.html create mode 100644 playground/css-sass-modern/main.js create mode 100644 playground/css-sass-modern/package.json create mode 100644 playground/css-sass-modern/test.sass create mode 100644 playground/css-sass-modern/test.scss create mode 100644 playground/css-sass-modern/vite.config.js diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 1c7f5723753438..ea5c7cd9d3a9a3 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2132,17 +2132,6 @@ const makeScssWorker = ( sassOptions.url = pathToFileURL(options.filename) sassOptions.sourceMap = options.enableSourcemap - if (typeof sassOptions.syntax === 'undefined') { - const ext = path.extname(options.filename) - if (ext && ext.toLowerCase() === '.scss') { - sassOptions.syntax = 'scss' - } else if (ext && ext.toLowerCase() === '.sass') { - sassOptions.syntax = 'indented' - } else if (ext && ext.toLowerCase() === '.css') { - sassOptions.syntax = 'css' - } - } - // https://github.com/sass/sass/issues/3247 const _internalImporter: Sass.Importer<'async'> = { canonicalize(url, context) { @@ -2736,7 +2725,7 @@ const createPreprocessorWorkerController = (maxWorkers: number | undefined) => { return scss.process( source, root, - { ...options, indentedSyntax: true }, + { ...options, indentedSyntax: true, syntax: 'indented' }, resolvers, ) } diff --git a/playground/css-sass-modern/css-dep/index.scss b/playground/css-sass-modern/css-dep/index.scss new file mode 100644 index 00000000000000..97a24aa0551eb9 --- /dev/null +++ b/playground/css-sass-modern/css-dep/index.scss @@ -0,0 +1,3 @@ +.css-dep-sass { + color: orange; +} diff --git a/playground/css-sass-modern/css-dep/package.json b/playground/css-sass-modern/css-dep/package.json new file mode 100644 index 00000000000000..204e8c71b0ebba --- /dev/null +++ b/playground/css-sass-modern/css-dep/package.json @@ -0,0 +1,8 @@ +{ + "name": "@vitejs/test-css-dep", + "private": true, + "version": "1.0.0", + "main": "index.js", + "style": "index.css", + "sass": "index.scss" +} diff --git a/playground/css-sass-modern/import.scss b/playground/css-sass-modern/import.scss new file mode 100644 index 00000000000000..daf3dc358af6c2 --- /dev/null +++ b/playground/css-sass-modern/import.scss @@ -0,0 +1 @@ +@import 'css-dep'; // package w/ sass entry points diff --git a/playground/css-sass-modern/index.html b/playground/css-sass-modern/index.html new file mode 100644 index 00000000000000..4dd4295a152bc4 --- /dev/null +++ b/playground/css-sass-modern/index.html @@ -0,0 +1,7 @@ +
+

test.scss: orange

+

test.scss: orange

+

css-dep: orange

+
+ + diff --git a/playground/css-sass-modern/main.js b/playground/css-sass-modern/main.js new file mode 100644 index 00000000000000..a59ac1916760b1 --- /dev/null +++ b/playground/css-sass-modern/main.js @@ -0,0 +1,3 @@ +import './test.scss' +import './test.sass' +import './import.scss' diff --git a/playground/css-sass-modern/package.json b/playground/css-sass-modern/package.json new file mode 100644 index 00000000000000..8e19cbaae6957d --- /dev/null +++ b/playground/css-sass-modern/package.json @@ -0,0 +1,15 @@ +{ + "name": "@vitejs/test-css-sass-modern", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "debug": "node --inspect-brk ../../packages/vite/bin/vite", + "preview": "vite preview" + }, + "devDependencies": { + "@vitejs/test-css-dep": "link:./css-dep" + } +} diff --git a/playground/css-sass-modern/test.sass b/playground/css-sass-modern/test.sass new file mode 100644 index 00000000000000..12b85b2e17ad94 --- /dev/null +++ b/playground/css-sass-modern/test.sass @@ -0,0 +1,2 @@ +.test-sass + color: $injectedColor diff --git a/playground/css-sass-modern/test.scss b/playground/css-sass-modern/test.scss new file mode 100644 index 00000000000000..49ab0b73235508 --- /dev/null +++ b/playground/css-sass-modern/test.scss @@ -0,0 +1,4 @@ +.test-scss { + /* injected via vite.config.js */ + color: $injectedColor; +} diff --git a/playground/css-sass-modern/vite.config.js b/playground/css-sass-modern/vite.config.js new file mode 100644 index 00000000000000..1a03f1224aeec0 --- /dev/null +++ b/playground/css-sass-modern/vite.config.js @@ -0,0 +1,16 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + css: { + preprocessorOptions: { + scss: { + api: 'modern', + additionalData: `$injectedColor: orange;`, + }, + sass: { + api: 'modern', + additionalData: `$injectedColor: orange\n`, + }, + }, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62131352ec51e9..6bf587b5323d73 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -597,6 +597,14 @@ importers: playground/css-no-codesplit: {} + playground/css-sass-modern: + devDependencies: + '@vitejs/test-css-dep': + specifier: link:./css-dep + version: link:css-dep + + playground/css-sass-modern/css-dep: {} + playground/css-sourcemap: devDependencies: less: From 2feb149e35f94e1c202696b56a54574a2f160242 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 20 Jul 2024 16:46:00 +0900 Subject: [PATCH 03/54] wip: sassInternalImporter --- packages/vite/src/node/plugins/css.ts | 49 +++++++++++++++++++-------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index ea5c7cd9d3a9a3..bb91082c9241ab 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2099,6 +2099,15 @@ const makeScssWorker = ( } } + const modernInternalImporter = async ( + url: string, + importer: string, + ): Promise => { + importer = cleanScssBugUrl(importer) + const resolved = await resolvers.sass(url, importer) + return resolved ?? null + } + type ScssWorkerResult = { css: string map?: string | undefined @@ -2116,7 +2125,7 @@ const makeScssWorker = ( // eslint-disable-next-line no-restricted-globals -- this function runs inside a cjs worker const sass: typeof Sass = require(sassPath) // eslint-disable-next-line no-restricted-globals - const path = require('node:path') + const path: typeof import('node:path') = require('node:path') // https://github.com/vitejs/vite/pull/7170 // https://github.com/vitejs/vite/issues/14689#issuecomment-2095118836 @@ -2124,29 +2133,41 @@ const makeScssWorker = ( // https://github.com/vitejs/vite/issues/14689 // https://github.com/webpack-contrib/sass-loader?tab=readme-ov-file#api if (options.api === 'modern') { - const { fileURLToPath, pathToFileURL } = + const { fileURLToPath, pathToFileURL }: typeof import('node:url') = // eslint-disable-next-line no-restricted-globals - require('node:url') as typeof import('node:url') + require('node:url') + // eslint-disable-next-line no-restricted-globals + const fs: typeof import('node:fs') = require('node:fs') const sassOptions = { ...options } as Sass.StringOptions<'async'> sassOptions.url = pathToFileURL(options.filename) sassOptions.sourceMap = options.enableSourcemap // https://github.com/sass/sass/issues/3247 - const _internalImporter: Sass.Importer<'async'> = { - canonicalize(url, context) { - if (context.containingUrl) { - const importer = fileURLToPath(context.containingUrl) - return internalImporter(url, importer, options.filename) - } - return null + const sassInternalImporter: Sass.Importer<'async'> = { + async canonicalize(url, context) { + const importer = context.containingUrl + ? fileURLToPath(context.containingUrl) + : options.filename + const resolved = await modernInternalImporter(url, importer) + return resolved ? pathToFileURL(resolved) : null }, - load(_canonicalUrl) { - return null + async load(canonicalUrl) { + const ext = path.extname(canonicalUrl.pathname) + let syntax: Sass.Syntax = 'scss' + if (ext && ext.toLowerCase() === '.scss') { + syntax = 'scss' + } else if (ext && ext.toLowerCase() === '.sass') { + syntax = 'indented' + } else if (ext && ext.toLowerCase() === '.css') { + syntax = 'css' + } + const contents = await fs.promises.readFile(canonicalUrl, 'utf-8') + return { contents, syntax } }, } sassOptions.importers ??= [] - sassOptions.importers.push(_internalImporter) + sassOptions.importers.push(sassInternalImporter) const result = await sass.compileStringAsync(data, sassOptions) return { @@ -2207,7 +2228,7 @@ const makeScssWorker = ( }) }, { - parentFunctions: { internalImporter }, + parentFunctions: { internalImporter, modernInternalImporter }, shouldUseFake(_sassPath, _data, options) { // functions and importer is a function and is not serializable // in that case, fallback to running in main thread From e572b9ffdd059e6dcfb2b84f3dd2288212863df9 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 20 Jul 2024 17:57:25 +0900 Subject: [PATCH 04/54] test: add custom importer example --- .../css-sass-modern/custom-importer.scss | 1 + .../import-relative-importee.scss | 3 +++ .../css-sass-modern/import-relative.scss | 1 + playground/css-sass-modern/index.html | 1 + playground/css-sass-modern/main.js | 2 ++ playground/css-sass-modern/vite.config.js | 20 +++++++++++++++++++ 6 files changed, 28 insertions(+) create mode 100644 playground/css-sass-modern/custom-importer.scss create mode 100644 playground/css-sass-modern/import-relative-importee.scss create mode 100644 playground/css-sass-modern/import-relative.scss diff --git a/playground/css-sass-modern/custom-importer.scss b/playground/css-sass-modern/custom-importer.scss new file mode 100644 index 00000000000000..2e5ead7d9e4d61 --- /dev/null +++ b/playground/css-sass-modern/custom-importer.scss @@ -0,0 +1 @@ +@use 'virtual:orange'; diff --git a/playground/css-sass-modern/import-relative-importee.scss b/playground/css-sass-modern/import-relative-importee.scss new file mode 100644 index 00000000000000..04e7110b4142ec --- /dev/null +++ b/playground/css-sass-modern/import-relative-importee.scss @@ -0,0 +1,3 @@ +body { + background-color: pink; +} diff --git a/playground/css-sass-modern/import-relative.scss b/playground/css-sass-modern/import-relative.scss new file mode 100644 index 00000000000000..55a2b514c1a31f --- /dev/null +++ b/playground/css-sass-modern/import-relative.scss @@ -0,0 +1 @@ +@import './import-relative-importee.scss'; diff --git a/playground/css-sass-modern/index.html b/playground/css-sass-modern/index.html index 4dd4295a152bc4..edcf1214918cb3 100644 --- a/playground/css-sass-modern/index.html +++ b/playground/css-sass-modern/index.html @@ -2,6 +2,7 @@

test.scss: orange

test.scss: orange

css-dep: orange

+

custom-importer: orange

diff --git a/playground/css-sass-modern/main.js b/playground/css-sass-modern/main.js index a59ac1916760b1..07d9d1d1d8c968 100644 --- a/playground/css-sass-modern/main.js +++ b/playground/css-sass-modern/main.js @@ -1,3 +1,5 @@ import './test.scss' import './test.sass' import './import.scss' +import './import-relative.scss' +import './custom-importer.scss' diff --git a/playground/css-sass-modern/vite.config.js b/playground/css-sass-modern/vite.config.js index 1a03f1224aeec0..96b49abdb2b1ce 100644 --- a/playground/css-sass-modern/vite.config.js +++ b/playground/css-sass-modern/vite.config.js @@ -6,6 +6,26 @@ export default defineConfig({ scss: { api: 'modern', additionalData: `$injectedColor: orange;`, + importers: [ + // example from https://sass-lang.com/documentation/js-api/interfaces/importer/ + { + /** + * @param {string} url + */ + canonicalize(url) { + return url.startsWith('virtual:') ? new URL(url) : null + }, + /** + * @param {URL} url + */ + load(url) { + return { + contents: `.custom-importer { color: ${url.pathname} }`, + syntax: 'scss', + } + }, + }, + ], }, sass: { api: 'modern', From 6619adeb1ff8981c358e527d80599caf78dcbe6d Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 20 Jul 2024 18:17:38 +0900 Subject: [PATCH 05/54] test: test internal importer --- packages/vite/src/node/plugins/css.ts | 16 ++++++++++------ playground/css-sass-modern/alias-to/import.scss | 1 + .../css-sass-modern/alias-to/importee.scss | 0 playground/css-sass-modern/alias-to/index.scss | 0 playground/css-sass-modern/alias.scss | 2 ++ playground/css-sass-modern/main.js | 1 + playground/css-sass-modern/vite.config.js | 5 +++++ 7 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 playground/css-sass-modern/alias-to/import.scss create mode 100644 playground/css-sass-modern/alias-to/importee.scss create mode 100644 playground/css-sass-modern/alias-to/index.scss create mode 100644 playground/css-sass-modern/alias.scss diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index bb91082c9241ab..cb2ef8acfe61ae 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2176,7 +2176,9 @@ const makeScssWorker = ( ? JSON.stringify(result.sourceMap) : undefined, stats: { - includedFiles: result.loadedUrls.map((url) => fileURLToPath(url)), + includedFiles: result.loadedUrls + .filter((url) => url.protocol === 'file') + .map((url) => fileURLToPath(url)), }, } satisfies ScssWorkerResult } @@ -2232,11 +2234,13 @@ const makeScssWorker = ( shouldUseFake(_sassPath, _data, options) { // functions and importer is a function and is not serializable // in that case, fallback to running in main thread - return !!( - (options.functions && Object.keys(options.functions).length > 0) || - (options.importer && - (!Array.isArray(options.importer) || options.importer.length > 0)) - ) + return !!((options.functions && + Object.keys(options.functions).length > 0) || + (options.importers && + (!Array.isArray(options.importers) || + options.importers.length > 0)), + options.importer && + (!Array.isArray(options.importer) || options.importer.length > 0)) }, max: maxWorkers, }, diff --git a/playground/css-sass-modern/alias-to/import.scss b/playground/css-sass-modern/alias-to/import.scss new file mode 100644 index 00000000000000..6ab1c9d172a99f --- /dev/null +++ b/playground/css-sass-modern/alias-to/import.scss @@ -0,0 +1 @@ +@import './importee.scss'; diff --git a/playground/css-sass-modern/alias-to/importee.scss b/playground/css-sass-modern/alias-to/importee.scss new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/css-sass-modern/alias-to/index.scss b/playground/css-sass-modern/alias-to/index.scss new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/css-sass-modern/alias.scss b/playground/css-sass-modern/alias.scss new file mode 100644 index 00000000000000..950f6d325e47a1 --- /dev/null +++ b/playground/css-sass-modern/alias.scss @@ -0,0 +1,2 @@ +@import 'alias-from'; +@import 'alias-from/import.scss'; diff --git a/playground/css-sass-modern/main.js b/playground/css-sass-modern/main.js index 07d9d1d1d8c968..8c40a0fc76c5c9 100644 --- a/playground/css-sass-modern/main.js +++ b/playground/css-sass-modern/main.js @@ -3,3 +3,4 @@ import './test.sass' import './import.scss' import './import-relative.scss' import './custom-importer.scss' +import './alias.scss' diff --git a/playground/css-sass-modern/vite.config.js b/playground/css-sass-modern/vite.config.js index 96b49abdb2b1ce..d08cbb456daa69 100644 --- a/playground/css-sass-modern/vite.config.js +++ b/playground/css-sass-modern/vite.config.js @@ -1,6 +1,11 @@ import { defineConfig } from 'vite' export default defineConfig({ + resolve: { + alias: { + 'alias-from': 'alias-to', + }, + }, css: { preprocessorOptions: { scss: { From fba1d4d44291a02f00fd21e3ade04f1261e281d5 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 20 Jul 2024 18:50:40 +0900 Subject: [PATCH 06/54] chore: cleanup playground --- playground/css-sass-modern/alias-to/index.scss | 0 playground/css-sass-modern/alias.scss | 3 +-- playground/css-sass-modern/import.scss | 1 + playground/css-sass-modern/nested/import.scss | 5 +++++ playground/css-sass-modern/nested/importee.css | 2 ++ .../css-sass-modern/{alias-to => nested}/importee.scss | 0 .../{alias-to/import.scss => nested/index.scss} | 0 playground/css-sass-modern/vite.config.js | 2 +- 8 files changed, 10 insertions(+), 3 deletions(-) delete mode 100644 playground/css-sass-modern/alias-to/index.scss create mode 100644 playground/css-sass-modern/nested/import.scss create mode 100644 playground/css-sass-modern/nested/importee.css rename playground/css-sass-modern/{alias-to => nested}/importee.scss (100%) rename playground/css-sass-modern/{alias-to/import.scss => nested/index.scss} (100%) diff --git a/playground/css-sass-modern/alias-to/index.scss b/playground/css-sass-modern/alias-to/index.scss deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/playground/css-sass-modern/alias.scss b/playground/css-sass-modern/alias.scss index 950f6d325e47a1..1a8a97c1edb94e 100644 --- a/playground/css-sass-modern/alias.scss +++ b/playground/css-sass-modern/alias.scss @@ -1,2 +1 @@ -@import 'alias-from'; -@import 'alias-from/import.scss'; +@import 'alias-nested'; diff --git a/playground/css-sass-modern/import.scss b/playground/css-sass-modern/import.scss index daf3dc358af6c2..df024d6892b4be 100644 --- a/playground/css-sass-modern/import.scss +++ b/playground/css-sass-modern/import.scss @@ -1 +1,2 @@ @import 'css-dep'; // package w/ sass entry points +@import './nested/import.scss'; diff --git a/playground/css-sass-modern/nested/import.scss b/playground/css-sass-modern/nested/import.scss new file mode 100644 index 00000000000000..3585f9b5bad55d --- /dev/null +++ b/playground/css-sass-modern/nested/import.scss @@ -0,0 +1,5 @@ +@import './importee.scss'; + +// this doesn't work, so we need `rebaseUrls` +// https://github.com/vitejs/vite/pull/7147 +// @import './importee.css'; diff --git a/playground/css-sass-modern/nested/importee.css b/playground/css-sass-modern/nested/importee.css new file mode 100644 index 00000000000000..25fa51c5a8bd9d --- /dev/null +++ b/playground/css-sass-modern/nested/importee.css @@ -0,0 +1,2 @@ +body { +} diff --git a/playground/css-sass-modern/alias-to/importee.scss b/playground/css-sass-modern/nested/importee.scss similarity index 100% rename from playground/css-sass-modern/alias-to/importee.scss rename to playground/css-sass-modern/nested/importee.scss diff --git a/playground/css-sass-modern/alias-to/import.scss b/playground/css-sass-modern/nested/index.scss similarity index 100% rename from playground/css-sass-modern/alias-to/import.scss rename to playground/css-sass-modern/nested/index.scss diff --git a/playground/css-sass-modern/vite.config.js b/playground/css-sass-modern/vite.config.js index d08cbb456daa69..409dbe93760594 100644 --- a/playground/css-sass-modern/vite.config.js +++ b/playground/css-sass-modern/vite.config.js @@ -3,7 +3,7 @@ import { defineConfig } from 'vite' export default defineConfig({ resolve: { alias: { - 'alias-from': 'alias-to', + 'alias-nested': 'nested', }, }, css: { From cbfe70d1cb183231aee631a6b5a4f0d7d0a8d263 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 20 Jul 2024 19:05:34 +0900 Subject: [PATCH 07/54] wip: rebaseUrls --- packages/vite/src/node/plugins/css.ts | 37 +++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index cb2ef8acfe61ae..46486967c4ed99 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2108,6 +2108,14 @@ const makeScssWorker = ( return resolved ?? null } + const modernInternalLoad = async (file: string, rootFile: string) => { + const result = await rebaseUrls(file, rootFile, alias, '$', resolvers.sass) + if (result.contents) { + return result.contents + } + return await fs.promises.readFile(result.file, 'utf-8') + } + type ScssWorkerResult = { css: string map?: string | undefined @@ -2136,8 +2144,8 @@ const makeScssWorker = ( const { fileURLToPath, pathToFileURL }: typeof import('node:url') = // eslint-disable-next-line no-restricted-globals require('node:url') - // eslint-disable-next-line no-restricted-globals - const fs: typeof import('node:fs') = require('node:fs') + + // const fs: typeof import('node:fs') = require('node:fs') const sassOptions = { ...options } as Sass.StringOptions<'async'> sassOptions.url = pathToFileURL(options.filename) @@ -2146,6 +2154,7 @@ const makeScssWorker = ( // https://github.com/sass/sass/issues/3247 const sassInternalImporter: Sass.Importer<'async'> = { async canonicalize(url, context) { + // console.log("[canonicalize]", url, context.containingUrl?.href); const importer = context.containingUrl ? fileURLToPath(context.containingUrl) : options.filename @@ -2162,7 +2171,10 @@ const makeScssWorker = ( } else if (ext && ext.toLowerCase() === '.css') { syntax = 'css' } - const contents = await fs.promises.readFile(canonicalUrl, 'utf-8') + const contents = await modernInternalLoad( + fileURLToPath(canonicalUrl), + options.filename, + ) return { contents, syntax } }, } @@ -2230,17 +2242,22 @@ const makeScssWorker = ( }) }, { - parentFunctions: { internalImporter, modernInternalImporter }, + parentFunctions: { + internalImporter, + modernInternalImporter, + modernInternalLoad, + }, shouldUseFake(_sassPath, _data, options) { // functions and importer is a function and is not serializable // in that case, fallback to running in main thread - return !!((options.functions && - Object.keys(options.functions).length > 0) || + return !!( + (options.functions && Object.keys(options.functions).length > 0) || (options.importers && (!Array.isArray(options.importers) || - options.importers.length > 0)), - options.importer && - (!Array.isArray(options.importer) || options.importer.length > 0)) + options.importers.length > 0)) || + (options.importer && + (!Array.isArray(options.importer) || options.importer.length > 0)) + ) }, max: maxWorkers, }, @@ -2320,7 +2337,7 @@ async function rebaseUrls( alias: Alias[], variablePrefix: string, resolver: ResolveFn, -): Promise { +): Promise<{ file: string; contents?: string }> { file = path.resolve(file) // ensure os-specific flashes // in the same dir, no need to rebase const fileDir = path.dirname(file) From b515950f7070912264f6d6dc3bf0bffbe4bdce71 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 14:50:54 +0900 Subject: [PATCH 08/54] test: test "modern" in playground/css --- playground/css/vite.config.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/playground/css/vite.config.js b/playground/css/vite.config.js index 5ac9d448a2734a..7946ff547504dd 100644 --- a/playground/css/vite.config.js +++ b/playground/css/vite.config.js @@ -60,13 +60,21 @@ export default defineConfig({ }, preprocessorOptions: { scss: { + api: 'modern', additionalData: `$injectedColor: orange;`, - importer: [ - function (url) { - return url === 'virtual-dep' ? { contents: '' } : null - }, - function (url) { - return url.endsWith('.wxss') ? { contents: '' } : null + importers: [ + { + canonicalize(url) { + return url === 'virtual-dep' + ? new URL('custom-importer:virtual-dep') + : null + }, + load() { + return { + contents: ``, + syntax: 'scss', + } + }, }, ], }, From f04f067bf84eccd228a4777bd3c4e4cdc28b2a62 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 15:00:08 +0900 Subject: [PATCH 09/54] chore: cleanup --- packages/vite/src/node/plugins/css.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 46486967c4ed99..38f31de752cdb5 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2135,18 +2135,14 @@ const makeScssWorker = ( // eslint-disable-next-line no-restricted-globals const path: typeof import('node:path') = require('node:path') + // thanks to // https://github.com/vitejs/vite/pull/7170 // https://github.com/vitejs/vite/issues/14689#issuecomment-2095118836 - // TODO: modern-compiler? - // https://github.com/vitejs/vite/issues/14689 - // https://github.com/webpack-contrib/sass-loader?tab=readme-ov-file#api if (options.api === 'modern') { const { fileURLToPath, pathToFileURL }: typeof import('node:url') = // eslint-disable-next-line no-restricted-globals require('node:url') - // const fs: typeof import('node:fs') = require('node:fs') - const sassOptions = { ...options } as Sass.StringOptions<'async'> sassOptions.url = pathToFileURL(options.filename) sassOptions.sourceMap = options.enableSourcemap @@ -2164,9 +2160,7 @@ const makeScssWorker = ( async load(canonicalUrl) { const ext = path.extname(canonicalUrl.pathname) let syntax: Sass.Syntax = 'scss' - if (ext && ext.toLowerCase() === '.scss') { - syntax = 'scss' - } else if (ext && ext.toLowerCase() === '.sass') { + if (ext && ext.toLowerCase() === '.sass') { syntax = 'indented' } else if (ext && ext.toLowerCase() === '.css') { syntax = 'css' @@ -2182,6 +2176,7 @@ const makeScssWorker = ( sassOptions.importers.push(sassInternalImporter) const result = await sass.compileStringAsync(data, sassOptions) + console.log("[compileStringAsync]", options.filename, result.loadedUrls.map(url => url.href)); return { css: result.css, map: result.sourceMap From f8154b1241a9b08c30a0ebc5c475110ede76f0b0 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 15:01:48 +0900 Subject: [PATCH 10/54] debug --- playground/css/vite.config.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/playground/css/vite.config.js b/playground/css/vite.config.js index 7946ff547504dd..11f4495ac87d0a 100644 --- a/playground/css/vite.config.js +++ b/playground/css/vite.config.js @@ -62,6 +62,16 @@ export default defineConfig({ scss: { api: 'modern', additionalData: `$injectedColor: orange;`, + // for api: "legacy" + // importer: [ + // function (url) { + // return url === 'virtual-dep' ? { contents: '' } : null + // }, + // function (url) { + // return url.endsWith('.wxss') ? { contents: '' } : null + // } + // ], + // for api: "modern" importers: [ { canonicalize(url) { From 1d5ce19af649d74d88c5122f173c099e8bf697df Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 15:09:48 +0900 Subject: [PATCH 11/54] fix: fix stats.includedFiles --- packages/vite/src/node/plugins/css.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 38f31de752cdb5..67e30d111b0c75 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2176,7 +2176,6 @@ const makeScssWorker = ( sassOptions.importers.push(sassInternalImporter) const result = await sass.compileStringAsync(data, sassOptions) - console.log("[compileStringAsync]", options.filename, result.loadedUrls.map(url => url.href)); return { css: result.css, map: result.sourceMap @@ -2184,7 +2183,7 @@ const makeScssWorker = ( : undefined, stats: { includedFiles: result.loadedUrls - .filter((url) => url.protocol === 'file') + .filter((url) => url.protocol === 'file:') .map((url) => fileURLToPath(url)), }, } satisfies ScssWorkerResult @@ -2227,6 +2226,7 @@ const makeScssWorker = ( if (err) { reject(err) } else { + console.log("[includedFiles]", options.filename, [...res!.stats.includedFiles]); resolve({ css: res!.css.toString(), map: res!.map?.toString(), From af7e6dc968805c396407b081c2520368f75a1d38 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 15:12:59 +0900 Subject: [PATCH 12/54] chore: cleanup --- packages/vite/src/node/plugins/css.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 67e30d111b0c75..1f3b8774f220a3 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2110,10 +2110,7 @@ const makeScssWorker = ( const modernInternalLoad = async (file: string, rootFile: string) => { const result = await rebaseUrls(file, rootFile, alias, '$', resolvers.sass) - if (result.contents) { - return result.contents - } - return await fs.promises.readFile(result.file, 'utf-8') + return result.contents ?? (await fs.promises.readFile(result.file, 'utf-8')) } type ScssWorkerResult = { @@ -2150,7 +2147,6 @@ const makeScssWorker = ( // https://github.com/sass/sass/issues/3247 const sassInternalImporter: Sass.Importer<'async'> = { async canonicalize(url, context) { - // console.log("[canonicalize]", url, context.containingUrl?.href); const importer = context.containingUrl ? fileURLToPath(context.containingUrl) : options.filename @@ -2226,7 +2222,6 @@ const makeScssWorker = ( if (err) { reject(err) } else { - console.log("[includedFiles]", options.filename, [...res!.stats.includedFiles]); resolve({ css: res!.css.toString(), map: res!.map?.toString(), From 659cd97a5eb6ce653fb70a210c5c377c5bf4c5c6 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 15:58:58 +0900 Subject: [PATCH 13/54] chore: remove playground/css-sass-modern --- playground/css-sass-modern/alias.scss | 1 - playground/css-sass-modern/css-dep/index.scss | 3 -- .../css-sass-modern/css-dep/package.json | 8 ---- .../css-sass-modern/custom-importer.scss | 1 - .../import-relative-importee.scss | 3 -- .../css-sass-modern/import-relative.scss | 1 - playground/css-sass-modern/import.scss | 2 - playground/css-sass-modern/index.html | 8 ---- playground/css-sass-modern/main.js | 6 --- playground/css-sass-modern/nested/import.scss | 5 --- .../css-sass-modern/nested/importee.css | 2 - .../css-sass-modern/nested/importee.scss | 0 playground/css-sass-modern/nested/index.scss | 1 - playground/css-sass-modern/package.json | 15 ------- playground/css-sass-modern/test.sass | 2 - playground/css-sass-modern/test.scss | 4 -- playground/css-sass-modern/vite.config.js | 41 ------------------- 17 files changed, 103 deletions(-) delete mode 100644 playground/css-sass-modern/alias.scss delete mode 100644 playground/css-sass-modern/css-dep/index.scss delete mode 100644 playground/css-sass-modern/css-dep/package.json delete mode 100644 playground/css-sass-modern/custom-importer.scss delete mode 100644 playground/css-sass-modern/import-relative-importee.scss delete mode 100644 playground/css-sass-modern/import-relative.scss delete mode 100644 playground/css-sass-modern/import.scss delete mode 100644 playground/css-sass-modern/index.html delete mode 100644 playground/css-sass-modern/main.js delete mode 100644 playground/css-sass-modern/nested/import.scss delete mode 100644 playground/css-sass-modern/nested/importee.css delete mode 100644 playground/css-sass-modern/nested/importee.scss delete mode 100644 playground/css-sass-modern/nested/index.scss delete mode 100644 playground/css-sass-modern/package.json delete mode 100644 playground/css-sass-modern/test.sass delete mode 100644 playground/css-sass-modern/test.scss delete mode 100644 playground/css-sass-modern/vite.config.js diff --git a/playground/css-sass-modern/alias.scss b/playground/css-sass-modern/alias.scss deleted file mode 100644 index 1a8a97c1edb94e..00000000000000 --- a/playground/css-sass-modern/alias.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'alias-nested'; diff --git a/playground/css-sass-modern/css-dep/index.scss b/playground/css-sass-modern/css-dep/index.scss deleted file mode 100644 index 97a24aa0551eb9..00000000000000 --- a/playground/css-sass-modern/css-dep/index.scss +++ /dev/null @@ -1,3 +0,0 @@ -.css-dep-sass { - color: orange; -} diff --git a/playground/css-sass-modern/css-dep/package.json b/playground/css-sass-modern/css-dep/package.json deleted file mode 100644 index 204e8c71b0ebba..00000000000000 --- a/playground/css-sass-modern/css-dep/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@vitejs/test-css-dep", - "private": true, - "version": "1.0.0", - "main": "index.js", - "style": "index.css", - "sass": "index.scss" -} diff --git a/playground/css-sass-modern/custom-importer.scss b/playground/css-sass-modern/custom-importer.scss deleted file mode 100644 index 2e5ead7d9e4d61..00000000000000 --- a/playground/css-sass-modern/custom-importer.scss +++ /dev/null @@ -1 +0,0 @@ -@use 'virtual:orange'; diff --git a/playground/css-sass-modern/import-relative-importee.scss b/playground/css-sass-modern/import-relative-importee.scss deleted file mode 100644 index 04e7110b4142ec..00000000000000 --- a/playground/css-sass-modern/import-relative-importee.scss +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: pink; -} diff --git a/playground/css-sass-modern/import-relative.scss b/playground/css-sass-modern/import-relative.scss deleted file mode 100644 index 55a2b514c1a31f..00000000000000 --- a/playground/css-sass-modern/import-relative.scss +++ /dev/null @@ -1 +0,0 @@ -@import './import-relative-importee.scss'; diff --git a/playground/css-sass-modern/import.scss b/playground/css-sass-modern/import.scss deleted file mode 100644 index df024d6892b4be..00000000000000 --- a/playground/css-sass-modern/import.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'css-dep'; // package w/ sass entry points -@import './nested/import.scss'; diff --git a/playground/css-sass-modern/index.html b/playground/css-sass-modern/index.html deleted file mode 100644 index edcf1214918cb3..00000000000000 --- a/playground/css-sass-modern/index.html +++ /dev/null @@ -1,8 +0,0 @@ -
-

test.scss: orange

-

test.scss: orange

-

css-dep: orange

-

custom-importer: orange

-
- - diff --git a/playground/css-sass-modern/main.js b/playground/css-sass-modern/main.js deleted file mode 100644 index 8c40a0fc76c5c9..00000000000000 --- a/playground/css-sass-modern/main.js +++ /dev/null @@ -1,6 +0,0 @@ -import './test.scss' -import './test.sass' -import './import.scss' -import './import-relative.scss' -import './custom-importer.scss' -import './alias.scss' diff --git a/playground/css-sass-modern/nested/import.scss b/playground/css-sass-modern/nested/import.scss deleted file mode 100644 index 3585f9b5bad55d..00000000000000 --- a/playground/css-sass-modern/nested/import.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import './importee.scss'; - -// this doesn't work, so we need `rebaseUrls` -// https://github.com/vitejs/vite/pull/7147 -// @import './importee.css'; diff --git a/playground/css-sass-modern/nested/importee.css b/playground/css-sass-modern/nested/importee.css deleted file mode 100644 index 25fa51c5a8bd9d..00000000000000 --- a/playground/css-sass-modern/nested/importee.css +++ /dev/null @@ -1,2 +0,0 @@ -body { -} diff --git a/playground/css-sass-modern/nested/importee.scss b/playground/css-sass-modern/nested/importee.scss deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/playground/css-sass-modern/nested/index.scss b/playground/css-sass-modern/nested/index.scss deleted file mode 100644 index 6ab1c9d172a99f..00000000000000 --- a/playground/css-sass-modern/nested/index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './importee.scss'; diff --git a/playground/css-sass-modern/package.json b/playground/css-sass-modern/package.json deleted file mode 100644 index 8e19cbaae6957d..00000000000000 --- a/playground/css-sass-modern/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@vitejs/test-css-sass-modern", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "debug": "node --inspect-brk ../../packages/vite/bin/vite", - "preview": "vite preview" - }, - "devDependencies": { - "@vitejs/test-css-dep": "link:./css-dep" - } -} diff --git a/playground/css-sass-modern/test.sass b/playground/css-sass-modern/test.sass deleted file mode 100644 index 12b85b2e17ad94..00000000000000 --- a/playground/css-sass-modern/test.sass +++ /dev/null @@ -1,2 +0,0 @@ -.test-sass - color: $injectedColor diff --git a/playground/css-sass-modern/test.scss b/playground/css-sass-modern/test.scss deleted file mode 100644 index 49ab0b73235508..00000000000000 --- a/playground/css-sass-modern/test.scss +++ /dev/null @@ -1,4 +0,0 @@ -.test-scss { - /* injected via vite.config.js */ - color: $injectedColor; -} diff --git a/playground/css-sass-modern/vite.config.js b/playground/css-sass-modern/vite.config.js deleted file mode 100644 index 409dbe93760594..00000000000000 --- a/playground/css-sass-modern/vite.config.js +++ /dev/null @@ -1,41 +0,0 @@ -import { defineConfig } from 'vite' - -export default defineConfig({ - resolve: { - alias: { - 'alias-nested': 'nested', - }, - }, - css: { - preprocessorOptions: { - scss: { - api: 'modern', - additionalData: `$injectedColor: orange;`, - importers: [ - // example from https://sass-lang.com/documentation/js-api/interfaces/importer/ - { - /** - * @param {string} url - */ - canonicalize(url) { - return url.startsWith('virtual:') ? new URL(url) : null - }, - /** - * @param {URL} url - */ - load(url) { - return { - contents: `.custom-importer { color: ${url.pathname} }`, - syntax: 'scss', - } - }, - }, - ], - }, - sass: { - api: 'modern', - additionalData: `$injectedColor: orange\n`, - }, - }, - }, -}) From 84840259a57a8356c60863325d44bc8f31522b2a Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 15:59:18 +0900 Subject: [PATCH 14/54] chore: lockfile --- pnpm-lock.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bf587b5323d73..62131352ec51e9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -597,14 +597,6 @@ importers: playground/css-no-codesplit: {} - playground/css-sass-modern: - devDependencies: - '@vitejs/test-css-dep': - specifier: link:./css-dep - version: link:css-dep - - playground/css-sass-modern/css-dep: {} - playground/css-sourcemap: devDependencies: less: From 073392b5f0218def7924955f05af42b4d0daac97 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 16:39:13 +0900 Subject: [PATCH 15/54] docs: update css.preprocessorOptions --- docs/config/shared-options.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/config/shared-options.md b/docs/config/shared-options.md index 19eb96e0f74439..fa3ccba14128aa 100644 --- a/docs/config/shared-options.md +++ b/docs/config/shared-options.md @@ -225,7 +225,7 @@ Note if an inline config is provided, Vite will not search for other PostCSS con Specify options to pass to CSS pre-processors. The file extensions are used as keys for the options. The supported options for each preprocessors can be found in their respective documentation: -- `sass`/`scss` - [Options](https://sass-lang.com/documentation/js-api/interfaces/LegacyStringOptions). +- `sass`/`scss` - top level option `api: "legacy" | "modern"` (default `"legacy"`) allows switching which sass API to use. [Options (legacy)](https://sass-lang.com/documentation/js-api/interfaces/LegacyStringOptions), [Options (modern)](https://sass-lang.com/documentation/js-api/interfaces/stringoptions/). - `less` - [Options](https://lesscss.org/usage/#less-options). - `styl`/`stylus` - Only [`define`](https://stylus-lang.com/docs/js.html#define-name-node) is supported, which can be passed as an object. @@ -243,6 +243,12 @@ export default defineConfig({ $specialColor: new stylus.nodes.RGBA(51, 197, 255, 1), }, }, + scss: { + api: 'modern', // or "legacy" + importers: [ + // ... + ], + }, }, }, }) From b0dac1769b82845b607499ebc0e7214df5163bcb Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 16:40:36 +0900 Subject: [PATCH 16/54] chore: comment --- packages/vite/src/node/plugins/css.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 1f3b8774f220a3..e6a066feb155bb 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2132,9 +2132,6 @@ const makeScssWorker = ( // eslint-disable-next-line no-restricted-globals const path: typeof import('node:path') = require('node:path') - // thanks to - // https://github.com/vitejs/vite/pull/7170 - // https://github.com/vitejs/vite/issues/14689#issuecomment-2095118836 if (options.api === 'modern') { const { fileURLToPath, pathToFileURL }: typeof import('node:url') = // eslint-disable-next-line no-restricted-globals @@ -2144,7 +2141,6 @@ const makeScssWorker = ( sassOptions.url = pathToFileURL(options.filename) sassOptions.sourceMap = options.enableSourcemap - // https://github.com/sass/sass/issues/3247 const sassInternalImporter: Sass.Importer<'async'> = { async canonicalize(url, context) { const importer = context.containingUrl From 61bc1700f20f84cc5e994765e30bc703f750a53a Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 21 Jul 2024 17:05:53 +0900 Subject: [PATCH 17/54] chore: tweak --- packages/vite/src/node/plugins/css.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index e6a066feb155bb..c47825a1163525 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2164,8 +2164,10 @@ const makeScssWorker = ( return { contents, syntax } }, } - sassOptions.importers ??= [] - sassOptions.importers.push(sassInternalImporter) + sassOptions.importers = [ + ...(sassOptions.importers ?? []), + sassInternalImporter, + ] const result = await sass.compileStringAsync(data, sassOptions) return { From 1ff2110dce62ad120a0c6995aac254b0b9289bc9 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 13:11:44 +0900 Subject: [PATCH 18/54] refactor: move to makeModernScssWorker --- packages/vite/src/node/plugins/css.ts | 112 +++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index c47825a1163525..b1c966bbafa795 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2253,6 +2253,114 @@ const makeScssWorker = ( return worker } +const makeModernScssWorker = ( + resolvers: CSSAtImportResolvers, + alias: Alias[], + maxWorkers: number | undefined, +) => { + const internalCanonicalize = async ( + url: string, + importer: string, + ): Promise => { + importer = cleanScssBugUrl(importer) + const resolved = await resolvers.sass(url, importer) + return resolved ?? null + } + + const internalLoad = async (file: string, rootFile: string) => { + const result = await rebaseUrls(file, rootFile, alias, '$', resolvers.sass) + if (result.contents) { + return result.contents + } + return await fs.promises.readFile(result.file, 'utf-8') + } + + const worker = new WorkerWithFallback( + () => + async ( + sassPath: string, + data: string, + // additionalData can a function that is not cloneable but it won't be used + options: SassStylePreprocessorOptions & { additionalData: undefined }, + ) => { + // eslint-disable-next-line no-restricted-globals -- this function runs inside a cjs worker + const sass: typeof Sass = require(sassPath) + // eslint-disable-next-line no-restricted-globals + const path: typeof import('node:path') = require('node:path') + + const { fileURLToPath, pathToFileURL }: typeof import('node:url') = + // eslint-disable-next-line no-restricted-globals + require('node:url') + + const sassOptions = { ...options } as Sass.StringOptions<'async'> + sassOptions.url = pathToFileURL(options.filename) + sassOptions.sourceMap = options.enableSourcemap + + const internalImporter: Sass.Importer<'async'> = { + async canonicalize(url, context) { + const importer = context.containingUrl + ? fileURLToPath(context.containingUrl) + : options.filename + const resolved = await internalCanonicalize(url, importer) + return resolved ? pathToFileURL(resolved) : null + }, + async load(canonicalUrl) { + const ext = path.extname(canonicalUrl.pathname) + let syntax: Sass.Syntax = 'scss' + if (ext && ext.toLowerCase() === '.sass') { + syntax = 'indented' + } else if (ext && ext.toLowerCase() === '.css') { + syntax = 'css' + } + const contents = await internalLoad( + fileURLToPath(canonicalUrl), + options.filename, + ) + return { contents, syntax } + }, + } + sassOptions.importers = [ + ...(sassOptions.importers ?? []), + internalImporter, + ] + + const result = await sass.compileStringAsync(data, sassOptions) + return { + css: result.css, + map: result.sourceMap ? JSON.stringify(result.sourceMap) : undefined, + stats: { + includedFiles: result.loadedUrls + .filter((url) => url.protocol === 'file:') + .map((url) => fileURLToPath(url)), + }, + } satisfies ScssWorkerResult + }, + { + parentFunctions: { + internalCanonicalize, + internalLoad, + }, + shouldUseFake(_sassPath, _data, options) { + // functions and importer is a function and is not serializable + // in that case, fallback to running in main thread + return !!( + (options.functions && Object.keys(options.functions).length > 0) || + (options.importers && + (!Array.isArray(options.importers) || options.importers.length > 0)) + ) + }, + max: maxWorkers, + }, + ) + return worker +} + +type ScssWorkerResult = { + css: string + map?: string | undefined + stats: Pick +} + const scssProcessor = ( maxWorkers: number | undefined, ): SassStylePreprocessor => { @@ -2270,7 +2378,9 @@ const scssProcessor = ( if (!workerMap.has(options.alias)) { workerMap.set( options.alias, - makeScssWorker(resolvers, options.alias, maxWorkers), + options.api === 'modern' + ? makeModernScssWorker(resolvers, options.alias, maxWorkers) + : makeScssWorker(resolvers, options.alias, maxWorkers), ) } const worker = workerMap.get(options.alias)! From e930f1dca4aa57100489173905a28d465e67aea7 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 13:13:21 +0900 Subject: [PATCH 19/54] chore: USE_LEGACY_SCSS flag in playground/css --- playground/css/vite.config.js | 58 ++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/playground/css/vite.config.js b/playground/css/vite.config.js index 11f4495ac87d0a..ab538cb0eebe1d 100644 --- a/playground/css/vite.config.js +++ b/playground/css/vite.config.js @@ -59,35 +59,37 @@ export default defineConfig({ // }, }, preprocessorOptions: { - scss: { - api: 'modern', - additionalData: `$injectedColor: orange;`, - // for api: "legacy" - // importer: [ - // function (url) { - // return url === 'virtual-dep' ? { contents: '' } : null - // }, - // function (url) { - // return url.endsWith('.wxss') ? { contents: '' } : null - // } - // ], - // for api: "modern" - importers: [ - { - canonicalize(url) { - return url === 'virtual-dep' - ? new URL('custom-importer:virtual-dep') - : null - }, - load() { - return { - contents: ``, - syntax: 'scss', - } - }, + scss: process.env['USE_LEGACY_SCSS'] + ? { + additionalData: `$injectedColor: orange;`, + importer: [ + function (url) { + return url === 'virtual-dep' ? { contents: '' } : null + }, + function (url) { + return url.endsWith('.wxss') ? { contents: '' } : null + }, + ], + } + : { + api: 'modern', + additionalData: `$injectedColor: orange;`, + importers: [ + { + canonicalize(url) { + return url === 'virtual-dep' + ? new URL('custom-importer:virtual-dep') + : null + }, + load() { + return { + contents: ``, + syntax: 'scss', + } + }, + }, + ], }, - ], - }, styl: { additionalData: `$injectedColor ?= orange`, imports: [ From 098f1812301160d5df5ec097f11113f8dea805d6 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 13:15:16 +0900 Subject: [PATCH 20/54] chore: cleanup old code --- packages/vite/src/node/plugins/css.ts | 80 +-------------------------- 1 file changed, 1 insertion(+), 79 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index b1c966bbafa795..4fa172837000cc 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2099,26 +2099,6 @@ const makeScssWorker = ( } } - const modernInternalImporter = async ( - url: string, - importer: string, - ): Promise => { - importer = cleanScssBugUrl(importer) - const resolved = await resolvers.sass(url, importer) - return resolved ?? null - } - - const modernInternalLoad = async (file: string, rootFile: string) => { - const result = await rebaseUrls(file, rootFile, alias, '$', resolvers.sass) - return result.contents ?? (await fs.promises.readFile(result.file, 'utf-8')) - } - - type ScssWorkerResult = { - css: string - map?: string | undefined - stats: Pick - } - const worker = new WorkerWithFallback( () => async ( @@ -2132,57 +2112,6 @@ const makeScssWorker = ( // eslint-disable-next-line no-restricted-globals const path: typeof import('node:path') = require('node:path') - if (options.api === 'modern') { - const { fileURLToPath, pathToFileURL }: typeof import('node:url') = - // eslint-disable-next-line no-restricted-globals - require('node:url') - - const sassOptions = { ...options } as Sass.StringOptions<'async'> - sassOptions.url = pathToFileURL(options.filename) - sassOptions.sourceMap = options.enableSourcemap - - const sassInternalImporter: Sass.Importer<'async'> = { - async canonicalize(url, context) { - const importer = context.containingUrl - ? fileURLToPath(context.containingUrl) - : options.filename - const resolved = await modernInternalImporter(url, importer) - return resolved ? pathToFileURL(resolved) : null - }, - async load(canonicalUrl) { - const ext = path.extname(canonicalUrl.pathname) - let syntax: Sass.Syntax = 'scss' - if (ext && ext.toLowerCase() === '.sass') { - syntax = 'indented' - } else if (ext && ext.toLowerCase() === '.css') { - syntax = 'css' - } - const contents = await modernInternalLoad( - fileURLToPath(canonicalUrl), - options.filename, - ) - return { contents, syntax } - }, - } - sassOptions.importers = [ - ...(sassOptions.importers ?? []), - sassInternalImporter, - ] - - const result = await sass.compileStringAsync(data, sassOptions) - return { - css: result.css, - map: result.sourceMap - ? JSON.stringify(result.sourceMap) - : undefined, - stats: { - includedFiles: result.loadedUrls - .filter((url) => url.protocol === 'file:') - .map((url) => fileURLToPath(url)), - }, - } satisfies ScssWorkerResult - } - // NOTE: `sass` always runs it's own importer first, and only falls back to // the `importer` option when it can't resolve a path const _internalImporter: Sass.LegacyAsyncImporter = ( @@ -2230,19 +2159,12 @@ const makeScssWorker = ( }) }, { - parentFunctions: { - internalImporter, - modernInternalImporter, - modernInternalLoad, - }, + parentFunctions: { internalImporter }, shouldUseFake(_sassPath, _data, options) { // functions and importer is a function and is not serializable // in that case, fallback to running in main thread return !!( (options.functions && Object.keys(options.functions).length > 0) || - (options.importers && - (!Array.isArray(options.importers) || - options.importers.length > 0)) || (options.importer && (!Array.isArray(options.importer) || options.importer.length > 0)) ) From 96a7336a6e7181f9aafd0a33731df30cece8270d Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 14:03:47 +0900 Subject: [PATCH 21/54] ci: test sass legacy --- .github/workflows/ci.yml | 12 ++++++++++++ playground/css/vite.config.js | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3dbc59fe388e05..51e5f0c52001f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,6 +126,18 @@ jobs: if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run test-build + - name: Test serve (sass legacy) + if: steps.changed-files.outputs.only_changed != 'true' + run: pnpm run test-serve playground/css + env: + TEST_SASS_LEGACY: 1 + + - name: Test build (sass legacy) + if: steps.changed-files.outputs.only_changed != 'true' + run: pnpm run test-build playground/css + env: + TEST_SASS_LEGACY: 1 + lint: timeout-minutes: 10 runs-on: ubuntu-latest diff --git a/playground/css/vite.config.js b/playground/css/vite.config.js index ab538cb0eebe1d..df99022acfdb9f 100644 --- a/playground/css/vite.config.js +++ b/playground/css/vite.config.js @@ -59,7 +59,7 @@ export default defineConfig({ // }, }, preprocessorOptions: { - scss: process.env['USE_LEGACY_SCSS'] + scss: process.env['TEST_SASS_LEGACY'] ? { additionalData: `$injectedColor: orange;`, importer: [ From c2a6256cb51d54165ff20d43ad169871592996cf Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 14:07:55 +0900 Subject: [PATCH 22/54] ci: filter more --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51e5f0c52001f4..6906128e9b7b2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,13 +128,13 @@ jobs: - name: Test serve (sass legacy) if: steps.changed-files.outputs.only_changed != 'true' - run: pnpm run test-serve playground/css + run: pnpm run test-serve playground/css/ env: TEST_SASS_LEGACY: 1 - name: Test build (sass legacy) if: steps.changed-files.outputs.only_changed != 'true' - run: pnpm run test-build playground/css + run: pnpm run test-build playground/css/ env: TEST_SASS_LEGACY: 1 From 35bf91ac744a92076a12537b91fdf8c3b9e780db Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 14:45:55 +0900 Subject: [PATCH 23/54] test: split vite config --- .../__tests__/sass-modern/sass-modern.spec.ts | 1 + playground/css/vite.config-sass-modern.js | 31 ++++++++++++++ playground/css/vite.config.js | 41 +++++-------------- 3 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 playground/css/__tests__/sass-modern/sass-modern.spec.ts create mode 100644 playground/css/vite.config-sass-modern.js diff --git a/playground/css/__tests__/sass-modern/sass-modern.spec.ts b/playground/css/__tests__/sass-modern/sass-modern.spec.ts new file mode 100644 index 00000000000000..90a9b9774d3ebc --- /dev/null +++ b/playground/css/__tests__/sass-modern/sass-modern.spec.ts @@ -0,0 +1 @@ +import '../css.spec' diff --git a/playground/css/vite.config-sass-modern.js b/playground/css/vite.config-sass-modern.js new file mode 100644 index 00000000000000..9f7acb3a098179 --- /dev/null +++ b/playground/css/vite.config-sass-modern.js @@ -0,0 +1,31 @@ +import { defineConfig } from 'vite' +import baseConfig from './vite.config.js' + +export default defineConfig({ + ...baseConfig, + css: { + ...baseConfig.css, + preprocessorOptions: { + ...baseConfig.css.preprocessorOptions, + scss: { + api: 'modern', + additionalData: `$injectedColor: orange;`, + importers: [ + { + canonicalize(url) { + return url === 'virtual-dep' + ? new URL('custom-importer:virtual-dep') + : null + }, + load() { + return { + contents: ``, + syntax: 'scss', + } + }, + }, + ], + }, + }, + }, +}) diff --git a/playground/css/vite.config.js b/playground/css/vite.config.js index df99022acfdb9f..aeea1fd08a92a6 100644 --- a/playground/css/vite.config.js +++ b/playground/css/vite.config.js @@ -59,37 +59,18 @@ export default defineConfig({ // }, }, preprocessorOptions: { - scss: process.env['TEST_SASS_LEGACY'] - ? { - additionalData: `$injectedColor: orange;`, - importer: [ - function (url) { - return url === 'virtual-dep' ? { contents: '' } : null - }, - function (url) { - return url.endsWith('.wxss') ? { contents: '' } : null - }, - ], - } - : { - api: 'modern', - additionalData: `$injectedColor: orange;`, - importers: [ - { - canonicalize(url) { - return url === 'virtual-dep' - ? new URL('custom-importer:virtual-dep') - : null - }, - load() { - return { - contents: ``, - syntax: 'scss', - } - }, - }, - ], + scss: { + additionalData: `$injectedColor: orange;`, + importer: [ + function (url) { + console.log('[importer]', { url }) + return url === 'virtual-dep' ? { contents: '' } : null + }, + function (url) { + return url.endsWith('.wxss') ? { contents: '' } : null }, + ], + }, styl: { additionalData: `$injectedColor ?= orange`, imports: [ From a9a7038ed4efee1f86cef2d942f421dedee3120f Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 14:53:21 +0900 Subject: [PATCH 24/54] chore: no console --- playground/css/vite.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/playground/css/vite.config.js b/playground/css/vite.config.js index aeea1fd08a92a6..5ac9d448a2734a 100644 --- a/playground/css/vite.config.js +++ b/playground/css/vite.config.js @@ -63,7 +63,6 @@ export default defineConfig({ additionalData: `$injectedColor: orange;`, importer: [ function (url) { - console.log('[importer]', { url }) return url === 'virtual-dep' ? { contents: '' } : null }, function (url) { From ddd3c14f337c27420b4b0e09b54b6bd0599e400b Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 16:20:11 +0900 Subject: [PATCH 25/54] test: separate `testDir` for variant tests --- playground/vitestGlobalSetup.ts | 12 ++++++++++++ playground/vitestSetup.ts | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/playground/vitestGlobalSetup.ts b/playground/vitestGlobalSetup.ts index 3a8288ab34ba57..ba8b835479ca08 100644 --- a/playground/vitestGlobalSetup.ts +++ b/playground/vitestGlobalSetup.ts @@ -40,6 +40,18 @@ export async function setup({ provide }: GlobalSetupContext): Promise { throw error } }) + // also setup dedicated copy for "variant" tests + await fs.copy( + path.resolve(__dirname, '../playground/css'), + path.resolve(tempDir, 'css__sass-modern'), + { + dereference: false, + filter(file) { + file = file.replace(/\\/g, '/') + return !file.includes('__tests__') && !/dist(?:\/|$)/.test(file) + }, + }, + ) } export async function teardown(): Promise { diff --git a/playground/vitestSetup.ts b/playground/vitestSetup.ts index ff2303dc498569..ea6b8742e6afab 100644 --- a/playground/vitestSetup.ts +++ b/playground/vitestSetup.ts @@ -136,6 +136,15 @@ beforeAll(async (s) => { const testCustomRoot = resolve(testDir, 'root') rootDir = fs.existsSync(testCustomRoot) ? testCustomRoot : testDir + // separate rootDir for variant + const variantName = path.basename(dirname(testPath)) + if (variantName !== '__tests__') { + const variantTestDir = testDir + '__' + variantName + if (fs.existsSync(variantTestDir)) { + rootDir = testDir = variantTestDir + } + } + const testCustomServe = [ resolve(dirname(testPath), 'serve.ts'), resolve(dirname(testPath), 'serve.js'), From 6adda0e764287623264cbb1bc9f9bc3c87d04afb Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 16:26:05 +0900 Subject: [PATCH 26/54] chore: cleanup --- playground/vitestGlobalSetup.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/playground/vitestGlobalSetup.ts b/playground/vitestGlobalSetup.ts index ba8b835479ca08..1cf405f84120fd 100644 --- a/playground/vitestGlobalSetup.ts +++ b/playground/vitestGlobalSetup.ts @@ -42,15 +42,8 @@ export async function setup({ provide }: GlobalSetupContext): Promise { }) // also setup dedicated copy for "variant" tests await fs.copy( - path.resolve(__dirname, '../playground/css'), + path.resolve(tempDir, 'css'), path.resolve(tempDir, 'css__sass-modern'), - { - dereference: false, - filter(file) { - file = file.replace(/\\/g, '/') - return !file.includes('__tests__') && !/dist(?:\/|$)/.test(file) - }, - }, ) } From 6e847c057c4cbbc1abd6c0c8d7442032df9ebc31 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 16:26:38 +0900 Subject: [PATCH 27/54] ci: cleanup --- .github/workflows/ci.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6906128e9b7b2b..3dbc59fe388e05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,18 +126,6 @@ jobs: if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run test-build - - name: Test serve (sass legacy) - if: steps.changed-files.outputs.only_changed != 'true' - run: pnpm run test-serve playground/css/ - env: - TEST_SASS_LEGACY: 1 - - - name: Test build (sass legacy) - if: steps.changed-files.outputs.only_changed != 'true' - run: pnpm run test-build playground/css/ - env: - TEST_SASS_LEGACY: 1 - lint: timeout-minutes: 10 runs-on: ubuntu-latest From 3bf2dc137e4c4e04d9623f4a8303c281108af057 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Wed, 24 Jul 2024 17:07:14 +0900 Subject: [PATCH 28/54] refactor: fsp + remove toLowerCase --- packages/vite/src/node/plugins/css.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 4fa172837000cc..cf70206cf4426b 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2194,7 +2194,7 @@ const makeModernScssWorker = ( if (result.contents) { return result.contents } - return await fs.promises.readFile(result.file, 'utf-8') + return await fsp.readFile(result.file, 'utf-8') } const worker = new WorkerWithFallback( @@ -2229,9 +2229,9 @@ const makeModernScssWorker = ( async load(canonicalUrl) { const ext = path.extname(canonicalUrl.pathname) let syntax: Sass.Syntax = 'scss' - if (ext && ext.toLowerCase() === '.sass') { + if (ext === '.sass') { syntax = 'indented' - } else if (ext && ext.toLowerCase() === '.css') { + } else if (ext === '.css') { syntax = 'css' } const contents = await internalLoad( From c2f82f4b10c3991dcb1f0f43cd6421c49d86be6c Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 17:45:35 +0900 Subject: [PATCH 29/54] feat(css): support sass compiler api --- packages/vite/src/node/plugins/css.ts | 80 ++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index cf70206cf4426b..59397a45ac0260 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2277,6 +2277,78 @@ const makeModernScssWorker = ( return worker } +const makeModernCompilerScssWorker = ( + resolvers: CSSAtImportResolvers, + alias: Alias[], + _maxWorkers: number | undefined, +) => { + let compiler: Sass.AsyncCompiler | undefined + + const worker: Awaited> = { + async run(sassPath, data, options) { + const { default: sass }: { default: typeof Sass } = await import(sassPath) + const path = await import('node:path') + const { fileURLToPath, pathToFileURL } = await import('node:url') + compiler ??= await sass.initAsyncCompiler() + + const sassOptions = { ...options } as Sass.StringOptions<'async'> + sassOptions.url = pathToFileURL(options.filename) + sassOptions.sourceMap = options.enableSourcemap + + const internalImporter: Sass.Importer<'async'> = { + async canonicalize(url, context) { + const importer = context.containingUrl + ? fileURLToPath(context.containingUrl) + : options.filename + const resolved = await resolvers.sass(url, cleanScssBugUrl(importer)) + return resolved ? pathToFileURL(resolved) : null + }, + async load(canonicalUrl) { + const ext = path.extname(canonicalUrl.pathname) + let syntax: Sass.Syntax = 'scss' + if (ext && ext.toLowerCase() === '.sass') { + syntax = 'indented' + } else if (ext && ext.toLowerCase() === '.css') { + syntax = 'css' + } + const result = await rebaseUrls( + fileURLToPath(canonicalUrl), + options.filename, + alias, + '$', + resolvers.sass, + ) + const contents = + result.contents ?? + (await fs.promises.readFile(result.file, 'utf-8')) + return { contents, syntax } + }, + } + sassOptions.importers = [ + ...(sassOptions.importers ?? []), + internalImporter, + ] + + const result = await compiler.compileStringAsync(data, sassOptions) + return { + css: result.css, + map: result.sourceMap ? JSON.stringify(result.sourceMap) : undefined, + stats: { + includedFiles: result.loadedUrls + .filter((url) => url.protocol === 'file:') + .map((url) => fileURLToPath(url)), + }, + } satisfies ScssWorkerResult + }, + async stop() { + compiler?.dispose() + compiler = undefined + }, + } + + return worker +} + type ScssWorkerResult = { css: string map?: string | undefined @@ -2300,9 +2372,11 @@ const scssProcessor = ( if (!workerMap.has(options.alias)) { workerMap.set( options.alias, - options.api === 'modern' - ? makeModernScssWorker(resolvers, options.alias, maxWorkers) - : makeScssWorker(resolvers, options.alias, maxWorkers), + options.api === 'modern-compiler' + ? makeModernCompilerScssWorker(resolvers, options.alias, maxWorkers) + : options.api === 'modern' + ? makeModernScssWorker(resolvers, options.alias, maxWorkers) + : makeScssWorker(resolvers, options.alias, maxWorkers), ) } const worker = workerMap.get(options.alias)! From 0d314c2418399821b2059d29004ada5167cc4eb1 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 23 Jul 2024 18:32:52 +0900 Subject: [PATCH 30/54] test: copy test --- .../sass-modern-compiler.spec.ts | 1 + .../css/vite.config-sass-modern-compiler.js | 31 +++++++++++++++++++ playground/css/vite.config-sass-modern.js | 2 +- playground/vitestGlobalSetup.ts | 4 +++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 playground/css/__tests__/sass-modern-compiler/sass-modern-compiler.spec.ts create mode 100644 playground/css/vite.config-sass-modern-compiler.js diff --git a/playground/css/__tests__/sass-modern-compiler/sass-modern-compiler.spec.ts b/playground/css/__tests__/sass-modern-compiler/sass-modern-compiler.spec.ts new file mode 100644 index 00000000000000..90a9b9774d3ebc --- /dev/null +++ b/playground/css/__tests__/sass-modern-compiler/sass-modern-compiler.spec.ts @@ -0,0 +1 @@ +import '../css.spec' diff --git a/playground/css/vite.config-sass-modern-compiler.js b/playground/css/vite.config-sass-modern-compiler.js new file mode 100644 index 00000000000000..9759d58506f597 --- /dev/null +++ b/playground/css/vite.config-sass-modern-compiler.js @@ -0,0 +1,31 @@ +import { defineConfig } from 'vite' +import baseConfig from './vite.config.js' + +export default defineConfig({ + ...baseConfig, + css: { + ...baseConfig.css, + preprocessorOptions: { + ...baseConfig.css.preprocessorOptions, + scss: { + api: 'modern-compiler', + additionalData: `$injectedColor: orange;`, + importers: [ + { + canonicalize(url) { + return url === 'virtual-dep' + ? new URL('custom-importer:virtual-dep') + : null + }, + load() { + return { + contents: ``, + syntax: 'scss', + } + }, + }, + ], + }, + }, + }, +}) diff --git a/playground/css/vite.config-sass-modern.js b/playground/css/vite.config-sass-modern.js index 9f7acb3a098179..9759d58506f597 100644 --- a/playground/css/vite.config-sass-modern.js +++ b/playground/css/vite.config-sass-modern.js @@ -8,7 +8,7 @@ export default defineConfig({ preprocessorOptions: { ...baseConfig.css.preprocessorOptions, scss: { - api: 'modern', + api: 'modern-compiler', additionalData: `$injectedColor: orange;`, importers: [ { diff --git a/playground/vitestGlobalSetup.ts b/playground/vitestGlobalSetup.ts index 1cf405f84120fd..b884df52160187 100644 --- a/playground/vitestGlobalSetup.ts +++ b/playground/vitestGlobalSetup.ts @@ -45,6 +45,10 @@ export async function setup({ provide }: GlobalSetupContext): Promise { path.resolve(tempDir, 'css'), path.resolve(tempDir, 'css__sass-modern'), ) + await fs.copy( + path.resolve(tempDir, 'css'), + path.resolve(tempDir, 'css__sass-modern-compiler'), + ) } export async function teardown(): Promise { From c823f4360bc7dd67859a7efaf05a96d4d592ce9c Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Wed, 24 Jul 2024 14:05:08 +0900 Subject: [PATCH 31/54] chore: typo --- playground/css/vite.config-sass-modern.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/css/vite.config-sass-modern.js b/playground/css/vite.config-sass-modern.js index 9759d58506f597..9f7acb3a098179 100644 --- a/playground/css/vite.config-sass-modern.js +++ b/playground/css/vite.config-sass-modern.js @@ -8,7 +8,7 @@ export default defineConfig({ preprocessorOptions: { ...baseConfig.css.preprocessorOptions, scss: { - api: 'modern-compiler', + api: 'modern', additionalData: `$injectedColor: orange;`, importers: [ { From f1435ad4c35e12ab419f99ee69c3da5b65f6d8ee Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Wed, 24 Jul 2024 12:02:57 +0900 Subject: [PATCH 32/54] chore: add sass-embedded as optional peer --- packages/vite/package.json | 5 + pnpm-lock.yaml | 230 +++++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) diff --git a/packages/vite/package.json b/packages/vite/package.json index 58ce1064f203f4..7283f1b6753cd4 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -142,6 +142,7 @@ "rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-license": "^3.5.2", "sass": "^1.77.8", + "sass-embedded": "^1.77.8", "sirv": "^2.0.4", "source-map-support": "^0.5.21", "strip-ansi": "^7.1.0", @@ -157,6 +158,7 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -168,6 +170,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62131352ec51e9..23f74950c008eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -388,6 +388,9 @@ importers: sass: specifier: ^1.77.8 version: 1.77.8 + sass-embedded: + specifier: ^1.77.8 + version: 1.77.8 sirv: specifier: ^2.0.4 version: 2.0.4(patch_hash=amdes53ifqfntejkflpaq5ifce) @@ -2219,6 +2222,9 @@ packages: resolution: {integrity: sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==} engines: {node: '>=6.9.0'} + '@bufbuild/protobuf@1.10.0': + resolution: {integrity: sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==} + '@cloudflare/workerd-darwin-64@1.20240718.0': resolution: {integrity: sha512-BsPZcSCgoGnufog2GIgdPuiKicYTNyO/Dp++HbpLRH+yQdX3x4aWx83M+a0suTl1xv76dO4g9aw7SIB6OSgIyQ==} engines: {node: '>=16'} @@ -3815,6 +3821,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-builder@0.2.0: + resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -5921,6 +5930,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -5931,6 +5943,125 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sass-embedded-android-arm64@1.77.8: + resolution: {integrity: sha512-EmWHLbEx0Zo/f/lTFzMeH2Du+/I4RmSRlEnERSUKQWVp3aBSO04QDvdxfFezgQ+2Yt/ub9WMqBpma9P/8MPsLg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + hasBin: true + + sass-embedded-android-arm@1.77.8: + resolution: {integrity: sha512-GpGL7xZ7V1XpFbnflib/NWbM0euRzineK0iwoo31/ntWKAXGj03iHhGzkSiOwWSFcXgsJJi3eRA5BTmBvK5Q+w==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + hasBin: true + + sass-embedded-android-ia32@1.77.8: + resolution: {integrity: sha512-+GjfJ3lDezPi4dUUyjQBxlNKXNa+XVWsExtGvVNkv1uKyaOxULJhubVo2G6QTJJU0esJdfeXf5Ca5/J0ph7+7w==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [android] + hasBin: true + + sass-embedded-android-x64@1.77.8: + resolution: {integrity: sha512-YZbFDzGe5NhaMCygShqkeCWtzjhkWxGVunc7ULR97wmxYPQLPeVyx7XFQZc84Aj0lKAJBJS4qRZeqphMqZEJsQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + hasBin: true + + sass-embedded-darwin-arm64@1.77.8: + resolution: {integrity: sha512-aifgeVRNE+i43toIkDFFJc/aPLMo0PJ5s5hKb52U+oNdiJE36n65n2L8F/8z3zZRvCa6eYtFY2b7f1QXR3B0LA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + hasBin: true + + sass-embedded-darwin-x64@1.77.8: + resolution: {integrity: sha512-/VWZQtcWIOek60Zj6Sxk6HebXA1Qyyt3sD8o5qwbTgZnKitB1iEBuNunyGoAgMNeUz2PRd6rVki6hvbas9hQ6w==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + hasBin: true + + sass-embedded-linux-arm64@1.77.8: + resolution: {integrity: sha512-6iIOIZtBFa2YfMsHqOb3qake3C9d/zlKxjooKKnTSo+6g6z+CLTzMXe1bOfayb7yxeenElmFoK1k54kWD/40+g==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + hasBin: true + + sass-embedded-linux-arm@1.77.8: + resolution: {integrity: sha512-2edZMB6jf0whx3T0zlgH+p131kOEmWp+I4wnKj7ZMUeokiY4Up05d10hSvb0Q63lOrSjFAWu6P5/pcYUUx8arQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + hasBin: true + + sass-embedded-linux-ia32@1.77.8: + resolution: {integrity: sha512-63GsFFHWN5yRLTWiSef32TM/XmjhCBx1DFhoqxmj+Yc6L9Z1h0lDHjjwdG6Sp5XTz5EmsaFKjpDgnQTP9hJX3Q==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + hasBin: true + + sass-embedded-linux-musl-arm64@1.77.8: + resolution: {integrity: sha512-j8cgQxNWecYK+aH8ESFsyam/Q6G+9gg8eJegiRVpA9x8yk3ykfHC7UdQWwUcF22ZcuY4zegrjJx8k+thsgsOVA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-musl-arm@1.77.8: + resolution: {integrity: sha512-nFkhSl3uu9btubm+JBW7uRglNVJ8W8dGfzVqh3fyQJKS1oyBC3vT3VOtfbT9YivXk28wXscSHpqXZwY7bUuopA==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-ia32@1.77.8: + resolution: {integrity: sha512-oWveMe+8TFlP8WBWPna/+Ec5TV0CE+PxEutyi0ltSruBds2zxRq9dPVOqrpPcDN9QUx50vNZC0Afgch0aQEd0g==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + + sass-embedded-linux-musl-x64@1.77.8: + resolution: {integrity: sha512-2NtRpMXHeFo9kaYxuZ+Ewwo39CE7BTS2JDfXkTjZTZqd8H+8KC53eBh516YQnn2oiqxSiKxm7a6pxbxGZGwXOQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-linux-x64@1.77.8: + resolution: {integrity: sha512-ND5qZLWUCpOn7LJfOf0gLSZUWhNIysY+7NZK1Ctq+pM6tpJky3JM5I1jSMplNxv5H3o8p80n0gSm+fcjsEFfjQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + hasBin: true + + sass-embedded-win32-arm64@1.77.8: + resolution: {integrity: sha512-7L8zT6xzEvTYj86MvUWnbkWYCNQP+74HvruLILmiPPE+TCgOjgdi750709BtppVJGGZSs40ZuN6mi/YQyGtwXg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + hasBin: true + + sass-embedded-win32-ia32@1.77.8: + resolution: {integrity: sha512-7Buh+4bP0WyYn6XPbthkIa3M2vtcR8QIsFVg3JElVlr+8Ng19jqe0t0SwggDgbMX6AdQZC+Wj4F1BprZSok42A==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [win32] + hasBin: true + + sass-embedded-win32-x64@1.77.8: + resolution: {integrity: sha512-rZmLIx4/LLQm+4GW39sRJW0MIlDqmyV0fkRzTmhFP5i/wVC7cuj8TUubPHw18rv2rkHFfBZKZJTCkPjCS5Z+SA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + hasBin: true + + sass-embedded@1.77.8: + resolution: {integrity: sha512-WGXA6jcaoBo5Uhw0HX/s6z/sl3zyYQ7ZOnLOJzqwpctFcFmU4L07zn51e2VSkXXFpQZFAdMZNqOGz/7h/fvcRA==} + engines: {node: '>=16.0.0'} + sass@1.77.8: resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==} engines: {node: '>=14.0.0'} @@ -6182,6 +6313,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -6458,6 +6593,9 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -7529,6 +7667,8 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + '@bufbuild/protobuf@1.10.0': {} + '@cloudflare/workerd-darwin-64@1.20240718.0': optional: true @@ -9003,6 +9143,8 @@ snapshots: node-releases: 2.0.14 update-browserslist-db: 1.1.0(browserslist@4.23.2) + buffer-builder@0.2.0: {} + buffer-from@1.1.2: {} builtin-modules@3.3.0: {} @@ -11377,6 +11519,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.1: + dependencies: + tslib: 2.6.3 + sade@1.8.1: dependencies: mri: 1.2.0 @@ -11385,6 +11531,84 @@ snapshots: safer-buffer@2.1.2: {} + sass-embedded-android-arm64@1.77.8: + optional: true + + sass-embedded-android-arm@1.77.8: + optional: true + + sass-embedded-android-ia32@1.77.8: + optional: true + + sass-embedded-android-x64@1.77.8: + optional: true + + sass-embedded-darwin-arm64@1.77.8: + optional: true + + sass-embedded-darwin-x64@1.77.8: + optional: true + + sass-embedded-linux-arm64@1.77.8: + optional: true + + sass-embedded-linux-arm@1.77.8: + optional: true + + sass-embedded-linux-ia32@1.77.8: + optional: true + + sass-embedded-linux-musl-arm64@1.77.8: + optional: true + + sass-embedded-linux-musl-arm@1.77.8: + optional: true + + sass-embedded-linux-musl-ia32@1.77.8: + optional: true + + sass-embedded-linux-musl-x64@1.77.8: + optional: true + + sass-embedded-linux-x64@1.77.8: + optional: true + + sass-embedded-win32-arm64@1.77.8: + optional: true + + sass-embedded-win32-ia32@1.77.8: + optional: true + + sass-embedded-win32-x64@1.77.8: + optional: true + + sass-embedded@1.77.8: + dependencies: + '@bufbuild/protobuf': 1.10.0 + buffer-builder: 0.2.0 + immutable: 4.0.0 + rxjs: 7.8.1 + supports-color: 8.1.1 + varint: 6.0.0 + optionalDependencies: + sass-embedded-android-arm: 1.77.8 + sass-embedded-android-arm64: 1.77.8 + sass-embedded-android-ia32: 1.77.8 + sass-embedded-android-x64: 1.77.8 + sass-embedded-darwin-arm64: 1.77.8 + sass-embedded-darwin-x64: 1.77.8 + sass-embedded-linux-arm: 1.77.8 + sass-embedded-linux-arm64: 1.77.8 + sass-embedded-linux-ia32: 1.77.8 + sass-embedded-linux-musl-arm: 1.77.8 + sass-embedded-linux-musl-arm64: 1.77.8 + sass-embedded-linux-musl-ia32: 1.77.8 + sass-embedded-linux-musl-x64: 1.77.8 + sass-embedded-linux-x64: 1.77.8 + sass-embedded-win32-arm64: 1.77.8 + sass-embedded-win32-ia32: 1.77.8 + sass-embedded-win32-x64: 1.77.8 + sass@1.77.8: dependencies: chokidar: 3.6.0(patch_hash=bckcfsslxcffppz65mxcq6naau) @@ -11645,6 +11869,10 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} systemjs@6.15.1: {} @@ -11945,6 +12173,8 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + varint@6.0.0: {} + vary@1.1.2: {} vfile-message@4.0.2: From aeee7771c25c059b898a096a63c931f37249ddf6 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Wed, 24 Jul 2024 14:04:29 +0900 Subject: [PATCH 33/54] feat: try loading sass-embedded before sass --- packages/vite/src/node/plugins/css.ts | 36 +++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 59397a45ac0260..f9e93ca8131ead 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -1945,7 +1945,9 @@ type StylePreprocessorOptions = { } type SassStylePreprocessorOptions = StylePreprocessorOptions & - Omit, 'data' | 'file' | 'outFile'> + Omit, 'data' | 'file' | 'outFile'> & { + api?: 'legacy' | 'modern' | 'modern-compiler' + } type StylusStylePreprocessorOptions = StylePreprocessorOptions & { define?: Record @@ -2020,6 +2022,24 @@ function loadPreprocessorPath( } } +function loadSassPackage(root: string): { + name: 'sass' | 'sass-embedded' + path: string +} { + // try sass-embedded before sass + try { + const path = loadPreprocessorPath('sass-embedded' as any, root) + return { name: 'sass-embedded', path } + } catch (e1) { + try { + const path = loadPreprocessorPath('sass' as any, root) + return { name: 'sass', path } + } catch (e2) { + throw e1 + } + } +} + let cachedSss: any function loadSss(root: string) { if (cachedSss) return cachedSss @@ -2367,14 +2387,20 @@ const scssProcessor = ( } }, async process(source, root, options, resolvers) { - const sassPath = loadPreprocessorPath(PreprocessLang.sass, root) + const sassPackage = loadSassPackage(root) + let api = options.api + if (!api) { + api = 'legacy' + // TODO: change default in v6 + // api = sassPackage.name === "sass-embedded" ? "modern-compiler" : "modern"; + } if (!workerMap.has(options.alias)) { workerMap.set( options.alias, - options.api === 'modern-compiler' + api === 'modern-compiler' ? makeModernCompilerScssWorker(resolvers, options.alias, maxWorkers) - : options.api === 'modern' + : api === 'modern' ? makeModernScssWorker(resolvers, options.alias, maxWorkers) : makeScssWorker(resolvers, options.alias, maxWorkers), ) @@ -2394,7 +2420,7 @@ const scssProcessor = ( } try { const result = await worker.run( - sassPath, + sassPackage.path, data, optionsWithoutAdditionalData, ) From 0aac86637df9a8f9abc3b4fdf4258395abe87110 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 29 Jul 2024 18:42:22 +0900 Subject: [PATCH 34/54] docs: update --- docs/config/shared-options.md | 2 +- docs/guide/features.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config/shared-options.md b/docs/config/shared-options.md index fa3ccba14128aa..8dafb2b65a8bc4 100644 --- a/docs/config/shared-options.md +++ b/docs/config/shared-options.md @@ -225,7 +225,7 @@ Note if an inline config is provided, Vite will not search for other PostCSS con Specify options to pass to CSS pre-processors. The file extensions are used as keys for the options. The supported options for each preprocessors can be found in their respective documentation: -- `sass`/`scss` - top level option `api: "legacy" | "modern"` (default `"legacy"`) allows switching which sass API to use. [Options (legacy)](https://sass-lang.com/documentation/js-api/interfaces/LegacyStringOptions), [Options (modern)](https://sass-lang.com/documentation/js-api/interfaces/stringoptions/). +- `sass`/`scss` - top level option `api: "legacy" | "modern" | "modern-compiler"` (default `"legacy"`) allows switching which sass API to use. For the best performance, it's recommended to use `api: "modern-compiler"` with `sass-embedded` package. [Options (legacy)](https://sass-lang.com/documentation/js-api/interfaces/LegacyStringOptions), [Options (modern)](https://sass-lang.com/documentation/js-api/interfaces/stringoptions/). - `less` - [Options](https://lesscss.org/usage/#less-options). - `styl`/`stylus` - Only [`define`](https://stylus-lang.com/docs/js.html#define-name-node) is supported, which can be passed as an object. diff --git a/docs/guide/features.md b/docs/guide/features.md index 75940b8d17310c..9998387dae46b0 100644 --- a/docs/guide/features.md +++ b/docs/guide/features.md @@ -257,7 +257,7 @@ That said, Vite does provide built-in support for `.scss`, `.sass`, `.less`, `.s ```bash # .scss and .sass -npm add -D sass +npm add -D sass-embedded # or sass # .less npm add -D less From 79f0f808591a5f93fca904046af96b10c9518678 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 29 Jul 2024 18:43:04 +0900 Subject: [PATCH 35/54] docs: tweak --- docs/config/shared-options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config/shared-options.md b/docs/config/shared-options.md index 8dafb2b65a8bc4..9e2af19e6255c5 100644 --- a/docs/config/shared-options.md +++ b/docs/config/shared-options.md @@ -244,7 +244,7 @@ export default defineConfig({ }, }, scss: { - api: 'modern', // or "legacy" + api: 'modern-compiler', // or "modern", "legacy" importers: [ // ... ], From c0460f8ddb5f3eac7f3ca81272a7c219f344dd87 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 29 Jul 2024 19:01:07 +0900 Subject: [PATCH 36/54] wip: how about no sass-embedded? --- packages/vite/src/node/plugins/css.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index f9e93ca8131ead..ce07d6ee426d97 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2028,8 +2028,8 @@ function loadSassPackage(root: string): { } { // try sass-embedded before sass try { - const path = loadPreprocessorPath('sass-embedded' as any, root) - return { name: 'sass-embedded', path } + const path = loadPreprocessorPath('sass' as any, root) + return { name: 'sass', path } } catch (e1) { try { const path = loadPreprocessorPath('sass' as any, root) From 297eb95a84868522ad3b34d170886fb2c95e767e Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 29 Jul 2024 19:09:27 +0900 Subject: [PATCH 37/54] Revert "wip: how about no sass-embedded?" This reverts commit c0460f8ddb5f3eac7f3ca81272a7c219f344dd87. --- packages/vite/src/node/plugins/css.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index ce07d6ee426d97..f9e93ca8131ead 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2028,8 +2028,8 @@ function loadSassPackage(root: string): { } { // try sass-embedded before sass try { - const path = loadPreprocessorPath('sass' as any, root) - return { name: 'sass', path } + const path = loadPreprocessorPath('sass-embedded' as any, root) + return { name: 'sass-embedded', path } } catch (e1) { try { const path = loadPreprocessorPath('sass' as any, root) From 52fa97a051e4546c67d62ab0a06c9e07fec5874a Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 08:33:15 +0900 Subject: [PATCH 38/54] test: debug windows --- .../vite/src/node/__tests__/build.spec.ts | 20 +++++++++++++++++++ .../node/__tests__/fixtures/sass-test/main.js | 1 + .../__tests__/fixtures/sass-test/main.scss | 3 +++ 3 files changed, 24 insertions(+) create mode 100644 packages/vite/src/node/__tests__/fixtures/sass-test/main.js create mode 100644 packages/vite/src/node/__tests__/fixtures/sass-test/main.scss diff --git a/packages/vite/src/node/__tests__/build.spec.ts b/packages/vite/src/node/__tests__/build.spec.ts index 2dad85578812cc..e60757c2c939ac 100644 --- a/packages/vite/src/node/__tests__/build.spec.ts +++ b/packages/vite/src/node/__tests__/build.spec.ts @@ -600,3 +600,23 @@ function assertOutputHashContentChange( } } } + +test('sass-test', async () => { + await build({ + root: resolve(__dirname, 'fixtures/sass-test'), + build: { + rollupOptions: { + input: { + index: '/main.js', + }, + }, + }, + css: { + preprocessorOptions: { + scss: { + api: 'modern-compiler', + }, + }, + }, + }) +}) diff --git a/packages/vite/src/node/__tests__/fixtures/sass-test/main.js b/packages/vite/src/node/__tests__/fixtures/sass-test/main.js new file mode 100644 index 00000000000000..87c1bbd8c51546 --- /dev/null +++ b/packages/vite/src/node/__tests__/fixtures/sass-test/main.js @@ -0,0 +1 @@ +import './main.scss' diff --git a/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss b/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss new file mode 100644 index 00000000000000..6446ebfd427495 --- /dev/null +++ b/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss @@ -0,0 +1,3 @@ +.test { + color: red; +} From 409f713e72b3bd950a2dfd8b0429fcbd0e9d9bce Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 08:38:59 +0900 Subject: [PATCH 39/54] Revert "test: debug windows" This reverts commit 52fa97a051e4546c67d62ab0a06c9e07fec5874a. --- .../vite/src/node/__tests__/build.spec.ts | 20 ------------------- .../node/__tests__/fixtures/sass-test/main.js | 1 - .../__tests__/fixtures/sass-test/main.scss | 3 --- 3 files changed, 24 deletions(-) delete mode 100644 packages/vite/src/node/__tests__/fixtures/sass-test/main.js delete mode 100644 packages/vite/src/node/__tests__/fixtures/sass-test/main.scss diff --git a/packages/vite/src/node/__tests__/build.spec.ts b/packages/vite/src/node/__tests__/build.spec.ts index e60757c2c939ac..2dad85578812cc 100644 --- a/packages/vite/src/node/__tests__/build.spec.ts +++ b/packages/vite/src/node/__tests__/build.spec.ts @@ -600,23 +600,3 @@ function assertOutputHashContentChange( } } } - -test('sass-test', async () => { - await build({ - root: resolve(__dirname, 'fixtures/sass-test'), - build: { - rollupOptions: { - input: { - index: '/main.js', - }, - }, - }, - css: { - preprocessorOptions: { - scss: { - api: 'modern-compiler', - }, - }, - }, - }) -}) diff --git a/packages/vite/src/node/__tests__/fixtures/sass-test/main.js b/packages/vite/src/node/__tests__/fixtures/sass-test/main.js deleted file mode 100644 index 87c1bbd8c51546..00000000000000 --- a/packages/vite/src/node/__tests__/fixtures/sass-test/main.js +++ /dev/null @@ -1 +0,0 @@ -import './main.scss' diff --git a/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss b/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss deleted file mode 100644 index 6446ebfd427495..00000000000000 --- a/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss +++ /dev/null @@ -1,3 +0,0 @@ -.test { - color: red; -} From 4be7db6fac13c4bdc2cd9d56ececb9e4fc902b43 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 08:44:00 +0900 Subject: [PATCH 40/54] fix: fix fs and path --- playground/vitestGlobalSetup.ts | 6 ++++-- playground/vitestSetup.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/playground/vitestGlobalSetup.ts b/playground/vitestGlobalSetup.ts index 1f45f125b14895..d97dec019d411e 100644 --- a/playground/vitestGlobalSetup.ts +++ b/playground/vitestGlobalSetup.ts @@ -42,13 +42,15 @@ export async function setup({ provide }: GlobalSetupContext): Promise { } }) // also setup dedicated copy for "variant" tests - await fs.copy( + await fs.cp( path.resolve(tempDir, 'css'), path.resolve(tempDir, 'css__sass-modern'), + { recursive: true }, ) - await fs.copy( + await fs.cp( path.resolve(tempDir, 'css'), path.resolve(tempDir, 'css__sass-modern-compiler'), + { recursive: true }, ) } diff --git a/playground/vitestSetup.ts b/playground/vitestSetup.ts index 98942f67a22f40..eb28b5f544d453 100644 --- a/playground/vitestSetup.ts +++ b/playground/vitestSetup.ts @@ -137,7 +137,7 @@ beforeAll(async (s) => { rootDir = fs.existsSync(testCustomRoot) ? testCustomRoot : testDir // separate rootDir for variant - const variantName = path.basename(dirname(testPath)) + const variantName = path.basename(path.dirname(testPath)) if (variantName !== '__tests__') { const variantTestDir = testDir + '__' + variantName if (fs.existsSync(variantTestDir)) { From 2be6934f1679a0452c7b428bccc7352f13ee93c0 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 08:44:28 +0900 Subject: [PATCH 41/54] Reapply "test: debug windows" This reverts commit 409f713e72b3bd950a2dfd8b0429fcbd0e9d9bce. --- .../vite/src/node/__tests__/build.spec.ts | 20 +++++++++++++++++++ .../node/__tests__/fixtures/sass-test/main.js | 1 + .../__tests__/fixtures/sass-test/main.scss | 3 +++ 3 files changed, 24 insertions(+) create mode 100644 packages/vite/src/node/__tests__/fixtures/sass-test/main.js create mode 100644 packages/vite/src/node/__tests__/fixtures/sass-test/main.scss diff --git a/packages/vite/src/node/__tests__/build.spec.ts b/packages/vite/src/node/__tests__/build.spec.ts index 2dad85578812cc..e60757c2c939ac 100644 --- a/packages/vite/src/node/__tests__/build.spec.ts +++ b/packages/vite/src/node/__tests__/build.spec.ts @@ -600,3 +600,23 @@ function assertOutputHashContentChange( } } } + +test('sass-test', async () => { + await build({ + root: resolve(__dirname, 'fixtures/sass-test'), + build: { + rollupOptions: { + input: { + index: '/main.js', + }, + }, + }, + css: { + preprocessorOptions: { + scss: { + api: 'modern-compiler', + }, + }, + }, + }) +}) diff --git a/packages/vite/src/node/__tests__/fixtures/sass-test/main.js b/packages/vite/src/node/__tests__/fixtures/sass-test/main.js new file mode 100644 index 00000000000000..87c1bbd8c51546 --- /dev/null +++ b/packages/vite/src/node/__tests__/fixtures/sass-test/main.js @@ -0,0 +1 @@ +import './main.scss' diff --git a/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss b/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss new file mode 100644 index 00000000000000..6446ebfd427495 --- /dev/null +++ b/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss @@ -0,0 +1,3 @@ +.test { + color: red; +} From c1df7b68a01ce7aa77ad333bd27970e81a227a98 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 08:52:15 +0900 Subject: [PATCH 42/54] fix: fix fs, path --- playground/vitestGlobalSetup.ts | 3 ++- playground/vitestSetup.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/playground/vitestGlobalSetup.ts b/playground/vitestGlobalSetup.ts index f73eece915df5a..193c47b6047eac 100644 --- a/playground/vitestGlobalSetup.ts +++ b/playground/vitestGlobalSetup.ts @@ -42,9 +42,10 @@ export async function setup({ provide }: GlobalSetupContext): Promise { } }) // also setup dedicated copy for "variant" tests - await fs.copy( + await fs.cp( path.resolve(tempDir, 'css'), path.resolve(tempDir, 'css__sass-modern'), + { recursive: true }, ) } diff --git a/playground/vitestSetup.ts b/playground/vitestSetup.ts index 98942f67a22f40..eb28b5f544d453 100644 --- a/playground/vitestSetup.ts +++ b/playground/vitestSetup.ts @@ -137,7 +137,7 @@ beforeAll(async (s) => { rootDir = fs.existsSync(testCustomRoot) ? testCustomRoot : testDir // separate rootDir for variant - const variantName = path.basename(dirname(testPath)) + const variantName = path.basename(path.dirname(testPath)) if (variantName !== '__tests__') { const variantTestDir = testDir + '__' + variantName if (fs.existsSync(variantTestDir)) { From f730495e1c0e85aee898c16df4b04ee87357e3cb Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 15:47:05 +0900 Subject: [PATCH 43/54] wip: what about build? --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3dbc59fe388e05..bfdcbd53424cd5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,9 +118,9 @@ jobs: if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run test-unit - - name: Test serve - if: steps.changed-files.outputs.only_changed != 'true' - run: pnpm run test-serve + # - name: Test serve + # if: steps.changed-files.outputs.only_changed != 'true' + # run: pnpm run test-serve - name: Test build if: steps.changed-files.outputs.only_changed != 'true' From 2a7db07319e517459ec81026f99ba2b6e71e4179 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 15:57:49 +0900 Subject: [PATCH 44/54] chore: cleanup --- packages/vite/src/node/plugins/css.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 6361974260b36a..6c3eccab107b2f 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2,6 +2,7 @@ import fs from 'node:fs' import fsp from 'node:fs/promises' import path from 'node:path' import { createRequire } from 'node:module' +import { fileURLToPath, pathToFileURL } from 'node:url' import glob from 'fast-glob' import postcssrc from 'postcss-load-config' import type { @@ -2297,6 +2298,9 @@ const makeModernScssWorker = ( return worker } +// this is mostly a copy&paste of makeModernScssWorker +// however sharing code between two is hard because +// makeModernScssWorker above needs function inlined for worker. const makeModernCompilerScssWorker = ( resolvers: CSSAtImportResolvers, alias: Alias[], @@ -2307,8 +2311,6 @@ const makeModernCompilerScssWorker = ( const worker: Awaited> = { async run(sassPath, data, options) { const { default: sass }: { default: typeof Sass } = await import(sassPath) - const path = await import('node:path') - const { fileURLToPath, pathToFileURL } = await import('node:url') compiler ??= await sass.initAsyncCompiler() const sassOptions = { ...options } as Sass.StringOptions<'async'> From 64a3f229d7d2051561419e11dc88a3a20320da1d Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 16:01:56 +0900 Subject: [PATCH 45/54] wip: debug --- packages/vite/src/node/plugins/css.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 6c3eccab107b2f..31f8dec21671b9 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2439,6 +2439,7 @@ const scssProcessor = ( } } catch (e) { // normalize SASS error + console.error(e); e.message = `[sass] ${e.message}` e.id = e.file e.frame = e.formatted From b514e46af53b5138eaaa7545af826cedcc0c9697 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 16:12:26 +0900 Subject: [PATCH 46/54] wip: debug --- packages/vite/src/node/__tests__/build.spec.ts | 16 ++++++++++++++++ .../node/__tests__/fixtures/sass-test/main.scss | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/__tests__/build.spec.ts b/packages/vite/src/node/__tests__/build.spec.ts index e60757c2c939ac..eec534db0afcfc 100644 --- a/packages/vite/src/node/__tests__/build.spec.ts +++ b/packages/vite/src/node/__tests__/build.spec.ts @@ -615,6 +615,22 @@ test('sass-test', async () => { preprocessorOptions: { scss: { api: 'modern-compiler', + additionalData: `$injectedColor: orange;`, + importers: [ + { + canonicalize(url: string) { + return url === 'virtual-dep' + ? new URL('custom-importer:virtual-dep') + : null + }, + load() { + return { + contents: ``, + syntax: 'scss', + } + }, + }, + ], }, }, }, diff --git a/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss b/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss index 6446ebfd427495..b2574c116cd515 100644 --- a/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss +++ b/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss @@ -1,3 +1,5 @@ +@import 'virtual-dep'; + .test { - color: red; + color: $injectedColor; } From 1811681c0e35af70241d30135df2425a06809ccb Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 16:15:52 +0900 Subject: [PATCH 47/54] chore: cleanup --- packages/vite/src/node/plugins/css.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 31f8dec21671b9..5718c5d478adb1 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2390,12 +2390,9 @@ const scssProcessor = ( }, async process(source, root, options, resolvers) { const sassPackage = loadSassPackage(root) - let api = options.api - if (!api) { - api = 'legacy' - // TODO: change default in v6 - // api = sassPackage.name === "sass-embedded" ? "modern-compiler" : "modern"; - } + // TODO: change default in v6 + // options.api ?? sassPackage.name === "sass-embedded" ? "modern-compiler" : "modern"; + let api = options.api ?? 'legacy' if (!workerMap.has(options.alias)) { workerMap.set( From ce90a9e804de111e947e30da51dd2db9ac6aca5b Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 16:28:26 +0900 Subject: [PATCH 48/54] wip: debug --- packages/vite/src/node/plugins/css.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 5718c5d478adb1..aab68bfa24f79f 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2310,7 +2310,17 @@ const makeModernCompilerScssWorker = ( const worker: Awaited> = { async run(sassPath, data, options) { - const { default: sass }: { default: typeof Sass } = await import(sassPath) + console.log("@@@", { sassPath }); + const { default: sass }: { default: typeof Sass } = await import(sassPath).then( + (v) => { + console.log('@@@@@@@@ OK'); + return v + }, + (e) => { + console.log('@@@@@@@@ ERROR'); + console.error(e); + } + ) compiler ??= await sass.initAsyncCompiler() const sassOptions = { ...options } as Sass.StringOptions<'async'> From 7829fe34eec922c60971bb0150d0ede6e0b862de Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 16:36:51 +0900 Subject: [PATCH 49/54] fix: replace `import` with `require` for Windows? --- packages/vite/src/node/plugins/css.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index aab68bfa24f79f..c2e31d5a5cfe6c 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2310,17 +2310,8 @@ const makeModernCompilerScssWorker = ( const worker: Awaited> = { async run(sassPath, data, options) { - console.log("@@@", { sassPath }); - const { default: sass }: { default: typeof Sass } = await import(sassPath).then( - (v) => { - console.log('@@@@@@@@ OK'); - return v - }, - (e) => { - console.log('@@@@@@@@ ERROR'); - console.error(e); - } - ) + // workaround for windows since import("D:...") fails + const sass: typeof Sass = createRequire(import.meta.url)(sassPath); compiler ??= await sass.initAsyncCompiler() const sassOptions = { ...options } as Sass.StringOptions<'async'> From 57f48f7a4b0e5480ac70f173c1789459b984fc2d Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 16:42:48 +0900 Subject: [PATCH 50/54] chore: revert debug --- .github/workflows/ci.yml | 6 +++--- packages/vite/src/node/plugins/css.ts | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfdcbd53424cd5..3dbc59fe388e05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,9 +118,9 @@ jobs: if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run test-unit - # - name: Test serve - # if: steps.changed-files.outputs.only_changed != 'true' - # run: pnpm run test-serve + - name: Test serve + if: steps.changed-files.outputs.only_changed != 'true' + run: pnpm run test-serve - name: Test build if: steps.changed-files.outputs.only_changed != 'true' diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index c2e31d5a5cfe6c..fca4062bcc33b3 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2311,7 +2311,7 @@ const makeModernCompilerScssWorker = ( const worker: Awaited> = { async run(sassPath, data, options) { // workaround for windows since import("D:...") fails - const sass: typeof Sass = createRequire(import.meta.url)(sassPath); + const sass: typeof Sass = createRequire(import.meta.url)(sassPath) compiler ??= await sass.initAsyncCompiler() const sassOptions = { ...options } as Sass.StringOptions<'async'> @@ -2393,7 +2393,7 @@ const scssProcessor = ( const sassPackage = loadSassPackage(root) // TODO: change default in v6 // options.api ?? sassPackage.name === "sass-embedded" ? "modern-compiler" : "modern"; - let api = options.api ?? 'legacy' + const api = options.api ?? 'legacy' if (!workerMap.has(options.alias)) { workerMap.set( @@ -2437,7 +2437,6 @@ const scssProcessor = ( } } catch (e) { // normalize SASS error - console.error(e); e.message = `[sass] ${e.message}` e.id = e.file e.frame = e.formatted From b432b0c33671ce0af4cb8e05ce39b41bf62e384b Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 18:21:03 +0900 Subject: [PATCH 51/54] refactor: replace createRequire --- packages/vite/src/node/plugins/css.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index fca4062bcc33b3..51dee5ea4c9edf 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2310,8 +2310,10 @@ const makeModernCompilerScssWorker = ( const worker: Awaited> = { async run(sassPath, data, options) { - // workaround for windows since import("D:...") fails - const sass: typeof Sass = createRequire(import.meta.url)(sassPath) + // need pathToFileURL for windows since import("D:...") fails + // https://github.com/nodejs/node/issues/31710 + const sass: typeof Sass = (await import(pathToFileURL(sassPath).href)) + .default compiler ??= await sass.initAsyncCompiler() const sassOptions = { ...options } as Sass.StringOptions<'async'> From 7c05d81b58028ba8f497d21f3951e7d292f8df72 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 30 Jul 2024 18:21:54 +0900 Subject: [PATCH 52/54] chore: revert debug test --- .../vite/src/node/__tests__/build.spec.ts | 36 ------------------- .../node/__tests__/fixtures/sass-test/main.js | 1 - .../__tests__/fixtures/sass-test/main.scss | 5 --- 3 files changed, 42 deletions(-) delete mode 100644 packages/vite/src/node/__tests__/fixtures/sass-test/main.js delete mode 100644 packages/vite/src/node/__tests__/fixtures/sass-test/main.scss diff --git a/packages/vite/src/node/__tests__/build.spec.ts b/packages/vite/src/node/__tests__/build.spec.ts index eec534db0afcfc..2dad85578812cc 100644 --- a/packages/vite/src/node/__tests__/build.spec.ts +++ b/packages/vite/src/node/__tests__/build.spec.ts @@ -600,39 +600,3 @@ function assertOutputHashContentChange( } } } - -test('sass-test', async () => { - await build({ - root: resolve(__dirname, 'fixtures/sass-test'), - build: { - rollupOptions: { - input: { - index: '/main.js', - }, - }, - }, - css: { - preprocessorOptions: { - scss: { - api: 'modern-compiler', - additionalData: `$injectedColor: orange;`, - importers: [ - { - canonicalize(url: string) { - return url === 'virtual-dep' - ? new URL('custom-importer:virtual-dep') - : null - }, - load() { - return { - contents: ``, - syntax: 'scss', - } - }, - }, - ], - }, - }, - }, - }) -}) diff --git a/packages/vite/src/node/__tests__/fixtures/sass-test/main.js b/packages/vite/src/node/__tests__/fixtures/sass-test/main.js deleted file mode 100644 index 87c1bbd8c51546..00000000000000 --- a/packages/vite/src/node/__tests__/fixtures/sass-test/main.js +++ /dev/null @@ -1 +0,0 @@ -import './main.scss' diff --git a/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss b/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss deleted file mode 100644 index b2574c116cd515..00000000000000 --- a/packages/vite/src/node/__tests__/fixtures/sass-test/main.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import 'virtual-dep'; - -.test { - color: $injectedColor; -} From 320b5a0c41e3ed41897ef3b3cd920b2c4fcbb761 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Wed, 31 Jul 2024 08:54:35 +0900 Subject: [PATCH 53/54] fix: apply review --- packages/vite/src/node/plugins/css.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 51dee5ea4c9edf..e0be896e3e365b 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2331,9 +2331,9 @@ const makeModernCompilerScssWorker = ( async load(canonicalUrl) { const ext = path.extname(canonicalUrl.pathname) let syntax: Sass.Syntax = 'scss' - if (ext && ext.toLowerCase() === '.sass') { + if (ext === '.sass') { syntax = 'indented' - } else if (ext && ext.toLowerCase() === '.css') { + } else if (ext === '.css') { syntax = 'css' } const result = await rebaseUrls( @@ -2344,8 +2344,7 @@ const makeModernCompilerScssWorker = ( resolvers.sass, ) const contents = - result.contents ?? - (await fs.promises.readFile(result.file, 'utf-8')) + result.contents ?? (await fsp.readFile(result.file, 'utf-8')) return { contents, syntax } }, } From 81687e3c22a72f8ce71038ac932a90ea68d96b08 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Wed, 31 Jul 2024 09:07:44 +0900 Subject: [PATCH 54/54] refactor: fix any --- packages/vite/src/node/plugins/css.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index e0be896e3e365b..26ba17c192f84e 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -1993,11 +1993,11 @@ export interface StylePreprocessorResults { } const loadedPreprocessorPath: Partial< - Record + Record > = {} function loadPreprocessorPath( - lang: PreprocessLang | PostCssDialectLang, + lang: PreprocessLang | PostCssDialectLang | 'sass-embedded', root: string, ): string { const cached = loadedPreprocessorPath[lang] @@ -2029,11 +2029,11 @@ function loadSassPackage(root: string): { } { // try sass-embedded before sass try { - const path = loadPreprocessorPath('sass-embedded' as any, root) + const path = loadPreprocessorPath('sass-embedded', root) return { name: 'sass-embedded', path } } catch (e1) { try { - const path = loadPreprocessorPath('sass' as any, root) + const path = loadPreprocessorPath(PreprocessLang.sass, root) return { name: 'sass', path } } catch (e2) { throw e1