From a1dad78099865d900ceff4703aeadb1aa055ca35 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Fri, 17 Feb 2023 11:34:00 +1100 Subject: [PATCH 01/21] WIP --- .../compiler/plugins/vanilla-extract/hash.ts | 4 + .../compiler/plugins/vanilla-extract/lock.ts | 33 ++ .../vanilla-extract/processVanillaFile.ts | 156 ++++++++++ .../vanilla-extract/vanillaExtractCompiler.ts | 294 ++++++++++++++++++ .../compiler/plugins/vanillaExtractPlugin.ts | 96 +++--- packages/remix-dev/package.json | 10 +- yarn.lock | 102 +++++- 7 files changed, 636 insertions(+), 59 deletions(-) create mode 100644 packages/remix-dev/compiler/plugins/vanilla-extract/hash.ts create mode 100644 packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts create mode 100644 packages/remix-dev/compiler/plugins/vanilla-extract/processVanillaFile.ts create mode 100644 packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/hash.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/hash.ts new file mode 100644 index 00000000000..d06acf823fe --- /dev/null +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/hash.ts @@ -0,0 +1,4 @@ +import crypto from "crypto"; + +export const hash = (value: string) => + crypto.createHash("md5").update(value).digest("hex"); diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts new file mode 100644 index 00000000000..6ed17c7a2a4 --- /dev/null +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts @@ -0,0 +1,33 @@ +const queue: Array<() => Promise> = []; +let isRunning = false; + +export const lock = async (fn: () => Promise): Promise => { + let executeNextTask = () => { + const nextTask = queue.pop(); + + if (nextTask) { + nextTask(); + } else { + isRunning = false; + } + }; + + if (!isRunning) { + isRunning = true; + let result = await fn(); + + executeNextTask(); + + return result; + } else { + return new Promise((resolve) => { + queue.push(async () => { + let result = await fn(); + + resolve(result); + + executeNextTask(); + }); + }); + } +}; diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/processVanillaFile.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/processVanillaFile.ts new file mode 100644 index 00000000000..2e50525fa72 --- /dev/null +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/processVanillaFile.ts @@ -0,0 +1,156 @@ +import type { FileScope } from "@vanilla-extract/css"; +import { stringify } from "javascript-stringify"; +import isPlainObject from "lodash/isPlainObject"; +import outdent from "outdent"; + +import { hash } from "./hash"; + +export function stringifyFileScope({ + packageName, + filePath, +}: FileScope): string { + return packageName ? `${filePath}$$$${packageName}` : filePath; +} + +function stringifyExports( + functionSerializationImports: Set, + value: any, + unusedCompositionRegex: RegExp | null, + key: string, + exportLookup: Map +): any { + return stringify( + value, + (value, _indent, next) => { + let valueType = typeof value; + + if ( + valueType === "boolean" || + valueType === "number" || + valueType === "undefined" || + value === null + ) { + return next(value); + } + + if (Array.isArray(value) || isPlainObject(value)) { + let reusedExport = exportLookup.get(value); + + if (reusedExport && reusedExport !== key) { + return reusedExport; + } + return next(value); + } + + if (Symbol.toStringTag in Object(value)) { + let { [Symbol.toStringTag]: _tag, ...valueWithoutTag } = value; + return next(valueWithoutTag); + } + + if (valueType === "string") { + return next( + unusedCompositionRegex + ? value.replace(unusedCompositionRegex, "") + : value + ); + } + + if ( + valueType === "function" && + (value.__function_serializer__ || value.__recipe__) + ) { + let { importPath, importName, args } = + value.__function_serializer__ || value.__recipe__; + + if ( + typeof importPath !== "string" || + typeof importName !== "string" || + !Array.isArray(args) + ) { + throw new Error("Invalid function serialization params"); + } + + try { + let hashedImportName = `_${hash(`${importName}${importPath}`).slice( + 0, + 5 + )}`; + + functionSerializationImports.add( + `import { ${importName} as ${hashedImportName} } from '${importPath}';` + ); + + return `${hashedImportName}(${args + .map((arg) => + stringifyExports( + functionSerializationImports, + arg, + unusedCompositionRegex, + key, + exportLookup + ) + ) + .join(",")})`; + } catch (err) { + console.error(err); + + throw new Error("Invalid function serialization params"); + } + } + + throw new Error(outdent` + Invalid exports. + You can only export plain objects, arrays, strings, numbers and null/undefined. + `); + }, + 0, + { + references: true, // Allow circular references + maxDepth: Infinity, + maxValues: Infinity, + } + ); +} + +const defaultExportName = "__default__"; + +export function serializeVanillaModule( + cssImports: Array, + exports: Record, + unusedCompositionRegex: RegExp | null +) { + let functionSerializationImports = new Set(); + let exportLookup = new Map( + Object.entries(exports).map(([key, value]) => [ + value, + key === "default" ? defaultExportName : key, + ]) + ); + + let moduleExports = Object.keys(exports).map((key) => { + let serializedExport = stringifyExports( + functionSerializationImports, + exports[key], + unusedCompositionRegex, + key === "default" ? defaultExportName : key, + exportLookup + ); + + if (key === "default") { + return [ + `var ${defaultExportName} = ${serializedExport};`, + `export default ${defaultExportName};`, + ].join("\n"); + } + + return `export var ${key} = ${serializedExport};`; + }); + + let outputCode = [ + ...cssImports, + ...functionSerializationImports, + ...moduleExports, + ]; + + return outputCode.join("\n"); +} diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts new file mode 100644 index 00000000000..78e717a0fde --- /dev/null +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts @@ -0,0 +1,294 @@ +import { pathToFileURL, fileURLToPath } from "url"; +import { relative } from "path"; +import { setAdapter, removeAdapter } from "@vanilla-extract/css/adapter"; +import { transformCss } from "@vanilla-extract/css/transformCss"; +import { + cssFileFilter, + getPackageInfo, + transform, +} from "@vanilla-extract/integration"; +import { resolvePath } from "mlly"; +import type { ModuleNode } from "vite"; +import { createServer } from "vite"; +import { ViteNodeRunner } from "vite-node/client"; +import { ViteNodeServer } from "vite-node/server"; +import type { Adapter } from "@vanilla-extract/css"; + +import { lock } from "./lock"; +import { + serializeVanillaModule, + stringifyFileScope, +} from "./processVanillaFile"; + +type Css = Parameters[0]; +type Composition = Parameters[0]; + +const scanModule = ( + entryModule: ModuleNode, + root: string, + cssCache: Map +) => { + let queue = [entryModule]; + let cssDeps = new Set(); + let watchFiles = new Set(); + + for (let moduleNode of queue) { + let relativePath = moduleNode.id && relative(root, moduleNode.id); + + if (relativePath && cssCache.has(relativePath)) { + cssDeps.add(relativePath!); + } + + if (moduleNode.file) { + watchFiles.add(moduleNode.file); + } + + for (let importedModule of moduleNode.importedModules) { + queue.push(importedModule); + } + } + + return { cssDeps, watchFiles }; +}; + +const createViteServer = async (root: string) => { + let pkg = getPackageInfo(root); + + let server = await createServer({ + root, + server: { + hmr: false, + }, + logLevel: "silent", + optimizeDeps: { + disabled: true, + }, + ssr: { + noExternal: true, + }, + plugins: [ + { + name: "vanilla-extract-externalize", + enforce: "pre", + async resolveId(source, importer) { + if (source.startsWith("@vanilla-extract/")) { + return { + external: true, + id: await resolvePath(source, { url: pathToFileURL(importer!) }), + }; + } + }, + }, + { + name: "vanilla-extract-transform", + async transform(code, id) { + if (cssFileFilter.test(id)) { + let filescopedCode = await transform({ + source: code, + rootPath: root, + filePath: id, + packageName: pkg.name, + identOption: "debug", + }); + + return filescopedCode; + } + }, + }, + ], + }); + + // this is need to initialize the plugins + await server.pluginContainer.buildStart({}); + + let node = new ViteNodeServer(server); + + let runner = new ViteNodeRunner({ + root, + base: server.config.base, + fetchModule(id) { + return node.fetchModule(id); + }, + resolveId(id, importer) { + return node.resolveId(id, importer); + }, + }); + + server.watcher.on("change", (filePath) => { + runner.moduleCache.invalidateDepTree([filePath]); + }); + + return { + server, + runner, + }; +}; + +export interface Compiler { + processVanillaFile( + filePath: string, + outputCss: boolean + ): Promise<{ source: string; watchFiles: Set }>; + getCssForFile(virtualCssFilePath: string): { filePath: string; css: string }; + close(): Promise; +} + +export interface CreateCompilerParams { + root: string; + toCssImport: (filePath: string) => string; +} +export const createVanillaExtractCompiler = ({ + root, + toCssImport, +}: CreateCompilerParams): Compiler => { + let vitePromise = createViteServer(root); + + let cssCache = new Map< + string, + { + css: string; + localClassNames: Set; + composedClassLists: Array; + usedCompositions: Set; + } + >(); + + return { + async processVanillaFile(filePath, outputCss) { + let { server, runner } = await vitePromise; + + let cssByFileScope = new Map>(); + let localClassNames = new Set(); + let composedClassLists: Array = []; + let usedCompositions = new Set(); + + let executedUrls: Array = []; + + let cssAdapter: Adapter = { + appendCss: (css, fileScope) => { + let fileScopeCss = cssByFileScope.get(fileScope.filePath) ?? []; + + fileScopeCss.push(css); + + cssByFileScope.set(fileScope.filePath, fileScopeCss); + }, + registerClassName: (className) => { + localClassNames.add(className); + }, + registerComposition: (composedClassList) => { + composedClassLists.push(composedClassList); + }, + markCompositionUsed: (identifier) => { + usedCompositions.add(identifier); + }, + onEndFileScope: (fileScope) => { + executedUrls.push(fileScope.filePath); + }, + getIdentOption: () => "debug", + }; + + let { fileExports, cssImports, watchFiles } = await lock(async () => { + setAdapter(cssAdapter); + + let fileExports = await runner.executeFile(filePath); + + let moduleNode = server.moduleGraph.getModuleById(filePath); + + if (!moduleNode) { + throw new Error(`Can't find ModuleNode for ${filePath}`); + } + + let cssImports = []; + + let { cssDeps, watchFiles } = scanModule(moduleNode, root, cssCache); + + for (let moduleId of cssDeps) { + let cssEntry = cssCache.get(moduleId); + + if (!cssEntry) { + throw new Error(`No CSS Entry found in cache for ${moduleId}`); + } + + cssImports.push(`import '${toCssImport(moduleId)}';`); + + cssEntry.localClassNames.forEach((localClassName) => { + localClassNames.add(localClassName); + }); + cssEntry.usedCompositions.forEach((usedComposition) => { + usedCompositions.add(usedComposition); + }); + composedClassLists.push(...cssEntry.composedClassLists); + } + + for (let url of executedUrls) { + let cssObjs = cssByFileScope.get(url); + if (!cssObjs) { + continue; + } + + let css = transformCss({ + localClassNames: Array.from(localClassNames), + composedClassLists, + cssObjs, + }).join("\n"); + + let moduleId = url; + + cssImports.push(`import '${toCssImport(moduleId)}';`); + + cssCache.set(moduleId, { + localClassNames, + composedClassLists, + usedCompositions, + css, + }); + } + + removeAdapter(); + + return { + fileExports, + cssImports: outputCss ? cssImports : [], + watchFiles, + }; + }); + + let unusedCompositions = composedClassLists + .filter(({ identifier }) => !usedCompositions.has(identifier)) + .map(({ identifier }) => identifier); + + let unusedCompositionRegex = + unusedCompositions.length > 0 + ? RegExp(`(${unusedCompositions.join("|")})\\s`, "g") + : null; + + return { + source: serializeVanillaModule( + cssImports, + fileExports, + unusedCompositionRegex + ), + watchFiles, + }; + }, + getCssForFile(filePath: string) { + let rootRelativePath = relative(root, filePath); + let result = cssCache.get(rootRelativePath); + + if (!result) { + throw new Error(`No CSS for file: ${filePath}`); + } + + return { + css: result.css, + filePath: rootRelativePath, + resolveDir: root, + }; + }, + async close() { + let { server } = await vitePromise; + + await server.close(); + }, + }; +}; diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts index e7e6cb0e42b..5a9741f3511 100644 --- a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts @@ -1,19 +1,24 @@ -import { dirname, join, extname } from "path"; +import { dirname, join, extname, basename, posix } from "path"; import type { IdentifierOption } from "@vanilla-extract/integration"; import { cssFileFilter, - virtualCssFileFilter, + // virtualCssFileFilter, processVanillaFile, getSourceFromVirtualCssFile, transform, } from "@vanilla-extract/integration"; import * as fse from "fs-extra"; -import * as esbuild from "esbuild"; +import type { Plugin, OutputFile, Loader } from "esbuild"; import type { RemixConfig } from "../../config"; import type { CompileOptions } from "../options"; -import { loaders } from "../loaders"; +// import { loaders } from "../loaders"; import { getPostcssProcessor } from "../utils/postcss"; +import { createVanillaExtractCompiler } from "./vanilla-extract/vanillaExtractCompiler"; + +let compiler: ReturnType; + +let virtualCssFileFilter = /\.vanilla\.css/; const pluginName = "vanilla-extract-plugin"; const namespace = `${pluginName}-ns`; @@ -26,10 +31,20 @@ export function vanillaExtractPlugin({ config: RemixConfig; mode: CompileOptions["mode"]; outputCss: boolean; -}): esbuild.Plugin { +}): Plugin { return { name: pluginName, async setup(build) { + let root = config.rootDirectory; + // let root = build.initialOptions.absWorkingDir || process.cwd(); + + compiler ||= createVanillaExtractCompiler({ + root, + toCssImport(filePath) { + return posix.relative(root, filePath) + ".vanilla.css"; + }, + }); + let postcssProcessor = await getPostcssProcessor({ config, context: { @@ -53,12 +68,18 @@ export function vanillaExtractPlugin({ build.onLoad( { filter: virtualCssFileFilter, namespace }, async ({ path }) => { - let { source, fileName } = await getSourceFromVirtualCssFile(path); - let resolveDir = dirname(join(rootDirectory, fileName)); + let [relativeFilePath] = path.split(".vanilla.css"); + + let { css, filePath } = compiler.getCssForFile( + posix.join(root, relativeFilePath) + ); + + // let { source, fileName } = await getSourceFromVirtualCssFile(path); + let resolveDir = dirname(join(rootDirectory, filePath)); if (postcssProcessor) { - source = ( - await postcssProcessor.process(source, { + css = ( + await postcssProcessor.process(css, { from: path, to: path, }) @@ -66,7 +87,7 @@ export function vanillaExtractPlugin({ } return { - contents: source, + contents: css, loader: "css", resolveDir, }; @@ -74,57 +95,26 @@ export function vanillaExtractPlugin({ ); build.onLoad({ filter: cssFileFilter }, async ({ path: filePath }) => { - let identOption: IdentifierOption = - mode === "production" ? "short" : "debug"; - - let { outputFiles } = await esbuild.build({ - entryPoints: [filePath], - outdir: config.assetsBuildDirectory, - assetNames: build.initialOptions.assetNames, - bundle: true, - external: ["@vanilla-extract"], - platform: "node", - write: false, - plugins: [ - vanillaExtractSideEffectsPlugin, - vanillaExtractTransformPlugin({ rootDirectory, identOption }), - ], - loader: loaders, - absWorkingDir: rootDirectory, - publicPath: config.publicPath, - }); + // let identOption: IdentifierOption = + // mode === "production" ? "short" : "debug"; - let source = outputFiles.find((file) => - file.path.endsWith(".js") - )?.text; - - if (!source) { - return null; - } - - let [contents] = await Promise.all([ - processVanillaFile({ - source, - filePath, - outputCss, - identOption, - }), - outputCss && writeAssets(outputFiles), - ]); + let { source, watchFiles } = await compiler.processVanillaFile( + filePath, + outputCss + ); return { - contents, + contents: source, resolveDir: dirname(filePath), loader: "js", + watchFiles: Array.from(watchFiles || []), }; }); }, }; } -async function writeAssets( - outputFiles: Array -): Promise { +async function writeAssets(outputFiles: Array): Promise { await Promise.all( outputFiles .filter((file) => !file.path.endsWith(".js")) @@ -135,7 +125,7 @@ async function writeAssets( ); } -const loaderForExtension: Record = { +const loaderForExtension: Record = { ".js": "js", ".jsx": "jsx", ".ts": "ts", @@ -155,7 +145,7 @@ function vanillaExtractTransformPlugin({ }: { identOption: IdentifierOption; rootDirectory: string; -}): esbuild.Plugin { +}): Plugin { return { name: "vanilla-extract-transform-plugin", setup(build) { @@ -185,7 +175,7 @@ function vanillaExtractTransformPlugin({ * to ensure that all usages of `globalStyle` are included in the CSS bundle, * even if a .css.ts/js file has no exports or is otherwise tree-shaken. */ -const vanillaExtractSideEffectsPlugin: esbuild.Plugin = { +const vanillaExtractSideEffectsPlugin: Plugin = { name: "vanilla-extract-side-effects-plugin", setup(build) { let preventInfiniteLoop = {}; diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json index 5ab257046d1..cce5913d266 100644 --- a/packages/remix-dev/package.json +++ b/packages/remix-dev/package.json @@ -30,6 +30,7 @@ "@esbuild-plugins/node-modules-polyfill": "^0.1.4", "@npmcli/package-json": "^2.0.0", "@remix-run/server-runtime": "1.13.0", + "@vanilla-extract/css": "^1.9.5", "@vanilla-extract/integration": "^6.0.2", "arg": "^5.0.1", "cacache": "^15.0.5", @@ -45,18 +46,21 @@ "get-port": "^5.1.1", "gunzip-maybe": "^1.4.2", "inquirer": "^8.2.1", + "javascript-stringify": "^2.1.0", "jsesc": "3.0.2", "json5": "^2.2.1", - "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", + "lodash": "^4.17.21", "lru-cache": "^7.14.1", "minimatch": "^3.0.4", + "mlly": "^1.1.1", "node-fetch": "^2.6.7", "ora": "^5.4.1", - "postcss": "^8.4.19", + "outdent": "^0.8.0", "postcss-discard-duplicates": "^5.1.0", "postcss-load-config": "^4.0.1", "postcss-modules": "^6.0.0", + "postcss": "^8.4.19", "prettier": "2.7.1", "pretty-ms": "^7.0.1", "proxy-agent": "^5.0.0", @@ -67,6 +71,8 @@ "sort-package-json": "^1.55.0", "tar-fs": "^2.1.1", "tsconfig-paths": "^4.0.0", + "vite-node": "~0.28.5", + "vite": "~4.1.1", "ws": "^7.4.5", "xdm": "^2.0.0" }, diff --git a/yarn.lock b/yarn.lock index d318cafb547..312930cb1bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3396,6 +3396,23 @@ media-query-parser "^2.0.2" outdent "^0.8.0" +"@vanilla-extract/css@^1.9.5": + version "1.9.5" + resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.9.5.tgz#c5361c04045e6f01502564c2fb6b82177b97f6bc" + integrity sha512-aVSv6q24zelKRtWx/l9yshU3gD1uCDMZ2ZGcIiYnAcPfyLryrG/1X5DxtyiPKcyI/hZWoteHofsN//2q9MvzOA== + dependencies: + "@emotion/hash" "^0.9.0" + "@vanilla-extract/private" "^1.0.3" + ahocorasick "1.0.2" + chalk "^4.1.1" + css-what "^5.0.1" + cssesc "^3.0.0" + csstype "^3.0.7" + deep-object-diff "^1.1.9" + deepmerge "^4.2.2" + media-query-parser "^2.0.2" + outdent "^0.8.0" + "@vanilla-extract/integration@^6.0.2": version "6.0.2" resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-6.0.2.tgz#ff9f03ef0d1d0fedc681f15f450af2dc52b0e60f" @@ -3544,6 +3561,11 @@ acorn@^8.2.4: resolved "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz" integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== +acorn@^8.8.1: + version "8.8.2" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -4382,6 +4404,11 @@ bytes@3.1.2: resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + cacache@^15.0.5: version "15.3.0" resolved "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz" @@ -5215,7 +5242,7 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -deep-object-diff@^1.1.0: +deep-object-diff@^1.1.0, deep-object-diff@^1.1.9: version "1.1.9" resolved "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz#6df7ef035ad6a0caa44479c536ed7b02570f4595" integrity sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA== @@ -5783,7 +5810,7 @@ esbuild@0.16.3: "@esbuild/win32-ia32" "0.16.3" "@esbuild/win32-x64" "0.16.3" -esbuild@^0.16.3: +esbuild@^0.16.14, esbuild@^0.16.3: version "0.16.17" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259" integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg== @@ -7791,7 +7818,7 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -javascript-stringify@^2.0.1: +javascript-stringify@^2.0.1, javascript-stringify@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79" integrity sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg== @@ -8376,6 +8403,11 @@ json5@^2.2.2: resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonc-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" @@ -9573,6 +9605,16 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mlly@^1.0.0, mlly@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/mlly/-/mlly-1.1.0.tgz#9e23c5e675ef7b10cc47ee6281795cb1a7aa3aa2" + integrity sha512-cwzBrBfwGC1gYJyfcy8TcZU1f+dbH/T+TuOhtYP2wLv/Fb51/uV7HJQfBPtEupZ2ORLRU1EKFS/QfS3eo9+kBQ== + dependencies: + acorn "^8.8.1" + pathe "^1.0.0" + pkg-types "^1.0.1" + ufo "^1.0.1" + morgan@^1.10.0: version "1.10.0" resolved "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz" @@ -10203,6 +10245,11 @@ path-type@^4.0.0: resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pathe@^1.0.0, pathe@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/pathe/-/pathe-1.1.0.tgz#e2e13f6c62b31a3289af4ba19886c230f295ec03" + integrity sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w== + peek-stream@^1.1.0: version "1.1.3" resolved "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz" @@ -10277,6 +10324,15 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-types@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz#25234407f9dc63409af45ced9407625ff446a761" + integrity sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g== + dependencies: + jsonc-parser "^3.2.0" + mlly "^1.0.0" + pathe "^1.0.0" + playwright-core@1.28.1: version "1.28.1" resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.1.tgz#8400be9f4a8d1c0489abdb9e75a4cc0ffc3c00cb" @@ -10386,7 +10442,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^ resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.18: +postcss@^8.4.18, postcss@^8.4.21: version "8.4.21" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== @@ -11181,6 +11237,13 @@ rollup@^2.36.1: optionalDependencies: fsevents "~2.3.2" +rollup@^3.10.0: + version "3.15.0" + resolved "https://registry.npmjs.org/rollup/-/rollup-3.15.0.tgz#6f4105e8c4b8145229657b74ad660b02fbfacc05" + integrity sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg== + optionalDependencies: + fsevents "~2.3.2" + run-async@^2.4.0: version "2.4.1" resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz" @@ -12329,6 +12392,11 @@ typescript@^4.8.4: resolved "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== +ufo@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/ufo/-/ufo-1.0.1.tgz#64ed43b530706bda2e4892f911f568cf4cf67d29" + integrity sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA== + uid-safe@2.1.5, uid-safe@^2.1.5: version "2.1.5" resolved "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz" @@ -12699,6 +12767,32 @@ vfile@^5.1.0: unist-util-stringify-position "^3.0.0" vfile-message "^3.0.0" +vite-node@~0.28.5: + version "0.28.5" + resolved "https://registry.npmjs.org/vite-node/-/vite-node-0.28.5.tgz#56d0f78846ea40fddf2e28390899df52a4738006" + integrity sha512-LmXb9saMGlrMZbXTvOveJKwMTBTNUH66c8rJnQ0ZPNX+myPEol64+szRzXtV5ORb0Hb/91yq+/D3oERoyAt6LA== + dependencies: + cac "^6.7.14" + debug "^4.3.4" + mlly "^1.1.0" + pathe "^1.1.0" + picocolors "^1.0.0" + source-map "^0.6.1" + source-map-support "^0.5.21" + vite "^3.0.0 || ^4.0.0" + +"vite@^3.0.0 || ^4.0.0", vite@~4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/vite/-/vite-4.1.1.tgz#3b18b81a4e85ce3df5cbdbf4c687d93ebf402e6b" + integrity sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg== + dependencies: + esbuild "^0.16.14" + postcss "^8.4.21" + resolve "^1.22.1" + rollup "^3.10.0" + optionalDependencies: + fsevents "~2.3.2" + vm2@^3.9.8: version "3.9.11" resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.11.tgz" From e73ee52c47e8e90ff91841ed09947674c21512b4 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Mon, 20 Feb 2023 16:35:46 +1100 Subject: [PATCH 02/21] Always use `scanModule` to get module order --- .../vanilla-extract/vanillaExtractCompiler.ts | 95 ++++++++----------- 1 file changed, 39 insertions(+), 56 deletions(-) diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts index 78e717a0fde..ed6c37453ce 100644 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts @@ -1,4 +1,4 @@ -import { pathToFileURL, fileURLToPath } from "url"; +import { pathToFileURL } from "url"; import { relative } from "path"; import { setAdapter, removeAdapter } from "@vanilla-extract/css/adapter"; import { transformCss } from "@vanilla-extract/css/transformCss"; @@ -15,19 +15,12 @@ import { ViteNodeServer } from "vite-node/server"; import type { Adapter } from "@vanilla-extract/css"; import { lock } from "./lock"; -import { - serializeVanillaModule, - stringifyFileScope, -} from "./processVanillaFile"; +import { serializeVanillaModule } from "./processVanillaFile"; type Css = Parameters[0]; type Composition = Parameters[0]; -const scanModule = ( - entryModule: ModuleNode, - root: string, - cssCache: Map -) => { +const scanModule = (entryModule: ModuleNode, root: string) => { let queue = [entryModule]; let cssDeps = new Set(); let watchFiles = new Set(); @@ -35,8 +28,8 @@ const scanModule = ( for (let moduleNode of queue) { let relativePath = moduleNode.id && relative(root, moduleNode.id); - if (relativePath && cssCache.has(relativePath)) { - cssDeps.add(relativePath!); + if (relativePath) { + cssDeps.add(relativePath); } if (moduleNode.file) { @@ -48,7 +41,11 @@ const scanModule = ( } } - return { cssDeps, watchFiles }; + // This ensures the root module's styles are last in terms of CSS ordering. We + // should probably find a way to avoid the need for this. + let [head, ...tail] = cssDeps; + + return { cssDeps: new Set([...tail, head]), watchFiles }; }; const createViteServer = async (root: string) => { @@ -143,7 +140,7 @@ export const createVanillaExtractCompiler = ({ }: CreateCompilerParams): Compiler => { let vitePromise = createViteServer(root); - let cssCache = new Map< + let adapterResultCache = new Map< string, { css: string; @@ -162,14 +159,10 @@ export const createVanillaExtractCompiler = ({ let composedClassLists: Array = []; let usedCompositions = new Set(); - let executedUrls: Array = []; - let cssAdapter: Adapter = { appendCss: (css, fileScope) => { let fileScopeCss = cssByFileScope.get(fileScope.filePath) ?? []; - fileScopeCss.push(css); - cssByFileScope.set(fileScope.filePath, fileScopeCss); }, registerClassName: (className) => { @@ -181,9 +174,7 @@ export const createVanillaExtractCompiler = ({ markCompositionUsed: (identifier) => { usedCompositions.add(identifier); }, - onEndFileScope: (fileScope) => { - executedUrls.push(fileScope.filePath); - }, + onEndFileScope: () => {}, getIdentOption: () => "debug", }; @@ -200,48 +191,40 @@ export const createVanillaExtractCompiler = ({ let cssImports = []; - let { cssDeps, watchFiles } = scanModule(moduleNode, root, cssCache); + let { cssDeps, watchFiles } = scanModule(moduleNode, root); for (let moduleId of cssDeps) { - let cssEntry = cssCache.get(moduleId); - - if (!cssEntry) { - throw new Error(`No CSS Entry found in cache for ${moduleId}`); - } - - cssImports.push(`import '${toCssImport(moduleId)}';`); - - cssEntry.localClassNames.forEach((localClassName) => { - localClassNames.add(localClassName); - }); - cssEntry.usedCompositions.forEach((usedComposition) => { - usedCompositions.add(usedComposition); - }); - composedClassLists.push(...cssEntry.composedClassLists); - } + let cssObjs = cssByFileScope.get(moduleId); + let cachedAdapterResult = adapterResultCache.get(moduleId); - for (let url of executedUrls) { - let cssObjs = cssByFileScope.get(url); - if (!cssObjs) { + if (!cssObjs && !cachedAdapterResult) { continue; } - let css = transformCss({ - localClassNames: Array.from(localClassNames), - composedClassLists, - cssObjs, - }).join("\n"); - - let moduleId = url; + if (cssObjs) { + let css = transformCss({ + localClassNames: Array.from(localClassNames), + composedClassLists, + cssObjs, + }).join("\n"); + + adapterResultCache.set(moduleId, { + localClassNames, + composedClassLists, + usedCompositions, + css, + }); + } else if (cachedAdapterResult) { + cachedAdapterResult.localClassNames.forEach((localClassName) => { + localClassNames.add(localClassName); + }); + cachedAdapterResult.usedCompositions.forEach((usedComposition) => { + usedCompositions.add(usedComposition); + }); + composedClassLists.push(...cachedAdapterResult.composedClassLists); + } cssImports.push(`import '${toCssImport(moduleId)}';`); - - cssCache.set(moduleId, { - localClassNames, - composedClassLists, - usedCompositions, - css, - }); } removeAdapter(); @@ -273,7 +256,7 @@ export const createVanillaExtractCompiler = ({ }, getCssForFile(filePath: string) { let rootRelativePath = relative(root, filePath); - let result = cssCache.get(rootRelativePath); + let result = adapterResultCache.get(rootRelativePath); if (!result) { throw new Error(`No CSS for file: ${filePath}`); From 6d91bcd3663bcf4f668dedbc2cf039c9ed9ad592 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Tue, 21 Feb 2023 11:12:57 +1100 Subject: [PATCH 03/21] Handle lock errors, identOption and app dir alias --- .../compiler/plugins/vanilla-extract/lock.ts | 56 ++++++++++--------- .../vanilla-extract/vanillaExtractCompiler.ts | 32 +++++++++-- .../compiler/plugins/vanillaExtractPlugin.ts | 34 +++++------ 3 files changed, 70 insertions(+), 52 deletions(-) diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts index 6ed17c7a2a4..2e1a2c3a9f2 100644 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts @@ -1,33 +1,37 @@ -const queue: Array<() => Promise> = []; -let isRunning = false; +type AsyncFunction = () => Promise; -export const lock = async (fn: () => Promise): Promise => { - let executeNextTask = () => { - const nextTask = queue.pop(); +let queue: Array<() => void> = []; +let isProcessingQueue = false; - if (nextTask) { - nextTask(); - } else { - isRunning = false; - } - }; +export async function lock(fn: AsyncFunction): Promise { + return new Promise((resolve, reject) => { + let queueFn = async () => { + try { + let result = await fn(); + resolve(result); + } catch (error) { + reject(error); + } finally { + isProcessingQueue = false; + processQueue(); + } + }; - if (!isRunning) { - isRunning = true; - let result = await fn(); + queue.push(queueFn); - executeNextTask(); + if (!isProcessingQueue) { + processQueue(); + } + }); +} - return result; - } else { - return new Promise((resolve) => { - queue.push(async () => { - let result = await fn(); +async function processQueue() { + if (isProcessingQueue || queue.length === 0) { + return; + } - resolve(result); + isProcessingQueue = true; + let fn = queue.shift()!; - executeNextTask(); - }); - }); - } -}; + await fn(); +} diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts index ed6c37453ce..fb4b7446dff 100644 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts @@ -2,13 +2,14 @@ import { pathToFileURL } from "url"; import { relative } from "path"; import { setAdapter, removeAdapter } from "@vanilla-extract/css/adapter"; import { transformCss } from "@vanilla-extract/css/transformCss"; +import type { IdentifierOption } from "@vanilla-extract/integration"; import { cssFileFilter, getPackageInfo, transform, } from "@vanilla-extract/integration"; import { resolvePath } from "mlly"; -import type { ModuleNode } from "vite"; +import type { AliasOptions, ModuleNode } from "vite"; import { createServer } from "vite"; import { ViteNodeRunner } from "vite-node/client"; import { ViteNodeServer } from "vite-node/server"; @@ -45,10 +46,18 @@ const scanModule = (entryModule: ModuleNode, root: string) => { // should probably find a way to avoid the need for this. let [head, ...tail] = cssDeps; - return { cssDeps: new Set([...tail, head]), watchFiles }; + return { cssDeps: [...tail, head], watchFiles }; }; -const createViteServer = async (root: string) => { +const createViteServer = async ({ + root, + identOption, + alias, +}: { + root: string; + identOption: IdentifierOption; + alias?: AliasOptions; +}) => { let pkg = getPackageInfo(root); let server = await createServer({ @@ -63,6 +72,9 @@ const createViteServer = async (root: string) => { ssr: { noExternal: true, }, + resolve: { + alias, + }, plugins: [ { name: "vanilla-extract-externalize", @@ -85,7 +97,7 @@ const createViteServer = async (root: string) => { rootPath: root, filePath: id, packageName: pkg.name, - identOption: "debug", + identOption, }); return filescopedCode; @@ -132,13 +144,21 @@ export interface Compiler { export interface CreateCompilerParams { root: string; + identOption: IdentifierOption; toCssImport: (filePath: string) => string; + alias?: AliasOptions; } export const createVanillaExtractCompiler = ({ root, + identOption, toCssImport, + alias, }: CreateCompilerParams): Compiler => { - let vitePromise = createViteServer(root); + let vitePromise = createViteServer({ + root, + identOption, + alias, + }); let adapterResultCache = new Map< string, @@ -175,7 +195,7 @@ export const createVanillaExtractCompiler = ({ usedCompositions.add(identifier); }, onEndFileScope: () => {}, - getIdentOption: () => "debug", + getIdentOption: () => identOption, }; let { fileExports, cssImports, watchFiles } = await lock(async () => { diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts index 5a9741f3511..bd15d30e28d 100644 --- a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts @@ -1,18 +1,11 @@ -import { dirname, join, extname, basename, posix } from "path"; +import { dirname, join, extname, posix } from "path"; import type { IdentifierOption } from "@vanilla-extract/integration"; -import { - cssFileFilter, - // virtualCssFileFilter, - processVanillaFile, - getSourceFromVirtualCssFile, - transform, -} from "@vanilla-extract/integration"; +import { cssFileFilter, transform } from "@vanilla-extract/integration"; import * as fse from "fs-extra"; import type { Plugin, OutputFile, Loader } from "esbuild"; import type { RemixConfig } from "../../config"; import type { CompileOptions } from "../options"; -// import { loaders } from "../loaders"; import { getPostcssProcessor } from "../utils/postcss"; import { createVanillaExtractCompiler } from "./vanilla-extract/vanillaExtractCompiler"; @@ -36,14 +29,19 @@ export function vanillaExtractPlugin({ name: pluginName, async setup(build) { let root = config.rootDirectory; - // let root = build.initialOptions.absWorkingDir || process.cwd(); - compiler ||= createVanillaExtractCompiler({ - root, - toCssImport(filePath) { - return posix.relative(root, filePath) + ".vanilla.css"; - }, - }); + compiler = + compiler || + createVanillaExtractCompiler({ + root, + identOption: mode === "production" ? "short" : "debug", + toCssImport(filePath) { + return posix.relative(root, filePath) + ".vanilla.css"; + }, + alias: { + "~": config.appDirectory, + }, + }); let postcssProcessor = await getPostcssProcessor({ config, @@ -74,7 +72,6 @@ export function vanillaExtractPlugin({ posix.join(root, relativeFilePath) ); - // let { source, fileName } = await getSourceFromVirtualCssFile(path); let resolveDir = dirname(join(rootDirectory, filePath)); if (postcssProcessor) { @@ -95,9 +92,6 @@ export function vanillaExtractPlugin({ ); build.onLoad({ filter: cssFileFilter }, async ({ path: filePath }) => { - // let identOption: IdentifierOption = - // mode === "production" ? "short" : "debug"; - let { source, watchFiles } = await compiler.processVanillaFile( filePath, outputCss From 33631241dc8b3bc284f00fba5244dc44823fcd00 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Tue, 21 Feb 2023 15:28:44 +1100 Subject: [PATCH 04/21] Handle relative static assets --- .../vanilla-extract/vanillaExtractCompiler.ts | 8 ++++- .../compiler/plugins/vanillaExtractPlugin.ts | 36 +++++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts index fb4b7446dff..6c43aa87518 100644 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts @@ -9,7 +9,7 @@ import { transform, } from "@vanilla-extract/integration"; import { resolvePath } from "mlly"; -import type { AliasOptions, ModuleNode } from "vite"; +import type { AliasOptions, ModuleNode, Plugin as VitePlugin } from "vite"; import { createServer } from "vite"; import { ViteNodeRunner } from "vite-node/client"; import { ViteNodeServer } from "vite-node/server"; @@ -53,10 +53,12 @@ const createViteServer = async ({ root, identOption, alias, + vitePlugins = [], }: { root: string; identOption: IdentifierOption; alias?: AliasOptions; + vitePlugins?: Array; }) => { let pkg = getPackageInfo(root); @@ -104,6 +106,7 @@ const createViteServer = async ({ } }, }, + ...vitePlugins, ], }); @@ -147,17 +150,20 @@ export interface CreateCompilerParams { identOption: IdentifierOption; toCssImport: (filePath: string) => string; alias?: AliasOptions; + vitePlugins?: Array; } export const createVanillaExtractCompiler = ({ root, identOption, toCssImport, alias, + vitePlugins, }: CreateCompilerParams): Compiler => { let vitePromise = createViteServer({ root, identOption, alias, + vitePlugins, }); let adapterResultCache = new Map< diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts index bd15d30e28d..ab71a451e31 100644 --- a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts @@ -6,13 +6,21 @@ import type { Plugin, OutputFile, Loader } from "esbuild"; import type { RemixConfig } from "../../config"; import type { CompileOptions } from "../options"; +import { loaders } from "../loaders"; import { getPostcssProcessor } from "../utils/postcss"; import { createVanillaExtractCompiler } from "./vanilla-extract/vanillaExtractCompiler"; let compiler: ReturnType; +let virtualCssFileSuffix = ".vanilla.css"; let virtualCssFileFilter = /\.vanilla\.css/; +const staticFileRegexp = new RegExp( + `(${Object.keys(loaders) + .filter((ext) => loaders[ext] === "file") + .join("|")})$` +); + const pluginName = "vanilla-extract-plugin"; const namespace = `${pluginName}-ns`; @@ -28,7 +36,7 @@ export function vanillaExtractPlugin({ return { name: pluginName, async setup(build) { - let root = config.rootDirectory; + let root = config.appDirectory; compiler = compiler || @@ -36,11 +44,28 @@ export function vanillaExtractPlugin({ root, identOption: mode === "production" ? "short" : "debug", toCssImport(filePath) { - return posix.relative(root, filePath) + ".vanilla.css"; + return filePath + virtualCssFileSuffix; }, alias: { - "~": config.appDirectory, + "~": root, }, + vitePlugins: [ + { + name: "remix-assets", + enforce: "pre", + async resolveId(source) { + if (source.startsWith("/") && staticFileRegexp.test(source)) { + return { + external: true, + id: "~" + source, + }; + } + }, + transform(code) { + return code.replace(/\/@fs\/~\//g, "~/"); + }, + }, + ], }); let postcssProcessor = await getPostcssProcessor({ @@ -49,7 +74,6 @@ export function vanillaExtractPlugin({ vanillaExtract: true, }, }); - let { rootDirectory } = config; // Resolve virtual CSS files first to avoid resolving the same // file multiple times since this filter is more specific and @@ -66,13 +90,13 @@ export function vanillaExtractPlugin({ build.onLoad( { filter: virtualCssFileFilter, namespace }, async ({ path }) => { - let [relativeFilePath] = path.split(".vanilla.css"); + let [relativeFilePath] = path.split(virtualCssFileSuffix); let { css, filePath } = compiler.getCssForFile( posix.join(root, relativeFilePath) ); - let resolveDir = dirname(join(rootDirectory, filePath)); + let resolveDir = dirname(join(root, filePath)); if (postcssProcessor) { css = ( From c9626307d9602ef17212d9ae2ce7aa7382e0d417 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Tue, 21 Feb 2023 16:34:20 +1100 Subject: [PATCH 05/21] Handle root relative imports in VE build --- .../vanilla-extract/vanillaExtractCompiler.ts | 10 +-- .../compiler/plugins/vanillaExtractPlugin.ts | 75 +++---------------- 2 files changed, 11 insertions(+), 74 deletions(-) diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts index 6c43aa87518..72105baa385 100644 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts @@ -9,7 +9,7 @@ import { transform, } from "@vanilla-extract/integration"; import { resolvePath } from "mlly"; -import type { AliasOptions, ModuleNode, Plugin as VitePlugin } from "vite"; +import type { ModuleNode, Plugin as VitePlugin } from "vite"; import { createServer } from "vite"; import { ViteNodeRunner } from "vite-node/client"; import { ViteNodeServer } from "vite-node/server"; @@ -52,12 +52,10 @@ const scanModule = (entryModule: ModuleNode, root: string) => { const createViteServer = async ({ root, identOption, - alias, vitePlugins = [], }: { root: string; identOption: IdentifierOption; - alias?: AliasOptions; vitePlugins?: Array; }) => { let pkg = getPackageInfo(root); @@ -74,9 +72,6 @@ const createViteServer = async ({ ssr: { noExternal: true, }, - resolve: { - alias, - }, plugins: [ { name: "vanilla-extract-externalize", @@ -149,20 +144,17 @@ export interface CreateCompilerParams { root: string; identOption: IdentifierOption; toCssImport: (filePath: string) => string; - alias?: AliasOptions; vitePlugins?: Array; } export const createVanillaExtractCompiler = ({ root, identOption, toCssImport, - alias, vitePlugins, }: CreateCompilerParams): Compiler => { let vitePromise = createViteServer({ root, identOption, - alias, vitePlugins, }); diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts index ab71a451e31..cf38994825c 100644 --- a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts @@ -1,8 +1,6 @@ -import { dirname, join, extname, posix } from "path"; -import type { IdentifierOption } from "@vanilla-extract/integration"; -import { cssFileFilter, transform } from "@vanilla-extract/integration"; -import * as fse from "fs-extra"; -import type { Plugin, OutputFile, Loader } from "esbuild"; +import { dirname, join, posix } from "path"; +import { cssFileFilter } from "@vanilla-extract/integration"; +import type { Plugin } from "esbuild"; import type { RemixConfig } from "../../config"; import type { CompileOptions } from "../options"; @@ -17,7 +15,7 @@ let virtualCssFileFilter = /\.vanilla\.css/; const staticFileRegexp = new RegExp( `(${Object.keys(loaders) - .filter((ext) => loaders[ext] === "file") + .filter((ext) => ext !== ".css" && loaders[ext] === "file") .join("|")})$` ); @@ -46,14 +44,17 @@ export function vanillaExtractPlugin({ toCssImport(filePath) { return filePath + virtualCssFileSuffix; }, - alias: { - "~": root, - }, vitePlugins: [ { name: "remix-assets", enforce: "pre", async resolveId(source) { + if (source.startsWith("~")) { + return this.resolve( + posix.join(root, source.replace("~", "")) + ); + } + if (source.startsWith("/") && staticFileRegexp.test(source)) { return { external: true, @@ -132,62 +133,6 @@ export function vanillaExtractPlugin({ }; } -async function writeAssets(outputFiles: Array): Promise { - await Promise.all( - outputFiles - .filter((file) => !file.path.endsWith(".js")) - .map(async (file) => { - await fse.ensureDir(dirname(file.path)); - await fse.writeFile(file.path, file.contents); - }) - ); -} - -const loaderForExtension: Record = { - ".js": "js", - ".jsx": "jsx", - ".ts": "ts", - ".tsx": "tsx", -}; - -/** - * This plugin is used within the child compilation. It applies the Vanilla - * Extract file transform to all .css.ts/js files. This is used to add "file - * scope" annotations, which is done via function calls at the beginning and end - * of each file so that we can tell which CSS file the styles belong to when - * evaluating the JS. It's also done to automatically apply debug IDs. - */ -function vanillaExtractTransformPlugin({ - rootDirectory, - identOption, -}: { - identOption: IdentifierOption; - rootDirectory: string; -}): Plugin { - return { - name: "vanilla-extract-transform-plugin", - setup(build) { - build.onLoad({ filter: cssFileFilter }, async ({ path }) => { - let source = await fse.readFile(path, "utf-8"); - - let contents = await transform({ - source, - filePath: path, - rootPath: rootDirectory, - packageName: "remix-app", // This option is designed to support scoping hashes for libraries, we can hard code an arbitrary value for simplicity - identOption, - }); - - return { - contents, - loader: loaderForExtension[extname(path)], - resolveDir: dirname(path), - }; - }); - }, - }; -} - /** * This plugin marks all .css.ts/js files as having side effects. This is * to ensure that all usages of `globalStyle` are included in the CSS bundle, From f9097fdba64f305360ad17f65dbedaeac928b1a8 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Wed, 22 Feb 2023 11:01:14 +1100 Subject: [PATCH 06/21] Cache calls to processVanillaFile --- .../vanilla-extract/vanillaExtractCompiler.ts | 142 +++++++++++------- 1 file changed, 91 insertions(+), 51 deletions(-) diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts index 72105baa385..faabe75d5c3 100644 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts @@ -140,6 +140,11 @@ export interface Compiler { close(): Promise; } +interface ProcessedVanillaFile { + source: string; + watchFiles: Set; +} + export interface CreateCompilerParams { root: string; identOption: IdentifierOption; @@ -168,10 +173,32 @@ export const createVanillaExtractCompiler = ({ } >(); + let processVanillaFileCache = new Map< + string, + { + lastInvalidationTimestamp: number; + result: ProcessedVanillaFile; + } + >(); + return { - async processVanillaFile(filePath, outputCss) { + async processVanillaFile( + filePath, + outputCss + ): Promise { let { server, runner } = await vitePromise; + let cachedFile = processVanillaFileCache.get(filePath); + if (cachedFile) { + let moduleNode = server.moduleGraph.getModuleById(filePath); + if ( + cachedFile.lastInvalidationTimestamp === + moduleNode?.lastInvalidationTimestamp + ) { + return cachedFile.result; + } + } + let cssByFileScope = new Map>(); let localClassNames = new Set(); let composedClassLists: Array = []; @@ -196,63 +223,69 @@ export const createVanillaExtractCompiler = ({ getIdentOption: () => identOption, }; - let { fileExports, cssImports, watchFiles } = await lock(async () => { - setAdapter(cssAdapter); - - let fileExports = await runner.executeFile(filePath); - - let moduleNode = server.moduleGraph.getModuleById(filePath); - - if (!moduleNode) { - throw new Error(`Can't find ModuleNode for ${filePath}`); - } - - let cssImports = []; + let { fileExports, cssImports, watchFiles, lastInvalidationTimestamp } = + await lock(async () => { + setAdapter(cssAdapter); - let { cssDeps, watchFiles } = scanModule(moduleNode, root); + let fileExports = await runner.executeFile(filePath); - for (let moduleId of cssDeps) { - let cssObjs = cssByFileScope.get(moduleId); - let cachedAdapterResult = adapterResultCache.get(moduleId); + let moduleNode = server.moduleGraph.getModuleById(filePath); - if (!cssObjs && !cachedAdapterResult) { - continue; + if (!moduleNode) { + throw new Error(`Can't find ModuleNode for ${filePath}`); } - if (cssObjs) { - let css = transformCss({ - localClassNames: Array.from(localClassNames), - composedClassLists, - cssObjs, - }).join("\n"); - - adapterResultCache.set(moduleId, { - localClassNames, - composedClassLists, - usedCompositions, - css, - }); - } else if (cachedAdapterResult) { - cachedAdapterResult.localClassNames.forEach((localClassName) => { - localClassNames.add(localClassName); - }); - cachedAdapterResult.usedCompositions.forEach((usedComposition) => { - usedCompositions.add(usedComposition); - }); - composedClassLists.push(...cachedAdapterResult.composedClassLists); + let cssImports = []; + + let { cssDeps, watchFiles } = scanModule(moduleNode, root); + + for (let cssDepModuleId of cssDeps) { + let cssObjs = cssByFileScope.get(cssDepModuleId); + let cachedAdapterResult = adapterResultCache.get(cssDepModuleId); + + if (!cssObjs && !cachedAdapterResult) { + continue; + } + + if (cssObjs) { + let css = transformCss({ + localClassNames: Array.from(localClassNames), + composedClassLists, + cssObjs, + }).join("\n"); + + adapterResultCache.set(cssDepModuleId, { + localClassNames, + composedClassLists, + usedCompositions, + css, + }); + } else if (cachedAdapterResult) { + cachedAdapterResult.localClassNames.forEach((localClassName) => { + localClassNames.add(localClassName); + }); + cachedAdapterResult.usedCompositions.forEach( + (usedComposition) => { + usedCompositions.add(usedComposition); + } + ); + composedClassLists.push( + ...cachedAdapterResult.composedClassLists + ); + } + + cssImports.push(`import '${toCssImport(cssDepModuleId)}';`); } - cssImports.push(`import '${toCssImport(moduleId)}';`); - } - - removeAdapter(); + removeAdapter(); - return { - fileExports, - cssImports: outputCss ? cssImports : [], - watchFiles, - }; - }); + return { + fileExports, + cssImports: outputCss ? cssImports : [], + watchFiles, + lastInvalidationTimestamp: moduleNode.lastInvalidationTimestamp, + }; + }); let unusedCompositions = composedClassLists .filter(({ identifier }) => !usedCompositions.has(identifier)) @@ -263,7 +296,7 @@ export const createVanillaExtractCompiler = ({ ? RegExp(`(${unusedCompositions.join("|")})\\s`, "g") : null; - return { + let result: ProcessedVanillaFile = { source: serializeVanillaModule( cssImports, fileExports, @@ -271,6 +304,13 @@ export const createVanillaExtractCompiler = ({ ), watchFiles, }; + + processVanillaFileCache.set(filePath, { + lastInvalidationTimestamp, + result, + }); + + return result; }, getCssForFile(filePath: string) { let rootRelativePath = relative(root, filePath); From 9b41846010b483f9ee0656844448fa4c0712361d Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Wed, 22 Feb 2023 16:39:10 +1100 Subject: [PATCH 07/21] Use consumer's css package, avoid mlly dependency --- .../vanilla-extract/vanillaExtractCompiler.ts | 34 ++++++++++++------- .../compiler/plugins/vanillaExtractPlugin.ts | 18 +++++----- packages/remix-dev/package.json | 1 - 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts index faabe75d5c3..b07257b16c4 100644 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts +++ b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts @@ -1,6 +1,4 @@ -import { pathToFileURL } from "url"; import { relative } from "path"; -import { setAdapter, removeAdapter } from "@vanilla-extract/css/adapter"; import { transformCss } from "@vanilla-extract/css/transformCss"; import type { IdentifierOption } from "@vanilla-extract/integration"; import { @@ -8,7 +6,6 @@ import { getPackageInfo, transform, } from "@vanilla-extract/integration"; -import { resolvePath } from "mlly"; import type { ModuleNode, Plugin as VitePlugin } from "vite"; import { createServer } from "vite"; import { ViteNodeRunner } from "vite-node/client"; @@ -21,6 +18,8 @@ import { serializeVanillaModule } from "./processVanillaFile"; type Css = Parameters[0]; type Composition = Parameters[0]; +const globalCssAdapterKey = "__ve_globalCssAdapter__"; + const scanModule = (entryModule: ModuleNode, root: string) => { let queue = [entryModule]; let cssDeps = new Set(); @@ -42,8 +41,7 @@ const scanModule = (entryModule: ModuleNode, root: string) => { } } - // This ensures the root module's styles are last in terms of CSS ordering. We - // should probably find a way to avoid the need for this. + // This ensures the root module's styles are last in terms of CSS ordering let [head, ...tail] = cssDeps; return { cssDeps: [...tail, head], watchFiles }; @@ -78,10 +76,11 @@ const createViteServer = async ({ enforce: "pre", async resolveId(source, importer) { if (source.startsWith("@vanilla-extract/")) { - return { - external: true, - id: await resolvePath(source, { url: pathToFileURL(importer!) }), - }; + let result = await this.resolve(source, importer, { + skipSelf: true, + }); + + return result ? { ...result, external: true } : null; } }, }, @@ -97,7 +96,15 @@ const createViteServer = async ({ identOption, }); - return filescopedCode; + return ` + import { + setAdapter as __ve_setAdapter__, + removeAdapter as __ve_removeAdapter__ + } from '@vanilla-extract/css/adapter'; + __ve_setAdapter__(global.${globalCssAdapterKey}); + ${filescopedCode}; + __ve_removeAdapter__(); + `; } }, }, @@ -225,7 +232,10 @@ export const createVanillaExtractCompiler = ({ let { fileExports, cssImports, watchFiles, lastInvalidationTimestamp } = await lock(async () => { - setAdapter(cssAdapter); + // @ts-expect-error We're adding this to the global context so it's + // available during the eval step, regardless of which + // `@vanilla-extract/css` package is used + global[globalCssAdapterKey] = cssAdapter; let fileExports = await runner.executeFile(filePath); @@ -277,8 +287,6 @@ export const createVanillaExtractCompiler = ({ cssImports.push(`import '${toCssImport(cssDepModuleId)}';`); } - removeAdapter(); - return { fileExports, cssImports: outputCss ? cssImports : [], diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts index cf38994825c..1d423567538 100644 --- a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts @@ -13,7 +13,7 @@ let compiler: ReturnType; let virtualCssFileSuffix = ".vanilla.css"; let virtualCssFileFilter = /\.vanilla\.css/; -const staticFileRegexp = new RegExp( +const staticAssetRegexp = new RegExp( `(${Object.keys(loaders) .filter((ext) => ext !== ".css" && loaders[ext] === "file") .join("|")})$` @@ -49,21 +49,23 @@ export function vanillaExtractPlugin({ name: "remix-assets", enforce: "pre", async resolveId(source) { + // Handle root-relative imports within Vanilla Extract files if (source.startsWith("~")) { - return this.resolve( - posix.join(root, source.replace("~", "")) - ); + return await this.resolve(source.replace("~", "")); } - - if (source.startsWith("/") && staticFileRegexp.test(source)) { + // Handle static asset JS imports + if (source.startsWith("/") && staticAssetRegexp.test(source)) { return { external: true, - id: "~" + source, + id: "__REMIX_STATIC_ASSET_PREFIX__" + source, }; } }, transform(code) { - return code.replace(/\/@fs\/~\//g, "~/"); + return code.replace( + /\/@fs\/__REMIX_STATIC_ASSET_PREFIX__\//g, + "~/" + ); }, }, ], diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json index cce5913d266..9c50346ef95 100644 --- a/packages/remix-dev/package.json +++ b/packages/remix-dev/package.json @@ -53,7 +53,6 @@ "lodash": "^4.17.21", "lru-cache": "^7.14.1", "minimatch": "^3.0.4", - "mlly": "^1.1.1", "node-fetch": "^2.6.7", "ora": "^5.4.1", "outdent": "^0.8.0", From d9c75cf88732c89d03c897eaec87b34b7eaa91d2 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Tue, 7 Mar 2023 09:08:39 +1100 Subject: [PATCH 08/21] Migrate to new official Vanilla Extract compiler --- .../compiler/plugins/vanilla-extract/hash.ts | 4 - .../compiler/plugins/vanilla-extract/lock.ts | 37 -- .../vanilla-extract/processVanillaFile.ts | 156 -------- .../vanilla-extract/vanillaExtractCompiler.ts | 343 ------------------ .../compiler/plugins/vanillaExtractPlugin.ts | 25 +- packages/remix-dev/package.json | 7 +- yarn.lock | 230 +++++++++--- 7 files changed, 197 insertions(+), 605 deletions(-) delete mode 100644 packages/remix-dev/compiler/plugins/vanilla-extract/hash.ts delete mode 100644 packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts delete mode 100644 packages/remix-dev/compiler/plugins/vanilla-extract/processVanillaFile.ts delete mode 100644 packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/hash.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/hash.ts deleted file mode 100644 index d06acf823fe..00000000000 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/hash.ts +++ /dev/null @@ -1,4 +0,0 @@ -import crypto from "crypto"; - -export const hash = (value: string) => - crypto.createHash("md5").update(value).digest("hex"); diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts deleted file mode 100644 index 2e1a2c3a9f2..00000000000 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/lock.ts +++ /dev/null @@ -1,37 +0,0 @@ -type AsyncFunction = () => Promise; - -let queue: Array<() => void> = []; -let isProcessingQueue = false; - -export async function lock(fn: AsyncFunction): Promise { - return new Promise((resolve, reject) => { - let queueFn = async () => { - try { - let result = await fn(); - resolve(result); - } catch (error) { - reject(error); - } finally { - isProcessingQueue = false; - processQueue(); - } - }; - - queue.push(queueFn); - - if (!isProcessingQueue) { - processQueue(); - } - }); -} - -async function processQueue() { - if (isProcessingQueue || queue.length === 0) { - return; - } - - isProcessingQueue = true; - let fn = queue.shift()!; - - await fn(); -} diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/processVanillaFile.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/processVanillaFile.ts deleted file mode 100644 index 2e50525fa72..00000000000 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/processVanillaFile.ts +++ /dev/null @@ -1,156 +0,0 @@ -import type { FileScope } from "@vanilla-extract/css"; -import { stringify } from "javascript-stringify"; -import isPlainObject from "lodash/isPlainObject"; -import outdent from "outdent"; - -import { hash } from "./hash"; - -export function stringifyFileScope({ - packageName, - filePath, -}: FileScope): string { - return packageName ? `${filePath}$$$${packageName}` : filePath; -} - -function stringifyExports( - functionSerializationImports: Set, - value: any, - unusedCompositionRegex: RegExp | null, - key: string, - exportLookup: Map -): any { - return stringify( - value, - (value, _indent, next) => { - let valueType = typeof value; - - if ( - valueType === "boolean" || - valueType === "number" || - valueType === "undefined" || - value === null - ) { - return next(value); - } - - if (Array.isArray(value) || isPlainObject(value)) { - let reusedExport = exportLookup.get(value); - - if (reusedExport && reusedExport !== key) { - return reusedExport; - } - return next(value); - } - - if (Symbol.toStringTag in Object(value)) { - let { [Symbol.toStringTag]: _tag, ...valueWithoutTag } = value; - return next(valueWithoutTag); - } - - if (valueType === "string") { - return next( - unusedCompositionRegex - ? value.replace(unusedCompositionRegex, "") - : value - ); - } - - if ( - valueType === "function" && - (value.__function_serializer__ || value.__recipe__) - ) { - let { importPath, importName, args } = - value.__function_serializer__ || value.__recipe__; - - if ( - typeof importPath !== "string" || - typeof importName !== "string" || - !Array.isArray(args) - ) { - throw new Error("Invalid function serialization params"); - } - - try { - let hashedImportName = `_${hash(`${importName}${importPath}`).slice( - 0, - 5 - )}`; - - functionSerializationImports.add( - `import { ${importName} as ${hashedImportName} } from '${importPath}';` - ); - - return `${hashedImportName}(${args - .map((arg) => - stringifyExports( - functionSerializationImports, - arg, - unusedCompositionRegex, - key, - exportLookup - ) - ) - .join(",")})`; - } catch (err) { - console.error(err); - - throw new Error("Invalid function serialization params"); - } - } - - throw new Error(outdent` - Invalid exports. - You can only export plain objects, arrays, strings, numbers and null/undefined. - `); - }, - 0, - { - references: true, // Allow circular references - maxDepth: Infinity, - maxValues: Infinity, - } - ); -} - -const defaultExportName = "__default__"; - -export function serializeVanillaModule( - cssImports: Array, - exports: Record, - unusedCompositionRegex: RegExp | null -) { - let functionSerializationImports = new Set(); - let exportLookup = new Map( - Object.entries(exports).map(([key, value]) => [ - value, - key === "default" ? defaultExportName : key, - ]) - ); - - let moduleExports = Object.keys(exports).map((key) => { - let serializedExport = stringifyExports( - functionSerializationImports, - exports[key], - unusedCompositionRegex, - key === "default" ? defaultExportName : key, - exportLookup - ); - - if (key === "default") { - return [ - `var ${defaultExportName} = ${serializedExport};`, - `export default ${defaultExportName};`, - ].join("\n"); - } - - return `export var ${key} = ${serializedExport};`; - }); - - let outputCode = [ - ...cssImports, - ...functionSerializationImports, - ...moduleExports, - ]; - - return outputCode.join("\n"); -} diff --git a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts b/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts deleted file mode 100644 index b07257b16c4..00000000000 --- a/packages/remix-dev/compiler/plugins/vanilla-extract/vanillaExtractCompiler.ts +++ /dev/null @@ -1,343 +0,0 @@ -import { relative } from "path"; -import { transformCss } from "@vanilla-extract/css/transformCss"; -import type { IdentifierOption } from "@vanilla-extract/integration"; -import { - cssFileFilter, - getPackageInfo, - transform, -} from "@vanilla-extract/integration"; -import type { ModuleNode, Plugin as VitePlugin } from "vite"; -import { createServer } from "vite"; -import { ViteNodeRunner } from "vite-node/client"; -import { ViteNodeServer } from "vite-node/server"; -import type { Adapter } from "@vanilla-extract/css"; - -import { lock } from "./lock"; -import { serializeVanillaModule } from "./processVanillaFile"; - -type Css = Parameters[0]; -type Composition = Parameters[0]; - -const globalCssAdapterKey = "__ve_globalCssAdapter__"; - -const scanModule = (entryModule: ModuleNode, root: string) => { - let queue = [entryModule]; - let cssDeps = new Set(); - let watchFiles = new Set(); - - for (let moduleNode of queue) { - let relativePath = moduleNode.id && relative(root, moduleNode.id); - - if (relativePath) { - cssDeps.add(relativePath); - } - - if (moduleNode.file) { - watchFiles.add(moduleNode.file); - } - - for (let importedModule of moduleNode.importedModules) { - queue.push(importedModule); - } - } - - // This ensures the root module's styles are last in terms of CSS ordering - let [head, ...tail] = cssDeps; - - return { cssDeps: [...tail, head], watchFiles }; -}; - -const createViteServer = async ({ - root, - identOption, - vitePlugins = [], -}: { - root: string; - identOption: IdentifierOption; - vitePlugins?: Array; -}) => { - let pkg = getPackageInfo(root); - - let server = await createServer({ - root, - server: { - hmr: false, - }, - logLevel: "silent", - optimizeDeps: { - disabled: true, - }, - ssr: { - noExternal: true, - }, - plugins: [ - { - name: "vanilla-extract-externalize", - enforce: "pre", - async resolveId(source, importer) { - if (source.startsWith("@vanilla-extract/")) { - let result = await this.resolve(source, importer, { - skipSelf: true, - }); - - return result ? { ...result, external: true } : null; - } - }, - }, - { - name: "vanilla-extract-transform", - async transform(code, id) { - if (cssFileFilter.test(id)) { - let filescopedCode = await transform({ - source: code, - rootPath: root, - filePath: id, - packageName: pkg.name, - identOption, - }); - - return ` - import { - setAdapter as __ve_setAdapter__, - removeAdapter as __ve_removeAdapter__ - } from '@vanilla-extract/css/adapter'; - __ve_setAdapter__(global.${globalCssAdapterKey}); - ${filescopedCode}; - __ve_removeAdapter__(); - `; - } - }, - }, - ...vitePlugins, - ], - }); - - // this is need to initialize the plugins - await server.pluginContainer.buildStart({}); - - let node = new ViteNodeServer(server); - - let runner = new ViteNodeRunner({ - root, - base: server.config.base, - fetchModule(id) { - return node.fetchModule(id); - }, - resolveId(id, importer) { - return node.resolveId(id, importer); - }, - }); - - server.watcher.on("change", (filePath) => { - runner.moduleCache.invalidateDepTree([filePath]); - }); - - return { - server, - runner, - }; -}; - -export interface Compiler { - processVanillaFile( - filePath: string, - outputCss: boolean - ): Promise<{ source: string; watchFiles: Set }>; - getCssForFile(virtualCssFilePath: string): { filePath: string; css: string }; - close(): Promise; -} - -interface ProcessedVanillaFile { - source: string; - watchFiles: Set; -} - -export interface CreateCompilerParams { - root: string; - identOption: IdentifierOption; - toCssImport: (filePath: string) => string; - vitePlugins?: Array; -} -export const createVanillaExtractCompiler = ({ - root, - identOption, - toCssImport, - vitePlugins, -}: CreateCompilerParams): Compiler => { - let vitePromise = createViteServer({ - root, - identOption, - vitePlugins, - }); - - let adapterResultCache = new Map< - string, - { - css: string; - localClassNames: Set; - composedClassLists: Array; - usedCompositions: Set; - } - >(); - - let processVanillaFileCache = new Map< - string, - { - lastInvalidationTimestamp: number; - result: ProcessedVanillaFile; - } - >(); - - return { - async processVanillaFile( - filePath, - outputCss - ): Promise { - let { server, runner } = await vitePromise; - - let cachedFile = processVanillaFileCache.get(filePath); - if (cachedFile) { - let moduleNode = server.moduleGraph.getModuleById(filePath); - if ( - cachedFile.lastInvalidationTimestamp === - moduleNode?.lastInvalidationTimestamp - ) { - return cachedFile.result; - } - } - - let cssByFileScope = new Map>(); - let localClassNames = new Set(); - let composedClassLists: Array = []; - let usedCompositions = new Set(); - - let cssAdapter: Adapter = { - appendCss: (css, fileScope) => { - let fileScopeCss = cssByFileScope.get(fileScope.filePath) ?? []; - fileScopeCss.push(css); - cssByFileScope.set(fileScope.filePath, fileScopeCss); - }, - registerClassName: (className) => { - localClassNames.add(className); - }, - registerComposition: (composedClassList) => { - composedClassLists.push(composedClassList); - }, - markCompositionUsed: (identifier) => { - usedCompositions.add(identifier); - }, - onEndFileScope: () => {}, - getIdentOption: () => identOption, - }; - - let { fileExports, cssImports, watchFiles, lastInvalidationTimestamp } = - await lock(async () => { - // @ts-expect-error We're adding this to the global context so it's - // available during the eval step, regardless of which - // `@vanilla-extract/css` package is used - global[globalCssAdapterKey] = cssAdapter; - - let fileExports = await runner.executeFile(filePath); - - let moduleNode = server.moduleGraph.getModuleById(filePath); - - if (!moduleNode) { - throw new Error(`Can't find ModuleNode for ${filePath}`); - } - - let cssImports = []; - - let { cssDeps, watchFiles } = scanModule(moduleNode, root); - - for (let cssDepModuleId of cssDeps) { - let cssObjs = cssByFileScope.get(cssDepModuleId); - let cachedAdapterResult = adapterResultCache.get(cssDepModuleId); - - if (!cssObjs && !cachedAdapterResult) { - continue; - } - - if (cssObjs) { - let css = transformCss({ - localClassNames: Array.from(localClassNames), - composedClassLists, - cssObjs, - }).join("\n"); - - adapterResultCache.set(cssDepModuleId, { - localClassNames, - composedClassLists, - usedCompositions, - css, - }); - } else if (cachedAdapterResult) { - cachedAdapterResult.localClassNames.forEach((localClassName) => { - localClassNames.add(localClassName); - }); - cachedAdapterResult.usedCompositions.forEach( - (usedComposition) => { - usedCompositions.add(usedComposition); - } - ); - composedClassLists.push( - ...cachedAdapterResult.composedClassLists - ); - } - - cssImports.push(`import '${toCssImport(cssDepModuleId)}';`); - } - - return { - fileExports, - cssImports: outputCss ? cssImports : [], - watchFiles, - lastInvalidationTimestamp: moduleNode.lastInvalidationTimestamp, - }; - }); - - let unusedCompositions = composedClassLists - .filter(({ identifier }) => !usedCompositions.has(identifier)) - .map(({ identifier }) => identifier); - - let unusedCompositionRegex = - unusedCompositions.length > 0 - ? RegExp(`(${unusedCompositions.join("|")})\\s`, "g") - : null; - - let result: ProcessedVanillaFile = { - source: serializeVanillaModule( - cssImports, - fileExports, - unusedCompositionRegex - ), - watchFiles, - }; - - processVanillaFileCache.set(filePath, { - lastInvalidationTimestamp, - result, - }); - - return result; - }, - getCssForFile(filePath: string) { - let rootRelativePath = relative(root, filePath); - let result = adapterResultCache.get(rootRelativePath); - - if (!result) { - throw new Error(`No CSS for file: ${filePath}`); - } - - return { - css: result.css, - filePath: rootRelativePath, - resolveDir: root, - }; - }, - async close() { - let { server } = await vitePromise; - - await server.close(); - }, - }; -}; diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts index 1d423567538..a8e017069b7 100644 --- a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts @@ -1,14 +1,16 @@ -import { dirname, join, posix } from "path"; -import { cssFileFilter } from "@vanilla-extract/integration"; +import { dirname, join } from "path"; +import { + cssFileFilter, + unstable_createCompiler, +} from "@vanilla-extract/integration"; import type { Plugin } from "esbuild"; import type { RemixConfig } from "../../config"; import type { CompileOptions } from "../options"; import { loaders } from "../loaders"; import { getPostcssProcessor } from "../utils/postcss"; -import { createVanillaExtractCompiler } from "./vanilla-extract/vanillaExtractCompiler"; -let compiler: ReturnType; +let compiler: ReturnType; let virtualCssFileSuffix = ".vanilla.css"; let virtualCssFileFilter = /\.vanilla\.css/; @@ -38,12 +40,9 @@ export function vanillaExtractPlugin({ compiler = compiler || - createVanillaExtractCompiler({ + unstable_createCompiler({ root, - identOption: mode === "production" ? "short" : "debug", - toCssImport(filePath) { - return filePath + virtualCssFileSuffix; - }, + identifiers: mode === "production" ? "short" : "debug", vitePlugins: [ { name: "remix-assets", @@ -94,11 +93,7 @@ export function vanillaExtractPlugin({ { filter: virtualCssFileFilter, namespace }, async ({ path }) => { let [relativeFilePath] = path.split(virtualCssFileSuffix); - - let { css, filePath } = compiler.getCssForFile( - posix.join(root, relativeFilePath) - ); - + let { css, filePath } = compiler.getCssForFile(relativeFilePath); let resolveDir = dirname(join(root, filePath)); if (postcssProcessor) { @@ -121,7 +116,7 @@ export function vanillaExtractPlugin({ build.onLoad({ filter: cssFileFilter }, async ({ path: filePath }) => { let { source, watchFiles } = await compiler.processVanillaFile( filePath, - outputCss + { outputCss } ); return { diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json index 9c50346ef95..c711545a8cd 100644 --- a/packages/remix-dev/package.json +++ b/packages/remix-dev/package.json @@ -30,8 +30,7 @@ "@esbuild-plugins/node-modules-polyfill": "^0.1.4", "@npmcli/package-json": "^2.0.0", "@remix-run/server-runtime": "1.13.0", - "@vanilla-extract/css": "^1.9.5", - "@vanilla-extract/integration": "^6.0.2", + "@vanilla-extract/integration": "0.0.0-create-compiler-api-2023264641", "arg": "^5.0.1", "cacache": "^15.0.5", "chalk": "^4.1.2", @@ -46,7 +45,6 @@ "get-port": "^5.1.1", "gunzip-maybe": "^1.4.2", "inquirer": "^8.2.1", - "javascript-stringify": "^2.1.0", "jsesc": "3.0.2", "json5": "^2.2.1", "lodash.debounce": "^4.0.8", @@ -55,7 +53,6 @@ "minimatch": "^3.0.4", "node-fetch": "^2.6.7", "ora": "^5.4.1", - "outdent": "^0.8.0", "postcss-discard-duplicates": "^5.1.0", "postcss-load-config": "^4.0.1", "postcss-modules": "^6.0.0", @@ -70,8 +67,6 @@ "sort-package-json": "^1.55.0", "tar-fs": "^2.1.1", "tsconfig-paths": "^4.0.0", - "vite-node": "~0.28.5", - "vite": "~4.1.1", "ws": "^7.4.5", "xdm": "^2.0.0" }, diff --git a/yarn.lock b/yarn.lock index 312930cb1bd..f8e4122401a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1629,6 +1629,11 @@ dependencies: "@edge-runtime/primitives" "^1.0.1" +"@emotion/hash@^0.8.0": + version "0.8.0" + resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + "@emotion/hash@^0.9.0": version "0.9.0" resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7" @@ -1652,6 +1657,11 @@ resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.3.tgz#6af6d16be6d534d776a51fc215bfd81a68906d2c" integrity sha512-RolFVeinkeraDvN/OoRf1F/lP0KUfGNb5jxy/vkIMeRRChkrX/HTYN6TYZosRJs3a1+8wqpxAo5PI5hFmxyPRg== +"@esbuild/android-arm64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.6.tgz#b11bd4e4d031bb320c93c83c137797b2be5b403b" + integrity sha512-YnYSCceN/dUzUr5kdtUzB+wZprCafuD89Hs0Aqv9QSdwhYQybhXTaSTcrl6X/aWThn1a/j0eEpUBGOE7269REg== + "@esbuild/android-arm@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2" @@ -1662,6 +1672,11 @@ resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.3.tgz#2a091222f3b1928e3246fb3c5202eaca88baab67" integrity sha512-mueuEoh+s1eRbSJqq9KNBQwI4QhQV6sRXIfTyLXSHGMpyew61rOK4qY21uKbXl1iBoMb0AdL1deWFCQVlN2qHA== +"@esbuild/android-arm@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.6.tgz#ac6b5674da2149997f6306b3314dae59bbe0ac26" + integrity sha512-bSC9YVUjADDy1gae8RrioINU6e1lCkg3VGVwm0QQ2E1CWcC4gnMce9+B6RpxuSsrsXsk1yojn7sp1fnG8erE2g== + "@esbuild/android-x64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e" @@ -1672,6 +1687,11 @@ resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.3.tgz#a6d749c58b022d371dc40d50ac1bb4aebd1eb953" integrity sha512-SFpTUcIT1bIJuCCBMCQWq1bL2gPTjWoLZdjmIhjdcQHaUfV41OQfho6Ici5uvvkMmZRXIUGpM3GxysP/EU7ifQ== +"@esbuild/android-x64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.6.tgz#18c48bf949046638fc209409ff684c6bb35a5462" + integrity sha512-MVcYcgSO7pfu/x34uX9u2QIZHmXAB7dEiLQC5bBl5Ryqtpj9lT2sg3gNDEsrPEmimSJW2FXIaxqSQ501YLDsZQ== + "@esbuild/darwin-arm64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220" @@ -1682,6 +1702,11 @@ resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.3.tgz#92d1826ed2f21dcac5830b70d7215c6afbb744e2" integrity sha512-DO8WykMyB+N9mIDfI/Hug70Dk1KipavlGAecxS3jDUwAbTpDXj0Lcwzw9svkhxfpCagDmpaTMgxWK8/C/XcXvw== +"@esbuild/darwin-arm64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.6.tgz#b3fe19af1e4afc849a07c06318124e9c041e0646" + integrity sha512-bsDRvlbKMQMt6Wl08nHtFz++yoZHsyTOxnjfB2Q95gato+Yi4WnRl13oC2/PJJA9yLCoRv9gqT/EYX0/zDsyMA== + "@esbuild/darwin-x64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4" @@ -1692,6 +1717,11 @@ resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.3.tgz#7fc3570c2b16e9ff4fc178593a0a4adb1ae8ea57" integrity sha512-uEqZQ2omc6BvWqdCiyZ5+XmxuHEi1SPzpVxXCSSV2+Sh7sbXbpeNhHIeFrIpRjAs0lI1FmA1iIOxFozKBhKgRQ== +"@esbuild/darwin-x64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.6.tgz#f4dacd1ab21e17b355635c2bba6a31eba26ba569" + integrity sha512-xh2A5oPrYRfMFz74QXIQTQo8uA+hYzGWJFoeTE8EvoZGHb+idyV4ATaukaUvnnxJiauhs/fPx3vYhU4wiGfosg== + "@esbuild/freebsd-arm64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27" @@ -1702,6 +1732,11 @@ resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.3.tgz#16735ce16f8c9a4e7289e9e259aa01a8d9874307" integrity sha512-nJansp3sSXakNkOD5i5mIz2Is/HjzIhFs49b1tjrPrpCmwgBmH9SSzhC/Z1UqlkivqMYkhfPwMw1dGFUuwmXhw== +"@esbuild/freebsd-arm64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.6.tgz#ea4531aeda70b17cbe0e77b0c5c36298053855b4" + integrity sha512-EnUwjRc1inT4ccZh4pB3v1cIhohE2S4YXlt1OvI7sw/+pD+dIE4smwekZlEPIwY6PhU6oDWwITrQQm5S2/iZgg== + "@esbuild/freebsd-x64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72" @@ -1712,6 +1747,11 @@ resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.3.tgz#f4edd1464cb072799ed6b8ab5178478e71c13459" integrity sha512-TfoDzLw+QHfc4a8aKtGSQ96Wa+6eimljjkq9HKR0rHlU83vw8aldMOUSJTUDxbcUdcgnJzPaX8/vGWm7vyV7ug== +"@esbuild/freebsd-x64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.6.tgz#1896170b3c9f63c5e08efdc1f8abc8b1ed7af29f" + integrity sha512-Uh3HLWGzH6FwpviUcLMKPCbZUAFzv67Wj5MTwK6jn89b576SR2IbEp+tqUHTr8DIl0iDmBAf51MVaP7pw6PY5Q== + "@esbuild/linux-arm64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca" @@ -1722,6 +1762,11 @@ resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.3.tgz#4b7ae6fe3618d9a40d6ca39c6edc991ac1447203" integrity sha512-7I3RlsnxEFCHVZNBLb2w7unamgZ5sVwO0/ikE2GaYvYuUQs9Qte/w7TqWcXHtCwxvZx/2+F97ndiUQAWs47ZfQ== +"@esbuild/linux-arm64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.6.tgz#967dfb951c6b2de6f2af82e96e25d63747f75079" + integrity sha512-bUR58IFOMJX523aDVozswnlp5yry7+0cRLCXDsxnUeQYJik1DukMY+apBsLOZJblpH+K7ox7YrKrHmJoWqVR9w== + "@esbuild/linux-arm@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196" @@ -1732,6 +1777,11 @@ resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.3.tgz#4b3e9f849822e16a76a70844c4db68075b259a58" integrity sha512-VwswmSYwVAAq6LysV59Fyqk3UIjbhuc6wb3vEcJ7HEJUtFuLK9uXWuFoH1lulEbE4+5GjtHi3MHX+w1gNHdOWQ== +"@esbuild/linux-arm@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.6.tgz#097a0ee2be39fed3f37ea0e587052961e3bcc110" + integrity sha512-7YdGiurNt7lqO0Bf/U9/arrPWPqdPqcV6JCZda4LZgEn+PTQ5SMEI4MGR52Bfn3+d6bNEGcWFzlIxiQdS48YUw== + "@esbuild/linux-ia32@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54" @@ -1742,6 +1792,11 @@ resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.3.tgz#2ff3936b91bfff62f9ecf7f6411ef399b29ed22d" integrity sha512-X8FDDxM9cqda2rJE+iblQhIMYY49LfvW4kaEjoFbTTQ4Go8G96Smj2w3BRTwA8IHGoi9dPOPGAX63dhuv19UqA== +"@esbuild/linux-ia32@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.6.tgz#a38a789d0ed157495a6b5b4469ec7868b59e5278" + integrity sha512-ujp8uoQCM9FRcbDfkqECoARsLnLfCUhKARTP56TFPog8ie9JG83D5GVKjQ6yVrEVdMie1djH86fm98eY3quQkQ== + "@esbuild/linux-loong64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8" @@ -1752,6 +1807,11 @@ resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.3.tgz#ff8aa59f49d9ccbc1ff952ba1f5cd01a534562df" integrity sha512-hIbeejCOyO0X9ujfIIOKjBjNAs9XD/YdJ9JXAy1lHA+8UXuOqbFe4ErMCqMr8dhlMGBuvcQYGF7+kO7waj2KHw== +"@esbuild/linux-loong64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.6.tgz#ae3983d0fb4057883c8246f57d2518c2af7cf2ad" + integrity sha512-y2NX1+X/Nt+izj9bLoiaYB9YXT/LoaQFYvCkVD77G/4F+/yuVXYCWz4SE9yr5CBMbOxOfBcy/xFL4LlOeNlzYQ== + "@esbuild/linux-mips64el@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726" @@ -1762,6 +1822,11 @@ resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.3.tgz#5dd5e118071c3912df69beedbfd11fb117f0fe5e" integrity sha512-znFRzICT/V8VZQMt6rjb21MtAVJv/3dmKRMlohlShrbVXdBuOdDrGb+C2cZGQAR8RFyRe7HS6klmHq103WpmVw== +"@esbuild/linux-mips64el@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.6.tgz#15fbbe04648d944ec660ee5797febdf09a9bd6af" + integrity sha512-09AXKB1HDOzXD+j3FdXCiL/MWmZP0Ex9eR8DLMBVcHorrWJxWmY8Nms2Nm41iRM64WVx7bA/JVHMv081iP2kUA== + "@esbuild/linux-ppc64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8" @@ -1772,6 +1837,11 @@ resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.3.tgz#36c62e24eae7fa3f0d921506da8fc1e6098a1364" integrity sha512-EV7LuEybxhXrVTDpbqWF2yehYRNz5e5p+u3oQUS2+ZFpknyi1NXxr8URk4ykR8Efm7iu04//4sBg249yNOwy5Q== +"@esbuild/linux-ppc64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.6.tgz#38210094e8e1a971f2d1fd8e48462cc65f15ef19" + integrity sha512-AmLhMzkM8JuqTIOhxnX4ubh0XWJIznEynRnZAVdA2mMKE6FAfwT2TWKTwdqMG+qEaeyDPtfNoZRpJbD4ZBv0Tg== + "@esbuild/linux-riscv64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9" @@ -1782,6 +1852,11 @@ resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.3.tgz#f0fec8e7affb5bcc817fefc61a21cbb95539e393" integrity sha512-uDxqFOcLzFIJ+r/pkTTSE9lsCEaV/Y6rMlQjUI9BkzASEChYL/aSQjZjchtEmdnVxDKETnUAmsaZ4pqK1eE5BQ== +"@esbuild/linux-riscv64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.6.tgz#bc3c66d5578c3b9951a6ed68763f2a6856827e4a" + integrity sha512-Y4Ri62PfavhLQhFbqucysHOmRamlTVK10zPWlqjNbj2XMea+BOs4w6ASKwQwAiqf9ZqcY9Ab7NOU4wIgpxwoSQ== + "@esbuild/linux-s390x@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87" @@ -1792,6 +1867,11 @@ resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.3.tgz#22e10edd6e91f53c2e1f60e46abd453d7794409b" integrity sha512-NbeREhzSxYwFhnCAQOQZmajsPYtX71Ufej3IQ8W2Gxskfz9DK58ENEju4SbpIj48VenktRASC52N5Fhyf/aliQ== +"@esbuild/linux-s390x@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.6.tgz#d7ba7af59285f63cfce6e5b7f82a946f3e6d67fc" + integrity sha512-SPUiz4fDbnNEm3JSdUW8pBJ/vkop3M1YwZAVwvdwlFLoJwKEZ9L98l3tzeyMzq27CyepDQ3Qgoba44StgbiN5Q== + "@esbuild/linux-x64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz#e4ba18e8b149a89c982351443a377c723762b85f" @@ -1802,6 +1882,11 @@ resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.3.tgz#38388b73fd9eebe45b073d7d8099b9c2e54f7139" integrity sha512-SDiG0nCixYO9JgpehoKgScwic7vXXndfasjnD5DLbp1xltANzqZ425l7LSdHynt19UWOcDjG9wJJzSElsPvk0w== +"@esbuild/linux-x64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.6.tgz#ba51f8760a9b9370a2530f98964be5f09d90fed0" + integrity sha512-a3yHLmOodHrzuNgdpB7peFGPx1iJ2x6m+uDvhP2CKdr2CwOaqEFMeSqYAHU7hG+RjCq8r2NFujcd/YsEsFgTGw== + "@esbuild/netbsd-x64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775" @@ -1812,6 +1897,11 @@ resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.3.tgz#e0270569567f1530b8dbe6d11d5b4930b9cc71ae" integrity sha512-AzbsJqiHEq1I/tUvOfAzCY15h4/7Ivp3ff/o1GpP16n48JMNAtbW0qui2WCgoIZArEHD0SUQ95gvR0oSO7ZbdA== +"@esbuild/netbsd-x64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.6.tgz#e84d6b6fdde0261602c1e56edbb9e2cb07c211b9" + integrity sha512-EanJqcU/4uZIBreTrnbnre2DXgXSa+Gjap7ifRfllpmyAU7YMvaXmljdArptTHmjrkkKm9BK6GH5D5Yo+p6y5A== + "@esbuild/openbsd-x64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35" @@ -1822,6 +1912,11 @@ resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.3.tgz#3b16642d443848bca605f33ee3978a1890911e6d" integrity sha512-gSABi8qHl8k3Cbi/4toAzHiykuBuWLZs43JomTcXkjMZVkp0gj3gg9mO+9HJW/8GB5H89RX/V0QP4JGL7YEEVg== +"@esbuild/openbsd-x64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.6.tgz#cf4b9fb80ce6d280a673d54a731d9c661f88b083" + integrity sha512-xaxeSunhQRsTNGFanoOkkLtnmMn5QbA0qBhNet/XLVsc+OVkpIWPHcr3zTW2gxVU5YOHFbIHR9ODuaUdNza2Vw== + "@esbuild/sunos-x64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c" @@ -1832,6 +1927,11 @@ resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.3.tgz#a838f247867380f0ae25ce1936dc5ab6f57b7734" integrity sha512-SF9Kch5Ete4reovvRO6yNjMxrvlfT0F0Flm+NPoUw5Z4Q3r1d23LFTgaLwm3Cp0iGbrU/MoUI+ZqwCv5XJijCw== +"@esbuild/sunos-x64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.6.tgz#a6838e246079b24d962b9dcb8d208a3785210a73" + integrity sha512-gnMnMPg5pfMkZvhHee21KbKdc6W3GR8/JuE0Da1kjwpK6oiFU3nqfHuVPgUX2rsOx9N2SadSQTIYV1CIjYG+xw== + "@esbuild/win32-arm64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a" @@ -1842,6 +1942,11 @@ resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.3.tgz#bedd9bef5fb41f89ce2599f1761973cf6d6a67b6" integrity sha512-u5aBonZIyGopAZyOnoPAA6fGsDeHByZ9CnEzyML9NqntK6D/xl5jteZUKm/p6nD09+v3pTM6TuUIqSPcChk5gg== +"@esbuild/win32-arm64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.6.tgz#ace0186e904d109ea4123317a3ba35befe83ac21" + integrity sha512-G95n7vP1UnGJPsVdKXllAJPtqjMvFYbN20e8RK8LVLhlTiSOH1sd7+Gt7rm70xiG+I5tM58nYgwWrLs6I1jHqg== + "@esbuild/win32-ia32@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09" @@ -1852,6 +1957,11 @@ resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.3.tgz#49800aa812d8cc35ceef61e8d3b01224684cc0b1" integrity sha512-GlgVq1WpvOEhNioh74TKelwla9KDuAaLZrdxuuUgsP2vayxeLgVc+rbpIv0IYF4+tlIzq2vRhofV+KGLD+37EQ== +"@esbuild/win32-ia32@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.6.tgz#7fb3f6d4143e283a7f7dffc98a6baf31bb365c7e" + integrity sha512-96yEFzLhq5bv9jJo5JhTs1gI+1cKQ83cUpyxHuGqXVwQtY5Eq54ZEsKs8veKtiKwlrNimtckHEkj4mRh4pPjsg== + "@esbuild/win32-x64@0.16.17": version "0.16.17" resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091" @@ -1862,6 +1972,11 @@ resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.3.tgz#94047dae921949cfb308117d993c4b941291ae10" integrity sha512-5/JuTd8OWW8UzEtyf19fbrtMJENza+C9JoPIkvItgTBQ1FO2ZLvjbPO6Xs54vk0s5JB5QsfieUEshRQfu7ZHow== +"@esbuild/win32-x64@0.17.6": + version "0.17.6" + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.6.tgz#563ff4277f1230a006472664fa9278a83dd124da" + integrity sha512-n6d8MOyUrNp6G4VSpRcgjs5xj4A91svJSaiwLIDWVWEsZtpN5FA9NlBbZHDmAJc2e8e6SF4tkBD3HAvPF+7igA== + "@eslint/eslintrc@^1.3.2": version "1.3.2" resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz" @@ -3355,34 +3470,35 @@ "@typescript-eslint/types" "5.38.0" eslint-visitor-keys "^3.3.0" -"@vanilla-extract/babel-plugin-debug-ids@^1.0.1": - version "1.0.1" - resolved "https://registry.npmjs.org/@vanilla-extract/babel-plugin-debug-ids/-/babel-plugin-debug-ids-1.0.1.tgz#d20bd0c9ec867ca892fcf665dca171110aa2a1e1" - integrity sha512-ynyKqsJiMzM1/yiIJ6QdqpWKlK4IMJJWREpPtaemZrE1xG1B4E/Nfa6YazuDWjDkCJC1tRIpEGnVs+pMIjUxyw== +"@vanilla-extract/babel-plugin-debug-ids@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@vanilla-extract/babel-plugin-debug-ids/-/babel-plugin-debug-ids-1.0.2.tgz#24674b4d09e98236c883d23aef6f37d1a326af28" + integrity sha512-LjnbQWGeMwaydmovx8jWUR8BxLtLiPyq0xz5C8G5OvFhsuJxvavLdrBHNNizvr1dq7/3qZGlPv0znsvU4P44YA== dependencies: "@babel/core" "^7.20.7" -"@vanilla-extract/css@^1.9.2": - version "1.9.2" - resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.9.2.tgz#2c4bcc58f3c7441a1d041083c76bf5c3e2c77675" - integrity sha512-CE5+R89LOl9XG5dRwEIvVyl/YcS2GkqjdE/XnGJ+p7Fp6Exu08fifv7tY87XxFeCIRAbc9psM+h4lF+wC3Y0fg== +"@vanilla-extract/css@^0.0.0-create-compiler-api-2023264641": + version "0.0.0-transform-perf-2022820614" + resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-0.0.0-transform-perf-2022820614.tgz#36102382051d11647cee9819277283d3f2f7b70f" + integrity sha512-giCKT4ERcGlTIe2fYJxiSofZChw3M5CoHcjL2juY2BixaWdYetbi1n0Slw3Nia24Su6dXPaKRcGotyooapxolw== dependencies: - "@emotion/hash" "^0.9.0" + "@emotion/hash" "^0.8.0" "@vanilla-extract/private" "^1.0.3" - ahocorasick "1.0.2" + ahocorasick "^1.0.2" chalk "^4.1.1" css-what "^5.0.1" cssesc "^3.0.0" csstype "^3.0.7" deep-object-diff "^1.1.0" deepmerge "^4.2.2" + escape-string-regexp "^4.0.0" media-query-parser "^2.0.2" outdent "^0.8.0" -"@vanilla-extract/css@^1.9.3": - version "1.9.3" - resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.9.3.tgz#59cd445e9ffa9676c4faf7f213ddf6538404c92c" - integrity sha512-vitcD8usEOTWDLAnbtnZ46YbHADAp3Es+3xyHsMDMZOEWk03FhD+PbR58kdwtGpr258+hMryCYtQPeFh5lWFbA== +"@vanilla-extract/css@^1.9.2": + version "1.9.2" + resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.9.2.tgz#2c4bcc58f3c7441a1d041083c76bf5c3e2c77675" + integrity sha512-CE5+R89LOl9XG5dRwEIvVyl/YcS2GkqjdE/XnGJ+p7Fp6Exu08fifv7tY87XxFeCIRAbc9psM+h4lF+wC3Y0fg== dependencies: "@emotion/hash" "^0.9.0" "@vanilla-extract/private" "^1.0.3" @@ -3396,38 +3512,24 @@ media-query-parser "^2.0.2" outdent "^0.8.0" -"@vanilla-extract/css@^1.9.5": - version "1.9.5" - resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.9.5.tgz#c5361c04045e6f01502564c2fb6b82177b97f6bc" - integrity sha512-aVSv6q24zelKRtWx/l9yshU3gD1uCDMZ2ZGcIiYnAcPfyLryrG/1X5DxtyiPKcyI/hZWoteHofsN//2q9MvzOA== - dependencies: - "@emotion/hash" "^0.9.0" - "@vanilla-extract/private" "^1.0.3" - ahocorasick "1.0.2" - chalk "^4.1.1" - css-what "^5.0.1" - cssesc "^3.0.0" - csstype "^3.0.7" - deep-object-diff "^1.1.9" - deepmerge "^4.2.2" - media-query-parser "^2.0.2" - outdent "^0.8.0" - -"@vanilla-extract/integration@^6.0.2": - version "6.0.2" - resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-6.0.2.tgz#ff9f03ef0d1d0fedc681f15f450af2dc52b0e60f" - integrity sha512-LwfXlh0THeNvVXdA3iWFYvJs1mvEP1PkfQD/7S6Purry7L8iDizDV/87FgWBJ79FnTmYIvMrc7BOQsUajNj9VQ== +"@vanilla-extract/integration@0.0.0-create-compiler-api-2023264641": + version "0.0.0-create-compiler-api-2023264641" + resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-0.0.0-create-compiler-api-2023264641.tgz#610f6c39ee77a21c03a07d637469eac44831f59c" + integrity sha512-J5hFvXXsiYGhs12N6LruEZONPkkaAd5u4dwHvUZjjUFOiydzwNofo5JTB3PYM1jj7xJxpr9Q7285yCLBXSSPpg== dependencies: "@babel/core" "^7.20.7" "@babel/plugin-syntax-typescript" "^7.20.0" - "@vanilla-extract/babel-plugin-debug-ids" "^1.0.1" - "@vanilla-extract/css" "^1.9.3" - esbuild "^0.16.3" + "@vanilla-extract/babel-plugin-debug-ids" "^1.0.2" + "@vanilla-extract/css" "^0.0.0-create-compiler-api-2023264641" + esbuild "0.17.6" eval "0.1.6" find-up "^5.0.0" javascript-stringify "^2.0.1" lodash "^4.17.21" + mlly "^1.1.0" outdent "^0.8.0" + vite "^4.1.4" + vite-node "^0.28.5" "@vanilla-extract/private@^1.0.3": version "1.0.3" @@ -3581,7 +3683,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ahocorasick@1.0.2: +ahocorasick@1.0.2, ahocorasick@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/ahocorasick/-/ahocorasick-1.0.2.tgz#9eee93aef9d02bfb476d9b648d9b7a40ef2fd500" integrity sha512-hCOfMzbFx5IDutmWLAt6MZwOUjIfSM9G9FyVxytmE4Rs/5YDPWQrD/+IR1w+FweD9H2oOZEnv36TmkjhNURBVA== @@ -5242,7 +5344,7 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -deep-object-diff@^1.1.0, deep-object-diff@^1.1.9: +deep-object-diff@^1.1.0: version "1.1.9" resolved "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz#6df7ef035ad6a0caa44479c536ed7b02570f4595" integrity sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA== @@ -5810,7 +5912,35 @@ esbuild@0.16.3: "@esbuild/win32-ia32" "0.16.3" "@esbuild/win32-x64" "0.16.3" -esbuild@^0.16.14, esbuild@^0.16.3: +esbuild@0.17.6: + version "0.17.6" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.17.6.tgz#bbccd4433629deb6e0a83860b3b61da120ba4e01" + integrity sha512-TKFRp9TxrJDdRWfSsSERKEovm6v30iHnrjlcGhLBOtReE28Yp1VSBRfO3GTaOFMoxsNerx4TjrhzSuma9ha83Q== + optionalDependencies: + "@esbuild/android-arm" "0.17.6" + "@esbuild/android-arm64" "0.17.6" + "@esbuild/android-x64" "0.17.6" + "@esbuild/darwin-arm64" "0.17.6" + "@esbuild/darwin-x64" "0.17.6" + "@esbuild/freebsd-arm64" "0.17.6" + "@esbuild/freebsd-x64" "0.17.6" + "@esbuild/linux-arm" "0.17.6" + "@esbuild/linux-arm64" "0.17.6" + "@esbuild/linux-ia32" "0.17.6" + "@esbuild/linux-loong64" "0.17.6" + "@esbuild/linux-mips64el" "0.17.6" + "@esbuild/linux-ppc64" "0.17.6" + "@esbuild/linux-riscv64" "0.17.6" + "@esbuild/linux-s390x" "0.17.6" + "@esbuild/linux-x64" "0.17.6" + "@esbuild/netbsd-x64" "0.17.6" + "@esbuild/openbsd-x64" "0.17.6" + "@esbuild/sunos-x64" "0.17.6" + "@esbuild/win32-arm64" "0.17.6" + "@esbuild/win32-ia32" "0.17.6" + "@esbuild/win32-x64" "0.17.6" + +esbuild@^0.16.14: version "0.16.17" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259" integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg== @@ -7818,7 +7948,7 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -javascript-stringify@^2.0.1, javascript-stringify@^2.1.0: +javascript-stringify@^2.0.1: version "2.1.0" resolved "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79" integrity sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg== @@ -12767,7 +12897,7 @@ vfile@^5.1.0: unist-util-stringify-position "^3.0.0" vfile-message "^3.0.0" -vite-node@~0.28.5: +vite-node@^0.28.5: version "0.28.5" resolved "https://registry.npmjs.org/vite-node/-/vite-node-0.28.5.tgz#56d0f78846ea40fddf2e28390899df52a4738006" integrity sha512-LmXb9saMGlrMZbXTvOveJKwMTBTNUH66c8rJnQ0ZPNX+myPEol64+szRzXtV5ORb0Hb/91yq+/D3oERoyAt6LA== @@ -12781,7 +12911,7 @@ vite-node@~0.28.5: source-map-support "^0.5.21" vite "^3.0.0 || ^4.0.0" -"vite@^3.0.0 || ^4.0.0", vite@~4.1.1: +"vite@^3.0.0 || ^4.0.0": version "4.1.1" resolved "https://registry.npmjs.org/vite/-/vite-4.1.1.tgz#3b18b81a4e85ce3df5cbdbf4c687d93ebf402e6b" integrity sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg== @@ -12793,6 +12923,18 @@ vite-node@~0.28.5: optionalDependencies: fsevents "~2.3.2" +vite@^4.1.4: + version "4.1.4" + resolved "https://registry.npmjs.org/vite/-/vite-4.1.4.tgz#170d93bcff97e0ebc09764c053eebe130bfe6ca0" + integrity sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg== + dependencies: + esbuild "^0.16.14" + postcss "^8.4.21" + resolve "^1.22.1" + rollup "^3.10.0" + optionalDependencies: + fsevents "~2.3.2" + vm2@^3.9.8: version "3.9.11" resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.11.tgz" From e24d4dc628a0cc9ee722c18d0b33d2b6c7f846a7 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Thu, 9 Mar 2023 14:46:10 +1100 Subject: [PATCH 09/21] Update to snapshot release, add cache option --- .../deterministic-build-output-test.ts | 240 ++++--- integration/vanilla-extract-test.ts | 627 ++++++++---------- package.json | 5 +- packages/remix-dev/compiler/compileBrowser.ts | 11 +- .../compiler/plugins/vanillaExtractPlugin.ts | 173 +---- .../plugins/vanillaExtractPluginCached.ts | 126 ++++ .../plugins/vanillaExtractPluginUncached.ts | 182 +++++ .../vanillaExtractSideEffectsPlugin.ts | 40 ++ packages/remix-dev/config.ts | 8 +- packages/remix-dev/package.json | 2 +- yarn.lock | 49 +- 11 files changed, 800 insertions(+), 663 deletions(-) create mode 100644 packages/remix-dev/compiler/plugins/vanillaExtractPluginCached.ts create mode 100644 packages/remix-dev/compiler/plugins/vanillaExtractPluginUncached.ts create mode 100644 packages/remix-dev/compiler/plugins/vanillaExtractSideEffectsPlugin.ts diff --git a/integration/deterministic-build-output-test.ts b/integration/deterministic-build-output-test.ts index 05b35902158..ede43e19170 100644 --- a/integration/deterministic-build-output-test.ts +++ b/integration/deterministic-build-output-test.ts @@ -5,116 +5,146 @@ import path from "path"; import { createFixtureProject, js, css } from "./helpers/create-fixture"; -test("builds deterministically under different paths", async () => { - // This test validates various flavors of remix virtual modules to ensure - // we get identical builds regardless of the parent paths. If a virtual - // module resolves or imports from absolute paths (e.g. via `path.resolve`), - // the build hashes may change even though the output is identical. This - // can cause broken apps (i.e. manifest mismatch) if the server and client - // are built separately. +const configurations = [ + { + name: "future flags enabled", + remixConfig: js` + module.exports = { + future: { + unstable_cssModules: true, + unstable_cssSideEffectImports: true, + unstable_postcss: true, + unstable_vanillaExtract: true, + }, + }; + `, + }, + { + name: "Vanilla Extract cache enabled", + remixConfig: js` + module.exports = { + future: { + unstable_cssModules: true, + unstable_cssSideEffectImports: true, + unstable_postcss: true, + unstable_vanillaExtract: { cache: true }, + }, + }; + `, + }, +] as const; - // Virtual modules tested: - // * browserRouteModulesPlugin (implicitly tested by root route) - // * cssEntryModulePlugin (implicitly tested by build) - // * cssModulesPlugin (via app/routes/foo.tsx' CSS Modules import) - // * cssSideEffectImportsPlugin (via app/routes/foo.tsx' CSS side-effect import) - // * emptyModulesPlugin (via app/routes/foo.tsx' server import) - // * mdx (via app/routes/index.mdx) - // * serverAssetsManifestPlugin (implicitly tested by build) - // * serverEntryModulePlugin (implicitly tested by build) - // * serverRouteModulesPlugin (implicitly tested by build) - // * vanillaExtractPlugin (via app/routes/foo.tsx' .css.ts file import) - let init = { - files: { - "remix.config.js": js` - module.exports = { - future: { - unstable_cssModules: true, - unstable_cssSideEffectImports: true, - unstable_postcss: true, - unstable_vanillaExtract: true, - }, - }; - `, - "app/routes/index.mdx": "# hello world", - "app/routes/foo.tsx": js` - export * from "~/foo/bar.server"; - import styles from "~/styles/foo.module.css"; - import { vanilla } from "~/styles/vanilla.css"; - import "~/styles/side-effect.css"; - export default () =>
YAY
; - `, - "app/foo/bar.server.ts": "export const meta = () => []", - "app/styles/foo.module.css": css` - .foo { - background-image: url(~/images/foo.svg); - composes: bar from "~/styles/bar.module.css"; - composes: baz from "./baz.module.css"; - } - `, - "app/styles/bar.module.css": css` - .bar { - background-color: peachpuff; - } - `, - "app/styles/baz.module.css": css` - .baz { - color: coral; - } - `, - "app/images/foo.svg": ` - - - - `, - "app/styles/vanilla.css.ts": css` - import { style } from "@vanilla-extract/css"; - import { chocolate } from "./chocolate.css"; - import imageUrl from "~/images/foo.svg"; +configurations.forEach((configuration) => { + test.describe(configuration.name, () => { + test("builds deterministically under different paths", async () => { + // This test validates various flavors of remix virtual modules to ensure + // we get identical builds regardless of the parent paths. If a virtual + // module resolves or imports from absolute paths (e.g. via `path.resolve`), + // the build hashes may change even though the output is identical. This + // can cause broken apps (i.e. manifest mismatch) if the server and client + // are built separately. - export const vanilla = style([ - chocolate, - { - backgroundImage: [ - "url(" + imageUrl + ")", - "url(~/images/foo.svg)", - ], - } - ]); - `, - "app/styles/chocolate.css.ts": css` - import { style } from "@vanilla-extract/css"; + // Virtual modules tested: + // * browserRouteModulesPlugin (implicitly tested by root route) + // * cssEntryModulePlugin (implicitly tested by build) + // * cssModulesPlugin (via app/routes/foo.tsx' CSS Modules import) + // * cssSideEffectImportsPlugin (via app/routes/foo.tsx' CSS side-effect import) + // * emptyModulesPlugin (via app/routes/foo.tsx' server import) + // * mdx (via app/routes/index.mdx) + // * serverAssetsManifestPlugin (implicitly tested by build) + // * serverEntryModulePlugin (implicitly tested by build) + // * serverRouteModulesPlugin (implicitly tested by build) + // * vanillaExtractPlugin (via app/routes/foo.tsx' .css.ts file import) + let init = { + files: { + "remix.config.js": configuration.remixConfig, + "app/routes/index.mdx": "# hello world", + "app/routes/foo.tsx": js` + export * from "~/foo/bar.server"; + import styles from "~/styles/foo.module.css"; + import { vanilla } from "~/styles/vanilla.css"; + import "~/styles/side-effect.css"; + export default () =>
YAY
; + `, + "app/foo/bar.server.ts": "export const meta = () => []", + "app/styles/foo.module.css": css` + .foo { + background-image: url(~/images/foo.svg); + composes: bar from "~/styles/bar.module.css"; + composes: baz from "./baz.module.css"; + } + `, + "app/styles/bar.module.css": css` + .bar { + background-color: peachpuff; + } + `, + "app/styles/baz.module.css": css` + .baz { + color: coral; + } + `, + "app/images/foo.svg": ` + + + + `, + "app/styles/vanilla.css.ts": css` + import { style } from "@vanilla-extract/css"; + import { chocolate } from "./chocolate.css"; + import imageUrl from "~/images/foo.svg"; - export const chocolate = style({ - color: "chocolate", - }); - `, - "app/styles/side-effect.css": css` - .side-effect { - color: mintcream; - } - `, - }, - }; - let dir1 = await createFixtureProject(init); - let dir2 = await createFixtureProject(init); + export const vanilla = style([ + chocolate, + { + backgroundImage: [ + "url(" + imageUrl + ")", + "url(~/images/foo.svg)", + ], + } + ]); + `, + "app/styles/chocolate.css.ts": css` + import { style } from "@vanilla-extract/css"; - expect(dir1).not.toEqual(dir2); + export const chocolate = style({ + color: "chocolate", + }); + `, + "app/styles/side-effect.css": css` + .side-effect { + color: mintcream; + } + `, + }, + }; + let dir1 = await createFixtureProject(init); + let dir2 = await createFixtureProject(init); - let files1 = await globby(["build/index.js", "public/build/**/*.{js,css}"], { - cwd: dir1, - }); - files1 = files1.sort(); - let files2 = await globby(["build/index.js", "public/build/**/*.{js,css}"], { - cwd: dir2, - }); - files2 = files2.sort(); + expect(dir1).not.toEqual(dir2); + + let files1 = await globby( + ["build/index.js", "public/build/**/*.{js,css}"], + { + cwd: dir1, + } + ); + files1 = files1.sort(); + let files2 = await globby( + ["build/index.js", "public/build/**/*.{js,css}"], + { + cwd: dir2, + } + ); + files2 = files2.sort(); - expect(files1.length).toBeGreaterThan(0); - expect(files1).toEqual(files2); - files1.forEach((file, i) => { - expect(fs.readFileSync(path.join(dir1, file))).toEqual( - fs.readFileSync(path.join(dir2, files2[i])) - ); + expect(files1.length).toBeGreaterThan(0); + expect(files1).toEqual(files2); + files1.forEach((file, i) => { + expect(fs.readFileSync(path.join(dir1, file))).toEqual( + fs.readFileSync(path.join(dir2, files2[i])) + ); + }); + }); }); }); diff --git a/integration/vanilla-extract-test.ts b/integration/vanilla-extract-test.ts index 1e40fe2ac58..cffae69dbdb 100644 --- a/integration/vanilla-extract-test.ts +++ b/integration/vanilla-extract-test.ts @@ -6,14 +6,21 @@ import { createAppFixture, createFixture, js } from "./helpers/create-fixture"; const TEST_PADDING_VALUE = "20px"; -test.describe("Vanilla Extract", () => { - let fixture: Fixture; - let appFixture: AppFixture; +const configurations = [ + { name: "Cached", config: "{ cached: true }" }, + { name: "Uncached", config: "true" }, +] as const; - test.beforeAll(async () => { - fixture = await createFixture({ - files: { - "remix.config.js": js` +test.describe("Vanilla Extract", () => { + configurations.forEach((configuration) => { + test.describe(configuration.name, () => { + let fixture: Fixture; + let appFixture: AppFixture; + + test.beforeAll(async () => { + fixture = await createFixture({ + files: { + "remix.config.js": js` module.exports = { future: { // Enable all CSS future flags to @@ -22,11 +29,11 @@ test.describe("Vanilla Extract", () => { unstable_cssSideEffectImports: true, unstable_postcss: true, unstable_tailwind: true, - unstable_vanillaExtract: true, + unstable_vanillaExtract: ${configuration.config}, }, }; `, - "app/root.jsx": js` + "app/root.jsx": js` import { Links, Outlet } from "@remix-run/react"; import { cssBundleHref } from "@remix-run/css-bundle"; export function links() { @@ -45,32 +52,30 @@ test.describe("Vanilla Extract", () => { ) } `, - ...typeScriptFixture(), - ...javaScriptFixture(), - ...classCompositionFixture(), - ...rootRelativeClassCompositionFixture(), - ...sideEffectImportsFixture(), - ...sideEffectImportsWithinChildCompilationFixture(), - ...stableIdentifiersFixture(), - ...imageUrlsViaCssUrlFixture(), - ...imageUrlsViaRootRelativeCssUrlFixture(), - ...imageUrlsViaJsImportFixture(), - ...imageUrlsViaRootRelativeJsImportFixture(), - ...imageUrlsViaClassCompositionFixture(), - ...imageUrlsViaJsImportClassCompositionFixture(), - ...standardImageUrlsViaJsImportFixture(), - ...standardImageUrlsViaRootRelativeJsImportFixture(), - }, - }); - appFixture = await createAppFixture(fixture); - }); + ...typeScriptFixture(), + ...javaScriptFixture(), + ...classCompositionFixture(), + ...rootRelativeClassCompositionFixture(), + ...sideEffectImportsFixture(), + ...sideEffectImportsWithinChildCompilationFixture(), + ...stableIdentifiersFixture(), + ...imageUrlsViaCssUrlFixture(), + ...imageUrlsViaRootRelativeCssUrlFixture(), + ...imageUrlsViaJsImportFixture(), + ...imageUrlsViaRootRelativeJsImportFixture(), + ...imageUrlsViaClassCompositionFixture(), + ...imageUrlsViaJsImportClassCompositionFixture(), + }, + }); + appFixture = await createAppFixture(fixture); + }); - test.afterAll(async () => { - await appFixture.close(); - }); + test.afterAll(async () => { + await appFixture.close(); + }); - let typeScriptFixture = () => ({ - "app/fixtures/typescript/styles.css.ts": js` + let typeScriptFixture = () => ({ + "app/fixtures/typescript/styles.css.ts": js` import { style } from "@vanilla-extract/css"; export const root = style({ @@ -78,7 +83,7 @@ test.describe("Vanilla Extract", () => { padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/routes/typescript-test.jsx": js` + "app/routes/typescript-test.jsx": js` import * as styles from "../fixtures/typescript/styles.css"; export default function() { @@ -89,19 +94,19 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("TypeScript", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/typescript-test"); - let locator = await page.locator("[data-testid='typescript']"); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + }); + test("TypeScript", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/typescript-test"); + let locator = await page.locator("[data-testid='typescript']"); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let javaScriptFixture = () => ({ - "app/fixtures/javascript/styles.css.js": js` + let javaScriptFixture = () => ({ + "app/fixtures/javascript/styles.css.js": js` import { style } from "@vanilla-extract/css"; export const root = style({ @@ -109,7 +114,7 @@ test.describe("Vanilla Extract", () => { padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/routes/javascript-test.jsx": js` + "app/routes/javascript-test.jsx": js` import * as styles from "../fixtures/javascript/styles.css"; export default function() { @@ -120,19 +125,19 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("JavaScript", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/javascript-test"); - let locator = await page.locator("[data-testid='javascript']"); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + }); + test("JavaScript", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/javascript-test"); + let locator = await page.locator("[data-testid='javascript']"); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let classCompositionFixture = () => ({ - "app/fixtures/class-composition/styles.css.ts": js` + let classCompositionFixture = () => ({ + "app/fixtures/class-composition/styles.css.ts": js` import { style } from "@vanilla-extract/css"; import { padding } from "./padding.css"; @@ -141,14 +146,14 @@ test.describe("Vanilla Extract", () => { { background: 'peachpuff' }, ]); `, - "app/fixtures/class-composition/padding.css.ts": js` + "app/fixtures/class-composition/padding.css.ts": js` import { style } from "@vanilla-extract/css"; export const padding = style({ padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/routes/class-composition-test.jsx": js` + "app/routes/class-composition-test.jsx": js` import * as styles from "../fixtures/class-composition/styles.css"; export default function() { @@ -159,19 +164,19 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("class composition", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/class-composition-test"); - let locator = await page.locator("[data-testid='class-composition']"); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + }); + test("class composition", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/class-composition-test"); + let locator = await page.locator("[data-testid='class-composition']"); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let rootRelativeClassCompositionFixture = () => ({ - "app/fixtures/root-relative-class-composition/styles.css.ts": js` + let rootRelativeClassCompositionFixture = () => ({ + "app/fixtures/root-relative-class-composition/styles.css.ts": js` import { style } from "@vanilla-extract/css"; import { padding } from "~/fixtures/root-relative-class-composition/padding.css"; @@ -180,14 +185,14 @@ test.describe("Vanilla Extract", () => { { background: 'peachpuff' }, ]); `, - "app/fixtures/root-relative-class-composition/padding.css.ts": js` + "app/fixtures/root-relative-class-composition/padding.css.ts": js` import { style } from "@vanilla-extract/css"; export const padding = style({ padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/routes/root-relative-class-composition-test.jsx": js` + "app/routes/root-relative-class-composition-test.jsx": js` import * as styles from "../fixtures/root-relative-class-composition/styles.css"; export default function() { @@ -198,28 +203,28 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("root-relative class composition", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/root-relative-class-composition-test"); - let locator = await page.locator( - "[data-testid='root-relative-class-composition']" - ); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + }); + test("root-relative class composition", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/root-relative-class-composition-test"); + let locator = await page.locator( + "[data-testid='root-relative-class-composition']" + ); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let sideEffectImportsFixture = () => ({ - "app/fixtures/side-effect-imports/styles.css.ts": js` + let sideEffectImportsFixture = () => ({ + "app/fixtures/side-effect-imports/styles.css.ts": js` import { globalStyle } from "@vanilla-extract/css"; globalStyle(".side-effect-imports", { padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/routes/side-effect-imports-test.jsx": js` + "app/routes/side-effect-imports-test.jsx": js` import "../fixtures/side-effect-imports/styles.css"; export default function() { @@ -230,29 +235,29 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("side-effect imports", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/side-effect-imports-test"); - let locator = await page.locator("[data-testid='side-effect-imports']"); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + }); + test("side-effect imports", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/side-effect-imports-test"); + let locator = await page.locator("[data-testid='side-effect-imports']"); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let sideEffectImportsWithinChildCompilationFixture = () => ({ - "app/fixtures/side-effect-imports-within-child-compilation/styles.css.ts": js` + let sideEffectImportsWithinChildCompilationFixture = () => ({ + "app/fixtures/side-effect-imports-within-child-compilation/styles.css.ts": js` import "./nested-side-effect.css"; `, - "app/fixtures/side-effect-imports-within-child-compilation/nested-side-effect.css.ts": js` + "app/fixtures/side-effect-imports-within-child-compilation/nested-side-effect.css.ts": js` import { globalStyle } from "@vanilla-extract/css"; globalStyle(".side-effect-imports-within-child-compilation", { padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/routes/side-effect-imports-within-child-compilation-test.jsx": js` + "app/routes/side-effect-imports-within-child-compilation-test.jsx": js` import "../fixtures/side-effect-imports-within-child-compilation/styles.css"; export default function() { @@ -263,33 +268,31 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("side-effect imports within child compilation", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/side-effect-imports-within-child-compilation-test"); - let locator = await page.locator( - "[data-testid='side-effect-imports-within-child-compilation']" - ); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + }); + test("side-effect imports within child compilation", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/side-effect-imports-within-child-compilation-test"); + let locator = await page.locator( + "[data-testid='side-effect-imports-within-child-compilation']" + ); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let stableIdentifiersFixture = () => ({ - "app/fixtures/stable-identifiers/styles_a.css.ts": js` - import { style } from "@vanilla-extract/css"; + let stableIdentifiersFixture = () => ({ + "app/fixtures/stable-identifiers/styles_a.css.ts": js` import { shared } from "./shared.css"; - export const root = style([shared]); + export const root = shared; `, - "app/fixtures/stable-identifiers/styles_b.css.ts": js` - import { style } from "@vanilla-extract/css"; + "app/fixtures/stable-identifiers/styles_b.css.ts": js` import { shared } from "./shared.css"; - export const root = style([shared]); + export const root = shared; `, - "app/fixtures/stable-identifiers/shared.css.ts": js` + "app/fixtures/stable-identifiers/shared.css.ts": js` import { style } from "@vanilla-extract/css"; export const shared = style({ @@ -297,7 +300,7 @@ test.describe("Vanilla Extract", () => { background: 'peachpuff', }); `, - "app/routes/stable-identifiers-test.jsx": js` + "app/routes/stable-identifiers-test.jsx": js` import * as styles_a from "../fixtures/stable-identifiers/styles_a.css"; import * as styles_b from "../fixtures/stable-identifiers/styles_b.css"; @@ -311,25 +314,25 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("stable identifiers", async ({ page }) => { - // This test ensures that file scoping is working as expected and - // identifiers are stable across different .css.ts contexts. We test this by - // using the same shared style in two different .css.ts files and then - // asserting that it's the same class name. - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/stable-identifiers-test"); - let locator = await page.locator("[data-testid='stable-identifiers']"); - let { padding, classList } = await locator.evaluate((element) => ({ - padding: window.getComputedStyle(element).padding, - classList: Array.from(element.classList), - })); - expect(padding).toBe(TEST_PADDING_VALUE); - expect(classList.length).toBe(1); - }); + }); + test("stable identifiers", async ({ page }) => { + // This test ensures that file scoping is working as expected and + // identifiers are stable across different .css.ts contexts. We test this by + // using the same shared style in two different .css.ts files and then + // asserting that it's the same class name. + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/stable-identifiers-test"); + let locator = await page.locator("[data-testid='stable-identifiers']"); + let { padding, classList } = await locator.evaluate((element) => ({ + padding: window.getComputedStyle(element).padding, + classList: Array.from(element.classList), + })); + expect(padding).toBe(TEST_PADDING_VALUE); + expect(classList.length).toBe(1); + }); - let imageUrlsViaCssUrlFixture = () => ({ - "app/fixtures/imageUrlsViaCssUrl/styles.css.ts": js` + let imageUrlsViaCssUrlFixture = () => ({ + "app/fixtures/imageUrlsViaCssUrl/styles.css.ts": js` import { style } from "@vanilla-extract/css"; export const root = style({ @@ -338,12 +341,12 @@ test.describe("Vanilla Extract", () => { padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/fixtures/imageUrlsViaCssUrl/image.svg": ` + "app/fixtures/imageUrlsViaCssUrl/image.svg": ` `, - "app/routes/image-urls-via-css-url-test.jsx": js` + "app/routes/image-urls-via-css-url-test.jsx": js` import * as styles from "../fixtures/imageUrlsViaCssUrl/styles.css"; export default function() { @@ -354,24 +357,26 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("image URLs via CSS URL", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); - }); - await app.goto("/image-urls-via-css-url-test"); - let locator = await page.locator("[data-testid='image-urls-via-css-url']"); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); - }); + }); + test("image URLs via CSS URL", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); + }); + await app.goto("/image-urls-via-css-url-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-css-url']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaRootRelativeCssUrlFixture = () => ({ - "app/fixtures/imageUrlsViaRootRelativeCssUrl/styles.css.ts": js` + let imageUrlsViaRootRelativeCssUrlFixture = () => ({ + "app/fixtures/imageUrlsViaRootRelativeCssUrl/styles.css.ts": js` import { style } from "@vanilla-extract/css"; export const root = style({ @@ -380,12 +385,12 @@ test.describe("Vanilla Extract", () => { padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/fixtures/imageUrlsViaRootRelativeCssUrl/image.svg": ` + "app/fixtures/imageUrlsViaRootRelativeCssUrl/image.svg": ` `, - "app/routes/image-urls-via-root-relative-css-url-test.jsx": js` + "app/routes/image-urls-via-root-relative-css-url-test.jsx": js` import * as styles from "../fixtures/imageUrlsViaRootRelativeCssUrl/styles.css"; export default function() { @@ -396,26 +401,26 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("image URLs via root-relative CSS URL", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); - }); - await app.goto("/image-urls-via-root-relative-css-url-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-root-relative-css-url']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); - }); + }); + test("image URLs via root-relative CSS URL", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); + }); + await app.goto("/image-urls-via-root-relative-css-url-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-root-relative-css-url']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaJsImportFixture = () => ({ - "app/fixtures/imageUrlsViaJsImport/styles.css.ts": js` + let imageUrlsViaJsImportFixture = () => ({ + "app/fixtures/imageUrlsViaJsImport/styles.css.ts": js` import { style } from "@vanilla-extract/css"; import href from "./image.svg"; @@ -425,12 +430,12 @@ test.describe("Vanilla Extract", () => { padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/fixtures/imageUrlsViaJsImport/image.svg": ` + "app/fixtures/imageUrlsViaJsImport/image.svg": ` `, - "app/routes/image-urls-via-js-import-test.jsx": js` + "app/routes/image-urls-via-js-import-test.jsx": js` import * as styles from "../fixtures/imageUrlsViaJsImport/styles.css"; export default function() { @@ -441,26 +446,26 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("image URLs via JS import", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); - }); - await app.goto("/image-urls-via-js-import-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-js-import']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); - }); + }); + test("image URLs via JS import", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); + }); + await app.goto("/image-urls-via-js-import-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-js-import']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaRootRelativeJsImportFixture = () => ({ - "app/fixtures/imageUrlsViaRootRelativeJsImport/styles.css.ts": js` + let imageUrlsViaRootRelativeJsImportFixture = () => ({ + "app/fixtures/imageUrlsViaRootRelativeJsImport/styles.css.ts": js` import { style } from "@vanilla-extract/css"; import href from "~/fixtures/imageUrlsViaRootRelativeJsImport/image.svg"; @@ -470,12 +475,12 @@ test.describe("Vanilla Extract", () => { padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); `, - "app/fixtures/imageUrlsViaRootRelativeJsImport/image.svg": ` + "app/fixtures/imageUrlsViaRootRelativeJsImport/image.svg": ` `, - "app/routes/image-urls-via-root-relative-js-import-test.jsx": js` + "app/routes/image-urls-via-root-relative-js-import-test.jsx": js` import * as styles from "../fixtures/imageUrlsViaRootRelativeJsImport/styles.css"; export default function() { @@ -486,26 +491,26 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("image URLs via root-relative JS import", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); - }); - await app.goto("/image-urls-via-root-relative-js-import-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-root-relative-js-import']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); - }); + }); + test("image URLs via root-relative JS import", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); + }); + await app.goto("/image-urls-via-root-relative-js-import-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-root-relative-js-import']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaClassCompositionFixture = () => ({ - "app/fixtures/imageUrlsViaClassComposition/styles.css.ts": js` + let imageUrlsViaClassCompositionFixture = () => ({ + "app/fixtures/imageUrlsViaClassComposition/styles.css.ts": js` import { style } from "@vanilla-extract/css"; import { backgroundImage } from "./nested/backgroundImage.css"; @@ -517,19 +522,19 @@ test.describe("Vanilla Extract", () => { } ]); `, - "app/fixtures/imageUrlsViaClassComposition/nested/backgroundImage.css.ts": js` + "app/fixtures/imageUrlsViaClassComposition/nested/backgroundImage.css.ts": js` import { style } from "@vanilla-extract/css"; export const backgroundImage = style({ backgroundImage: 'url(../image.svg)', }); `, - "app/fixtures/imageUrlsViaClassComposition/image.svg": ` + "app/fixtures/imageUrlsViaClassComposition/image.svg": ` `, - "app/routes/image-urls-via-class-composition-test.jsx": js` + "app/routes/image-urls-via-class-composition-test.jsx": js` import * as styles from "../fixtures/imageUrlsViaClassComposition/styles.css"; export default function() { @@ -540,26 +545,26 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("image URLs via class composition", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); - }); - await app.goto("/image-urls-via-class-composition-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-class-composition']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); - }); + }); + test("image URLs via class composition", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); + }); + await app.goto("/image-urls-via-class-composition-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-class-composition']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaJsImportClassCompositionFixture = () => ({ - "app/fixtures/imageUrlsViaJsImportClassComposition/styles.css.ts": js` + let imageUrlsViaJsImportClassCompositionFixture = () => ({ + "app/fixtures/imageUrlsViaJsImportClassComposition/styles.css.ts": js` import { style } from "@vanilla-extract/css"; import { backgroundImage } from "./nested/backgroundImage.css"; @@ -571,7 +576,7 @@ test.describe("Vanilla Extract", () => { } ]); `, - "app/fixtures/imageUrlsViaJsImportClassComposition/nested/backgroundImage.css.ts": js` + "app/fixtures/imageUrlsViaJsImportClassComposition/nested/backgroundImage.css.ts": js` import { style } from "@vanilla-extract/css"; import href from "../image.svg"; @@ -579,12 +584,12 @@ test.describe("Vanilla Extract", () => { backgroundImage: 'url(' + href + ')', }); `, - "app/fixtures/imageUrlsViaJsImportClassComposition/image.svg": ` + "app/fixtures/imageUrlsViaJsImportClassComposition/image.svg": ` `, - "app/routes/image-urls-via-js-import-class-composition-test.jsx": js` + "app/routes/image-urls-via-js-import-class-composition-test.jsx": js` import * as styles from "../fixtures/imageUrlsViaJsImportClassComposition/styles.css"; export default function() { @@ -595,115 +600,23 @@ test.describe("Vanilla Extract", () => { ) } `, - }); - test("image URLs via JS import class composition", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); - }); - await app.goto("/image-urls-via-js-import-class-composition-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-js-import-class-composition']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); - }); - - let standardImageUrlsViaJsImportFixture = () => ({ - "app/fixtures/standardImageUrlsViaJsImport/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - - export { default as src } from "./image.svg"; - - export const root = style({ - width: 200, - height: 200, }); - `, - "app/fixtures/standardImageUrlsViaJsImport/image.svg": ` - - - - `, - "app/routes/standard-image-urls-via-js-import-test.jsx": js` - import { root, src } from "../fixtures/standardImageUrlsViaJsImport/styles.css"; - - export default function() { - return ( - - ) - } - `, - }); - test("standard image URLs via JS import", async ({ page }) => { - // This ensures that image URLs are fully resolved within the CSS file - // rather than using some intermediary format that needs to be resolved - // later. This is important to ensure that image import semantics are the - // same throughout the app, regardless of whether it's in a JS file or a - // Vanilla Extract context, e.g. you might want to export the image URL - // from the CSS file and use it for preloading. - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); - }); - await app.goto("/standard-image-urls-via-js-import-test"); - let element = await app.getElement( - "[data-testid='standard-image-urls-via-js-import']" - ); - expect(element.attr("src")).toContain(".svg"); - expect(imgStatus).toBe(200); - }); - - let standardImageUrlsViaRootRelativeJsImportFixture = () => ({ - "app/fixtures/standardImageUrlsViaRootRelativeJsImport/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - - export { default as src } from "~/fixtures/standardImageUrlsViaRootRelativeJsImport/image.svg"; - - export const root = style({ - width: 200, - height: 200, + test("image URLs via JS import class composition", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); + }); + await app.goto("/image-urls-via-js-import-class-composition-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-js-import-class-composition']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); }); - `, - "app/fixtures/standardImageUrlsViaRootRelativeJsImport/image.svg": ` - - - - `, - "app/routes/standard-image-urls-via-root-relative-js-import-test.jsx": js` - import { root, src } from "../fixtures/standardImageUrlsViaRootRelativeJsImport/styles.css"; - - export default function() { - return ( - - ) - } - `, - }); - test("standard image URLs via root-relative JS import", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); }); - await app.goto("/standard-image-urls-via-root-relative-js-import-test"); - let element = await app.getElement( - "[data-testid='standard-image-urls-via-root-relative-js-import']" - ); - expect(element.attr("src")).toContain(".svg"); - expect(imgStatus).toBe(200); }); }); diff --git a/package.json b/package.json index 9c6f0e2ba3f..fb8ebe0409f 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "@types/semver": "^7.3.4", "@types/ssri": "^7.1.0", "@types/use-sync-external-store": "^0.0.3", - "@vanilla-extract/css": "^1.9.2", + "@vanilla-extract/css": "0.0.0-create-compiler-api-2023282247", "abort-controller": "^3.0.0", "abortcontroller-polyfill": "^1.7.3", "aws-sdk": "^2.1055.0", @@ -135,6 +135,9 @@ "unist-util-remove": "^3.1.0", "unist-util-visit": "^4.1.1" }, + "resolutions": { + "@vanilla-extract/css": "0.0.0-create-compiler-api-2023282247" + }, "engines": { "node": ">=14" } diff --git a/packages/remix-dev/compiler/compileBrowser.ts b/packages/remix-dev/compiler/compileBrowser.ts index eeb410fa5ce..77b2990cfad 100644 --- a/packages/remix-dev/compiler/compileBrowser.ts +++ b/packages/remix-dev/compiler/compileBrowser.ts @@ -71,11 +71,12 @@ const writeAssetsManifest = async ( ); }; -const isCssBundlingEnabled = (config: RemixConfig) => - config.future.unstable_cssModules || - config.future.unstable_cssSideEffectImports || - config.future.unstable_vanillaExtract; - +const isCssBundlingEnabled = (config: RemixConfig): boolean => + Boolean( + config.future.unstable_cssModules || + config.future.unstable_cssSideEffectImports || + config.future.unstable_vanillaExtract + ); const createEsbuildConfig = ( build: "app" | "css", config: RemixConfig, diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts index a8e017069b7..b5a2479f0e3 100644 --- a/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPlugin.ts @@ -1,169 +1,30 @@ -import { dirname, join } from "path"; -import { - cssFileFilter, - unstable_createCompiler, -} from "@vanilla-extract/integration"; import type { Plugin } from "esbuild"; -import type { RemixConfig } from "../../config"; +import type { RemixConfig, VanillaExtractOptions } from "../../config"; import type { CompileOptions } from "../options"; -import { loaders } from "../loaders"; -import { getPostcssProcessor } from "../utils/postcss"; +import { vanillaExtractPluginCached } from "./vanillaExtractPluginCached"; +import { vanillaExtractPluginUncached } from "./vanillaExtractPluginUncached"; -let compiler: ReturnType; - -let virtualCssFileSuffix = ".vanilla.css"; -let virtualCssFileFilter = /\.vanilla\.css/; - -const staticAssetRegexp = new RegExp( - `(${Object.keys(loaders) - .filter((ext) => ext !== ".css" && loaders[ext] === "file") - .join("|")})$` -); - -const pluginName = "vanilla-extract-plugin"; -const namespace = `${pluginName}-ns`; - -export function vanillaExtractPlugin({ - config, - mode, - outputCss, -}: { +export function vanillaExtractPlugin(options: { config: RemixConfig; mode: CompileOptions["mode"]; outputCss: boolean; }): Plugin { - return { - name: pluginName, - async setup(build) { - let root = config.appDirectory; - - compiler = - compiler || - unstable_createCompiler({ - root, - identifiers: mode === "production" ? "short" : "debug", - vitePlugins: [ - { - name: "remix-assets", - enforce: "pre", - async resolveId(source) { - // Handle root-relative imports within Vanilla Extract files - if (source.startsWith("~")) { - return await this.resolve(source.replace("~", "")); - } - // Handle static asset JS imports - if (source.startsWith("/") && staticAssetRegexp.test(source)) { - return { - external: true, - id: "__REMIX_STATIC_ASSET_PREFIX__" + source, - }; - } - }, - transform(code) { - return code.replace( - /\/@fs\/__REMIX_STATIC_ASSET_PREFIX__\//g, - "~/" - ); - }, - }, - ], - }); - - let postcssProcessor = await getPostcssProcessor({ - config, - context: { - vanillaExtract: true, - }, - }); - - // Resolve virtual CSS files first to avoid resolving the same - // file multiple times since this filter is more specific and - // doesn't require a file system lookup. - build.onResolve({ filter: virtualCssFileFilter }, (args) => { - return { - path: args.path, - namespace, - }; - }); - - vanillaExtractSideEffectsPlugin.setup(build); - - build.onLoad( - { filter: virtualCssFileFilter, namespace }, - async ({ path }) => { - let [relativeFilePath] = path.split(virtualCssFileSuffix); - let { css, filePath } = compiler.getCssForFile(relativeFilePath); - let resolveDir = dirname(join(root, filePath)); - - if (postcssProcessor) { - css = ( - await postcssProcessor.process(css, { - from: path, - to: path, - }) - ).css; - } - - return { - contents: css, - loader: "css", - resolveDir, - }; - } - ); - - build.onLoad({ filter: cssFileFilter }, async ({ path: filePath }) => { - let { source, watchFiles } = await compiler.processVanillaFile( - filePath, - { outputCss } - ); - - return { - contents: source, - resolveDir: dirname(filePath), - loader: "js", - watchFiles: Array.from(watchFiles || []), - }; - }); - }, + let defaultPluginOptions: Required = { + cache: false, }; -} - -/** - * This plugin marks all .css.ts/js files as having side effects. This is - * to ensure that all usages of `globalStyle` are included in the CSS bundle, - * even if a .css.ts/js file has no exports or is otherwise tree-shaken. - */ -const vanillaExtractSideEffectsPlugin: Plugin = { - name: "vanilla-extract-side-effects-plugin", - setup(build) { - let preventInfiniteLoop = {}; - build.onResolve( - { filter: /\.css(\.(j|t)sx?)?(\?.*)?$/, namespace: "file" }, - async (args) => { - if (args.pluginData === preventInfiniteLoop) { - return null; - } + let futureFlag = options.config.future.unstable_vanillaExtract; + let pluginOptions = typeof futureFlag === "object" ? futureFlag : {}; - let resolvedPath = ( - await build.resolve(args.path, { - resolveDir: args.resolveDir, - kind: args.kind, - pluginData: preventInfiniteLoop, - }) - ).path; + let { cache } = { + ...defaultPluginOptions, + ...pluginOptions, + }; - if (!cssFileFilter.test(resolvedPath)) { - return null; - } + let resolvedPlugin = cache + ? vanillaExtractPluginCached + : vanillaExtractPluginUncached; - return { - path: resolvedPath, - sideEffects: true, - }; - } - ); - }, -}; + return resolvedPlugin(options); +} diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPluginCached.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPluginCached.ts new file mode 100644 index 00000000000..06113529ea1 --- /dev/null +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPluginCached.ts @@ -0,0 +1,126 @@ +import { dirname, join } from "path"; +import type { Compiler } from "@vanilla-extract/integration"; +import { cssFileFilter, createCompiler } from "@vanilla-extract/integration"; +import type { Plugin } from "esbuild"; + +import type { RemixConfig } from "../../config"; +import type { CompileOptions } from "../options"; +import { loaders } from "../loaders"; +import { getPostcssProcessor } from "../utils/postcss"; +import { vanillaExtractSideEffectsPlugin } from "./vanillaExtractSideEffectsPlugin"; + +const pluginName = "vanilla-extract-plugin-cached"; +const namespace = `${pluginName}-ns`; +const virtualCssFileFilter = /\.vanilla.css$/; + +const staticAssetRegexp = new RegExp( + `(${Object.keys(loaders) + .filter((ext) => ext !== ".css" && loaders[ext] === "file") + .join("|")})$` +); + +let compiler: Compiler; + +export function vanillaExtractPluginCached({ + config, + mode, + outputCss, +}: { + config: RemixConfig; + mode: CompileOptions["mode"]; + outputCss: boolean; +}): Plugin { + return { + name: pluginName, + async setup(build) { + let root = config.appDirectory; + + compiler = + compiler || + createCompiler({ + root, + identifiers: mode === "production" ? "short" : "debug", + vitePlugins: [ + { + name: "remix-assets", + enforce: "pre", + async resolveId(source) { + // Handle root-relative imports within Vanilla Extract files + if (source.startsWith("~")) { + return await this.resolve(source.replace("~", "")); + } + // Handle static asset JS imports + if (source.startsWith("/") && staticAssetRegexp.test(source)) { + return { + external: true, + id: "~" + source, + }; + } + }, + transform(code) { + // Translate Vite's fs import format for root-relative imports + return code.replace(/\/@fs\/~\//g, "~/"); + }, + }, + ], + }); + + let postcssProcessor = await getPostcssProcessor({ + config, + context: { + vanillaExtract: true, + }, + }); + + // Resolve virtual CSS files first to avoid resolving the same + // file multiple times since this filter is more specific and + // doesn't require a file system lookup. + build.onResolve({ filter: virtualCssFileFilter }, (args) => { + return { + path: args.path, + namespace, + }; + }); + + vanillaExtractSideEffectsPlugin.setup(build); + + build.onLoad( + { filter: virtualCssFileFilter, namespace }, + async ({ path }) => { + let [relativeFilePath] = path.split(".vanilla.css"); + let { css, filePath } = compiler.getCssForFile(relativeFilePath); + let resolveDir = dirname(join(root, filePath)); + + if (postcssProcessor) { + css = ( + await postcssProcessor.process(css, { + from: path, + to: path, + }) + ).css; + } + + return { + contents: css, + loader: "css", + resolveDir, + }; + } + ); + + build.onLoad({ filter: cssFileFilter }, async ({ path: filePath }) => { + let { source, watchFiles } = await compiler.processVanillaFile( + filePath, + { outputCss } + ); + + return { + contents: source, + resolveDir: dirname(filePath), + loader: "js", + watchFiles: Array.from(watchFiles || []), + }; + }); + }, + }; +} diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPluginUncached.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPluginUncached.ts new file mode 100644 index 00000000000..f33fb12deca --- /dev/null +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPluginUncached.ts @@ -0,0 +1,182 @@ +import { dirname, join, extname } from "path"; +import type { IdentifierOption } from "@vanilla-extract/integration"; +import { + cssFileFilter, + virtualCssFileFilter, + processVanillaFile, + getSourceFromVirtualCssFile, + transform, +} from "@vanilla-extract/integration"; +import * as fse from "fs-extra"; +import * as esbuild from "esbuild"; + +import type { RemixConfig } from "../../config"; +import type { CompileOptions } from "../options"; +import { loaders } from "../loaders"; +import { getPostcssProcessor } from "../utils/postcss"; +import { vanillaExtractSideEffectsPlugin } from "./vanillaExtractSideEffectsPlugin"; + +const pluginName = "vanilla-extract-plugin-uncached"; +const namespace = `${pluginName}-ns`; + +export function vanillaExtractPluginUncached({ + config, + mode, + outputCss, +}: { + config: RemixConfig; + mode: CompileOptions["mode"]; + outputCss: boolean; +}): esbuild.Plugin { + return { + name: pluginName, + async setup(build) { + let postcssProcessor = await getPostcssProcessor({ + config, + context: { + vanillaExtract: true, + }, + }); + let { rootDirectory } = config; + + // Resolve virtual CSS files first to avoid resolving the same + // file multiple times since this filter is more specific and + // doesn't require a file system lookup. + build.onResolve({ filter: virtualCssFileFilter }, (args) => { + return { + path: args.path, + namespace, + }; + }); + + vanillaExtractSideEffectsPlugin.setup(build); + + build.onLoad( + { filter: virtualCssFileFilter, namespace }, + async ({ path }) => { + let { source, fileName } = await getSourceFromVirtualCssFile(path); + let resolveDir = dirname(join(rootDirectory, fileName)); + + if (postcssProcessor) { + source = ( + await postcssProcessor.process(source, { + from: path, + to: path, + }) + ).css; + } + + return { + contents: source, + loader: "css", + resolveDir, + }; + } + ); + + build.onLoad({ filter: cssFileFilter }, async ({ path: filePath }) => { + let identOption: IdentifierOption = + mode === "production" ? "short" : "debug"; + + let { outputFiles } = await esbuild.build({ + entryPoints: [filePath], + outdir: config.assetsBuildDirectory, + assetNames: build.initialOptions.assetNames, + bundle: true, + external: ["@vanilla-extract"], + platform: "node", + write: false, + plugins: [ + vanillaExtractSideEffectsPlugin, + vanillaExtractTransformPlugin({ rootDirectory, identOption }), + ], + loader: loaders, + absWorkingDir: rootDirectory, + publicPath: config.publicPath, + }); + + let source = outputFiles.find((file) => + file.path.endsWith(".js") + )?.text; + + if (!source) { + return null; + } + + let [contents] = await Promise.all([ + processVanillaFile({ + source, + filePath, + outputCss, + identOption, + }), + outputCss && writeAssets(outputFiles), + ]); + + return { + contents, + resolveDir: dirname(filePath), + loader: "js", + }; + }); + }, + }; +} + +async function writeAssets( + outputFiles: Array +): Promise { + await Promise.all( + outputFiles + .filter((file) => !file.path.endsWith(".js")) + .map(async (file) => { + await fse.ensureDir(dirname(file.path)); + await fse.writeFile(file.path, file.contents); + }) + ); +} + +const loaderForExtension: Record = { + ".js": "js", + ".jsx": "jsx", + ".ts": "ts", + ".tsx": "tsx", +}; + +/** + * This plugin is used within the child compilation. It applies the Vanilla + * Extract file transform to all .css.ts/js files. This is used to add "file + * scope" annotations, which is done via function calls at the beginning and end + * of each file so that we can tell which CSS file the styles belong to when + * evaluating the JS. It's also done to automatically apply debug IDs. + */ +function vanillaExtractTransformPlugin({ + rootDirectory, + identOption, +}: { + identOption: IdentifierOption; + rootDirectory: string; +}): esbuild.Plugin { + return { + name: "vanilla-extract-transform-plugin", + setup(build) { + build.onLoad({ filter: cssFileFilter }, async ({ path }) => { + let source = await fse.readFile(path, "utf-8"); + + let contents = await transform({ + source, + filePath: path, + rootPath: rootDirectory, + packageName: "remix-app", // This option is designed to support scoping hashes for libraries, we can hard code an arbitrary value for simplicity + identOption, + }); + + return { + contents, + loader: loaderForExtension[extname(path)], + resolveDir: dirname(path), + }; + }); + }, + }; +} diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractSideEffectsPlugin.ts b/packages/remix-dev/compiler/plugins/vanillaExtractSideEffectsPlugin.ts new file mode 100644 index 00000000000..c560bedc701 --- /dev/null +++ b/packages/remix-dev/compiler/plugins/vanillaExtractSideEffectsPlugin.ts @@ -0,0 +1,40 @@ +import type { Plugin } from "esbuild"; +import { cssFileFilter } from "@vanilla-extract/integration"; + +/** + * This plugin marks all .css.ts/js files as having side effects. This is + * to ensure that all usages of `globalStyle` are included in the CSS bundle, + * even if a .css.ts/js file has no exports or is otherwise tree-shaken. + */ +export const vanillaExtractSideEffectsPlugin: Plugin = { + name: "vanilla-extract-side-effects-plugin", + setup(build) { + let preventInfiniteLoop = {}; + + build.onResolve( + { filter: /\.css(\.(j|t)sx?)?(\?.*)?$/, namespace: "file" }, + async (args) => { + if (args.pluginData === preventInfiniteLoop) { + return null; + } + + let resolvedPath = ( + await build.resolve(args.path, { + resolveDir: args.resolveDir, + kind: args.kind, + pluginData: preventInfiniteLoop, + }) + ).path; + + if (!cssFileFilter.test(resolvedPath)) { + return null; + } + + return { + path: resolvedPath, + sideEffects: true, + }; + } + ); + }, +}; diff --git a/packages/remix-dev/config.ts b/packages/remix-dev/config.ts index 8686777438a..9b87f5ab714 100644 --- a/packages/remix-dev/config.ts +++ b/packages/remix-dev/config.ts @@ -43,13 +43,17 @@ type Dev = { rebuildPollIntervalMs?: number; }; +export type VanillaExtractOptions = { + cache?: boolean; +}; + interface FutureConfig { unstable_cssModules: boolean; unstable_cssSideEffectImports: boolean; unstable_dev: boolean | Dev; unstable_postcss: boolean; unstable_tailwind: boolean; - unstable_vanillaExtract: boolean; + unstable_vanillaExtract: boolean | VanillaExtractOptions; v2_errorBoundary: boolean; v2_meta: boolean; v2_routeConvention: boolean; @@ -622,7 +626,7 @@ export async function readConfig( unstable_dev: appConfig.future?.unstable_dev ?? false, unstable_postcss: appConfig.future?.unstable_postcss === true, unstable_tailwind: appConfig.future?.unstable_tailwind === true, - unstable_vanillaExtract: appConfig.future?.unstable_vanillaExtract === true, + unstable_vanillaExtract: appConfig.future?.unstable_vanillaExtract ?? false, v2_errorBoundary: appConfig.future?.v2_errorBoundary === true, v2_meta: appConfig.future?.v2_meta === true, v2_routeConvention: appConfig.future?.v2_routeConvention === true, diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json index 7ffabb007fd..7f6e6626250 100644 --- a/packages/remix-dev/package.json +++ b/packages/remix-dev/package.json @@ -30,7 +30,7 @@ "@esbuild-plugins/node-modules-polyfill": "^0.1.4", "@npmcli/package-json": "^2.0.0", "@remix-run/server-runtime": "1.14.0", - "@vanilla-extract/integration": "0.0.0-create-compiler-api-2023264641", + "@vanilla-extract/integration": "0.0.0-create-compiler-api-2023282247", "arg": "^5.0.1", "cacache": "^15.0.5", "chalk": "^4.1.2", diff --git a/yarn.lock b/yarn.lock index 0bec23354da..bd2c7c8ee34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1629,11 +1629,6 @@ dependencies: "@edge-runtime/primitives" "^1.0.1" -"@emotion/hash@^0.8.0": - version "0.8.0" - resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" - integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== - "@emotion/hash@^0.9.0": version "0.9.0" resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz" @@ -3504,28 +3499,10 @@ dependencies: "@babel/core" "^7.20.7" -"@vanilla-extract/css@^0.0.0-create-compiler-api-2023264641": - version "0.0.0-transform-perf-2022820614" - resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-0.0.0-transform-perf-2022820614.tgz#36102382051d11647cee9819277283d3f2f7b70f" - integrity sha512-giCKT4ERcGlTIe2fYJxiSofZChw3M5CoHcjL2juY2BixaWdYetbi1n0Slw3Nia24Su6dXPaKRcGotyooapxolw== - dependencies: - "@emotion/hash" "^0.8.0" - "@vanilla-extract/private" "^1.0.3" - ahocorasick "^1.0.2" - chalk "^4.1.1" - css-what "^5.0.1" - cssesc "^3.0.0" - csstype "^3.0.7" - deep-object-diff "^1.1.0" - deepmerge "^4.2.2" - escape-string-regexp "^4.0.0" - media-query-parser "^2.0.2" - outdent "^0.8.0" - -"@vanilla-extract/css@^1.9.2": - version "1.9.2" - resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.9.2.tgz" - integrity sha512-CE5+R89LOl9XG5dRwEIvVyl/YcS2GkqjdE/XnGJ+p7Fp6Exu08fifv7tY87XxFeCIRAbc9psM+h4lF+wC3Y0fg== +"@vanilla-extract/css@0.0.0-create-compiler-api-2023282247", "@vanilla-extract/css@^0.0.0-create-compiler-api-2023282247": + version "0.0.0-create-compiler-api-2023282247" + resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-0.0.0-create-compiler-api-2023282247.tgz#4884cce2e10219214d2148e0502cc8cc7cb9ea0d" + integrity sha512-uNGJ5geyUe5jCDm0q4YPbvmhpplDzIHBZu9q/v9THyttwr3GH3CRUCBwVdjr+se9XCksJ7qjJcP55yphwihKew== dependencies: "@emotion/hash" "^0.9.0" "@vanilla-extract/private" "^1.0.3" @@ -3534,20 +3511,20 @@ css-what "^5.0.1" cssesc "^3.0.0" csstype "^3.0.7" - deep-object-diff "^1.1.0" + deep-object-diff "^1.1.9" deepmerge "^4.2.2" media-query-parser "^2.0.2" outdent "^0.8.0" -"@vanilla-extract/integration@0.0.0-create-compiler-api-2023264641": - version "0.0.0-create-compiler-api-2023264641" - resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-0.0.0-create-compiler-api-2023264641.tgz#610f6c39ee77a21c03a07d637469eac44831f59c" - integrity sha512-J5hFvXXsiYGhs12N6LruEZONPkkaAd5u4dwHvUZjjUFOiydzwNofo5JTB3PYM1jj7xJxpr9Q7285yCLBXSSPpg== +"@vanilla-extract/integration@0.0.0-create-compiler-api-2023282247": + version "0.0.0-create-compiler-api-2023282247" + resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-0.0.0-create-compiler-api-2023282247.tgz#57486b4bdce1c2b95474d78fdafeaf6e55c29c13" + integrity sha512-mCJQJHEeW2vDVwIMDmG8+zcA/O8r0o6ArHyv2oGEAFN33E/11Er41VWE0olbvW+HF6ckkZjeRWWdWlBaxMDA+g== dependencies: "@babel/core" "^7.20.7" "@babel/plugin-syntax-typescript" "^7.20.0" "@vanilla-extract/babel-plugin-debug-ids" "^1.0.2" - "@vanilla-extract/css" "^0.0.0-create-compiler-api-2023264641" + "@vanilla-extract/css" "^0.0.0-create-compiler-api-2023282247" esbuild "0.17.6" eval "0.1.6" find-up "^5.0.0" @@ -3715,7 +3692,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ahocorasick@1.0.2, ahocorasick@^1.0.2: +ahocorasick@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/ahocorasick/-/ahocorasick-1.0.2.tgz" integrity sha512-hCOfMzbFx5IDutmWLAt6MZwOUjIfSM9G9FyVxytmE4Rs/5YDPWQrD/+IR1w+FweD9H2oOZEnv36TmkjhNURBVA== @@ -5383,9 +5360,9 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -deep-object-diff@^1.1.0: +deep-object-diff@^1.1.9: version "1.1.9" - resolved "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz" + resolved "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz#6df7ef035ad6a0caa44479c536ed7b02570f4595" integrity sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA== deepmerge@^4.2.2: From e342f9c18f85c851cda240988cee92aa73ef74fe Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Thu, 9 Mar 2023 14:55:44 +1100 Subject: [PATCH 10/21] Add changeset --- .changeset/vanilla-extract-cache.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/vanilla-extract-cache.md diff --git a/.changeset/vanilla-extract-cache.md b/.changeset/vanilla-extract-cache.md new file mode 100644 index 00000000000..cb8630c9123 --- /dev/null +++ b/.changeset/vanilla-extract-cache.md @@ -0,0 +1,5 @@ +--- +"@remix-run/dev": minor +--- + +Add experimental support for Vanilla Extract caching which can be enabled by setting `future.unstable_vanillaExtract: { cache: true }` in `remix.config`. This is considered experimental because it's using a brand new Vanilla Extract compiler under the hood. From c5d00de9eeff02e8ededc2aee58fa91bac44d79d Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Thu, 9 Mar 2023 15:17:48 +1100 Subject: [PATCH 11/21] Refactor deterministic build output test --- .../deterministic-build-output-test.ts | 228 +++++++++++------- integration/helpers/create-fixture.ts | 2 +- 2 files changed, 146 insertions(+), 84 deletions(-) diff --git a/integration/deterministic-build-output-test.ts b/integration/deterministic-build-output-test.ts index a3ca418ada5..d100853fa6e 100644 --- a/integration/deterministic-build-output-test.ts +++ b/integration/deterministic-build-output-test.ts @@ -3,33 +3,158 @@ import globby from "globby"; import fs from "fs"; import path from "path"; +import type { FixtureInit } from "./helpers/create-fixture"; import { createFixtureProject, js, css } from "./helpers/create-fixture"; -const configurations = [ +const testCases: Array<{ name: string; init: FixtureInit }> = [ { - name: "future flags enabled", - future: { - unstable_cssModules: true, - unstable_cssSideEffectImports: true, - unstable_postcss: true, - unstable_vanillaExtract: true, - v2_routeConvention: true, + name: "all future flags enabled", + init: { + future: { + unstable_cssModules: true, + unstable_cssSideEffectImports: true, + unstable_postcss: true, + unstable_vanillaExtract: true, + v2_routeConvention: true, + }, + files: { + "app/routes/_index.mdx": "# hello world", + "app/routes/foo.tsx": js` + export * from "~/foo/bar.server"; + import styles from "~/styles/foo.module.css"; + import { vanilla } from "~/styles/vanilla.css"; + import "~/styles/side-effect.css"; + export default () =>
YAY
; + `, + "app/foo/bar.server.ts": "export const meta = () => []", + "app/styles/foo.module.css": css` + .foo { + background-image: url(~/images/foo.svg); + composes: bar from "~/styles/bar.module.css"; + composes: baz from "./baz.module.css"; + } + `, + "app/styles/bar.module.css": css` + .bar { + background-color: peachpuff; + } + `, + "app/styles/baz.module.css": css` + .baz { + color: coral; + } + `, + "app/images/foo.svg": ` + + + + `, + "app/styles/vanilla.css.ts": css` + import { style } from "@vanilla-extract/css"; + import { chocolate } from "./chocolate.css"; + import imageUrl from "~/images/foo.svg"; + + export const vanilla = style([ + chocolate, + { + backgroundImage: [ + "url(" + imageUrl + ")", + "url(~/images/foo.svg)", + ], + } + ]); + `, + "app/styles/chocolate.css.ts": css` + import { style } from "@vanilla-extract/css"; + + export const chocolate = style({ + color: "chocolate", + }); + `, + "app/styles/side-effect.css": css` + .side-effect { + color: mintcream; + } + `, + }, }, }, { - name: "Vanilla Extract cache enabled", - future: { - unstable_cssModules: true, - unstable_cssSideEffectImports: true, - unstable_postcss: true, - unstable_vanillaExtract: { cache: true }, - v2_routeConvention: true, + name: "Vanilla Extract with cache enabled", + init: { + future: { + unstable_cssModules: true, + unstable_cssSideEffectImports: true, + unstable_postcss: true, + unstable_vanillaExtract: { cache: true }, + v2_routeConvention: true, + }, + files: { + "app/routes/_index.mdx": "# hello world", + "app/routes/foo.tsx": js` + export * from "~/foo/bar.server"; + import styles from "~/styles/foo.module.css"; + import { vanilla } from "~/styles/vanilla.css"; + import "~/styles/side-effect.css"; + export default () =>
YAY
; + `, + "app/foo/bar.server.ts": "export const meta = () => []", + "app/styles/foo.module.css": css` + .foo { + background-image: url(~/images/foo.svg); + composes: bar from "~/styles/bar.module.css"; + composes: baz from "./baz.module.css"; + } + `, + "app/styles/bar.module.css": css` + .bar { + background-color: peachpuff; + } + `, + "app/styles/baz.module.css": css` + .baz { + color: coral; + } + `, + "app/images/foo.svg": ` + + + + `, + "app/styles/vanilla.css.ts": css` + import { style } from "@vanilla-extract/css"; + import { chocolate } from "./chocolate.css"; + import imageUrl from "~/images/foo.svg"; + + export const vanilla = style([ + chocolate, + { + backgroundImage: [ + "url(" + imageUrl + ")", + "url(~/images/foo.svg)", + ], + } + ]); + `, + "app/styles/chocolate.css.ts": css` + import { style } from "@vanilla-extract/css"; + + export const chocolate = style({ + color: "chocolate", + }); + `, + "app/styles/side-effect.css": css` + .side-effect { + color: mintcream; + } + `, + }, }, }, -] as const; +]; -configurations.forEach((configuration) => { - test.describe(configuration.name, () => { +testCases.forEach((testCase) => { + test.describe(testCase.name, () => { test("builds deterministically under different paths", async () => { // This test validates various flavors of remix virtual modules to ensure // we get identical builds regardless of the parent paths. If a virtual @@ -49,71 +174,8 @@ configurations.forEach((configuration) => { // * serverEntryModulePlugin (implicitly tested by build) // * serverRouteModulesPlugin (implicitly tested by build) // * vanillaExtractPlugin (via app/routes/foo.tsx' .css.ts file import) - let init = { - future: configuration.future, - files: { - "app/routes/_index.mdx": "# hello world", - "app/routes/foo.tsx": js` - export * from "~/foo/bar.server"; - import styles from "~/styles/foo.module.css"; - import { vanilla } from "~/styles/vanilla.css"; - import "~/styles/side-effect.css"; - export default () =>
YAY
; - `, - "app/foo/bar.server.ts": "export const meta = () => []", - "app/styles/foo.module.css": css` - .foo { - background-image: url(~/images/foo.svg); - composes: bar from "~/styles/bar.module.css"; - composes: baz from "./baz.module.css"; - } - `, - "app/styles/bar.module.css": css` - .bar { - background-color: peachpuff; - } - `, - "app/styles/baz.module.css": css` - .baz { - color: coral; - } - `, - "app/images/foo.svg": ` - - - - `, - "app/styles/vanilla.css.ts": css` - import { style } from "@vanilla-extract/css"; - import { chocolate } from "./chocolate.css"; - import imageUrl from "~/images/foo.svg"; - - export const vanilla = style([ - chocolate, - { - backgroundImage: [ - "url(" + imageUrl + ")", - "url(~/images/foo.svg)", - ], - } - ]); - `, - "app/styles/chocolate.css.ts": css` - import { style } from "@vanilla-extract/css"; - - export const chocolate = style({ - color: "chocolate", - }); - `, - "app/styles/side-effect.css": css` - .side-effect { - color: mintcream; - } - `, - }, - }; - let dir1 = await createFixtureProject(init); - let dir2 = await createFixtureProject(init); + let dir1 = await createFixtureProject(testCase.init); + let dir2 = await createFixtureProject(testCase.init); expect(dir1).not.toEqual(dir2); diff --git a/integration/helpers/create-fixture.ts b/integration/helpers/create-fixture.ts index 4238d6a3b75..f10aca44dc1 100644 --- a/integration/helpers/create-fixture.ts +++ b/integration/helpers/create-fixture.ts @@ -15,7 +15,7 @@ import { createRequestHandler as createExpressHandler } from "../../build/node_m const TMP_DIR = path.join(process.cwd(), ".tmp", "integration"); -interface FixtureInit { +export interface FixtureInit { buildStdio?: Writable; sourcemap?: boolean; files?: { [filename: string]: string }; From 50d97163fe4c4c7b3d9c32eabe743e14b9d01041 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Thu, 9 Mar 2023 15:22:50 +1100 Subject: [PATCH 12/21] Restore original dependency order --- packages/remix-dev/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json index 7f6e6626250..438a341f8f3 100644 --- a/packages/remix-dev/package.json +++ b/packages/remix-dev/package.json @@ -47,16 +47,16 @@ "inquirer": "^8.2.1", "jsesc": "3.0.2", "json5": "^2.2.1", - "lodash.debounce": "^4.0.8", "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", "lru-cache": "^7.14.1", "minimatch": "^3.0.4", "node-fetch": "^2.6.7", "ora": "^5.4.1", + "postcss": "^8.4.19", "postcss-discard-duplicates": "^5.1.0", "postcss-load-config": "^4.0.1", "postcss-modules": "^6.0.0", - "postcss": "^8.4.19", "prettier": "2.7.1", "pretty-ms": "^7.0.1", "proxy-agent": "^5.0.0", From d6a418edd7383806882b7a4e3b5cc23017fc0b77 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Thu, 9 Mar 2023 15:41:25 +1100 Subject: [PATCH 13/21] Fix future flag types --- integration/vanilla-extract-test.ts | 4 ++-- packages/remix-react/entry.ts | 6 +++++- packages/remix-server-runtime/entry.ts | 6 +++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/integration/vanilla-extract-test.ts b/integration/vanilla-extract-test.ts index 7d1701f5a01..389e0518ac1 100644 --- a/integration/vanilla-extract-test.ts +++ b/integration/vanilla-extract-test.ts @@ -7,8 +7,8 @@ import { createAppFixture, createFixture, js } from "./helpers/create-fixture"; const TEST_PADDING_VALUE = "20px"; const configurations = [ - { name: "Cached", config: { cached: true } }, - { name: "Uncached", config: "true" }, + { name: "Cached", config: { cache: true } }, + { name: "Uncached", config: true }, ] as const; test.describe("Vanilla Extract", () => { diff --git a/packages/remix-react/entry.ts b/packages/remix-react/entry.ts index d97ea699656..3e4f9450870 100644 --- a/packages/remix-react/entry.ts +++ b/packages/remix-react/entry.ts @@ -26,13 +26,17 @@ type Dev = { rebuildPollIntervalMs?: number; }; +type VanillaExtractOptions = { + cache?: boolean; +}; + export interface FutureConfig { unstable_cssModules: boolean; unstable_cssSideEffectImports: boolean; unstable_dev: boolean | Dev; unstable_postcss: boolean; unstable_tailwind: boolean; - unstable_vanillaExtract: boolean; + unstable_vanillaExtract: boolean | VanillaExtractOptions; v2_errorBoundary: boolean; v2_meta: boolean; v2_routeConvention: boolean; diff --git a/packages/remix-server-runtime/entry.ts b/packages/remix-server-runtime/entry.ts index 2d5136ce977..ce8b31cdec3 100644 --- a/packages/remix-server-runtime/entry.ts +++ b/packages/remix-server-runtime/entry.ts @@ -18,13 +18,17 @@ type Dev = { rebuildPollIntervalMs?: number; }; +type VanillaExtractOptions = { + cache?: boolean; +}; + export interface FutureConfig { unstable_cssModules: boolean; unstable_cssSideEffectImports: boolean; unstable_dev: boolean | Dev; unstable_postcss: boolean; unstable_tailwind: boolean; - unstable_vanillaExtract: boolean; + unstable_vanillaExtract: boolean | VanillaExtractOptions; v2_errorBoundary: boolean; v2_meta: boolean; v2_routeConvention: boolean; From 3930975dbaeb00ce7f5a57e63f1b862cb4a6b2a3 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Thu, 9 Mar 2023 17:23:46 +1100 Subject: [PATCH 14/21] Tidy up test --- integration/vanilla-extract-test.ts | 1146 +++++++++++++-------------- 1 file changed, 569 insertions(+), 577 deletions(-) diff --git a/integration/vanilla-extract-test.ts b/integration/vanilla-extract-test.ts index 389e0518ac1..fd8c5844da9 100644 --- a/integration/vanilla-extract-test.ts +++ b/integration/vanilla-extract-test.ts @@ -14,613 +14,605 @@ const configurations = [ test.describe("Vanilla Extract", () => { configurations.forEach((configuration) => { test.describe(configuration.name, () => { - test.describe("Vanilla Extract", () => { - let fixture: Fixture; - let appFixture: AppFixture; + let fixture: Fixture; + let appFixture: AppFixture; - test.beforeAll(async () => { - fixture = await createFixture({ - future: { - v2_routeConvention: true, - // Enable all CSS future flags to - // ensure features don't clash - unstable_cssModules: true, - unstable_cssSideEffectImports: true, - unstable_postcss: true, - unstable_tailwind: true, - unstable_vanillaExtract: configuration.config, - }, - files: { - "app/root.jsx": js` - import { Links, Outlet } from "@remix-run/react"; - import { cssBundleHref } from "@remix-run/css-bundle"; - export function links() { - return [{ rel: "stylesheet", href: cssBundleHref }]; - } - export default function Root() { - return ( - - - - - - - - - ) - } - `, - ...typeScriptFixture(), - ...javaScriptFixture(), - ...classCompositionFixture(), - ...rootRelativeClassCompositionFixture(), - ...sideEffectImportsFixture(), - ...sideEffectImportsWithinChildCompilationFixture(), - ...stableIdentifiersFixture(), - ...imageUrlsViaCssUrlFixture(), - ...imageUrlsViaRootRelativeCssUrlFixture(), - ...imageUrlsViaJsImportFixture(), - ...imageUrlsViaRootRelativeJsImportFixture(), - ...imageUrlsViaClassCompositionFixture(), - ...imageUrlsViaJsImportClassCompositionFixture(), - }, - }); - appFixture = await createAppFixture(fixture); + test.beforeAll(async () => { + fixture = await createFixture({ + future: { + v2_routeConvention: true, + // Enable all CSS future flags to + // ensure features don't clash + unstable_cssModules: true, + unstable_cssSideEffectImports: true, + unstable_postcss: true, + unstable_tailwind: true, + unstable_vanillaExtract: configuration.config, + }, + files: { + "app/root.jsx": js` + import { Links, Outlet } from "@remix-run/react"; + import { cssBundleHref } from "@remix-run/css-bundle"; + export function links() { + return [{ rel: "stylesheet", href: cssBundleHref }]; + } + export default function Root() { + return ( + + + + + + + + + ) + } + `, + ...typeScriptFixture(), + ...javaScriptFixture(), + ...classCompositionFixture(), + ...rootRelativeClassCompositionFixture(), + ...sideEffectImportsFixture(), + ...sideEffectImportsWithinChildCompilationFixture(), + ...stableIdentifiersFixture(), + ...imageUrlsViaCssUrlFixture(), + ...imageUrlsViaRootRelativeCssUrlFixture(), + ...imageUrlsViaJsImportFixture(), + ...imageUrlsViaRootRelativeJsImportFixture(), + ...imageUrlsViaClassCompositionFixture(), + ...imageUrlsViaJsImportClassCompositionFixture(), + }, }); + appFixture = await createAppFixture(fixture); + }); - test.afterAll(() => appFixture.close()); + test.afterAll(() => appFixture.close()); - let typeScriptFixture = () => ({ - "app/fixtures/typescript/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - - export const root = style({ - background: 'peachpuff', - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/routes/typescript-test.jsx": js` - import * as styles from "../fixtures/typescript/styles.css"; - - export default function() { - return ( -
- TypeScript test -
- ) - } - `, - }); - test("TypeScript", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/typescript-test"); - let locator = await page.locator("[data-testid='typescript']"); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + let typeScriptFixture = () => ({ + "app/fixtures/typescript/styles.css.ts": js` + import { style } from "@vanilla-extract/css"; + + export const root = style({ + background: 'peachpuff', + padding: ${JSON.stringify(TEST_PADDING_VALUE)} + }); + `, + "app/routes/typescript-test.jsx": js` + import * as styles from "../fixtures/typescript/styles.css"; + + export default function() { + return ( +
+ TypeScript test +
+ ) + } + `, + }); + test("TypeScript", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/typescript-test"); + let locator = await page.locator("[data-testid='typescript']"); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let javaScriptFixture = () => ({ - "app/fixtures/javascript/styles.css.js": js` - import { style } from "@vanilla-extract/css"; - - export const root = style({ - background: 'peachpuff', - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/routes/javascript-test.jsx": js` - import * as styles from "../fixtures/javascript/styles.css"; - - export default function() { - return ( -
- javaScript test -
- ) - } - `, - }); - test("JavaScript", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/javascript-test"); - let locator = await page.locator("[data-testid='javascript']"); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + let javaScriptFixture = () => ({ + "app/fixtures/javascript/styles.css.js": js` + import { style } from "@vanilla-extract/css"; + + export const root = style({ + background: 'peachpuff', + padding: ${JSON.stringify(TEST_PADDING_VALUE)} + }); + `, + "app/routes/javascript-test.jsx": js` + import * as styles from "../fixtures/javascript/styles.css"; + + export default function() { + return ( +
+ javaScript test +
+ ) + } + `, + }); + test("JavaScript", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/javascript-test"); + let locator = await page.locator("[data-testid='javascript']"); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let classCompositionFixture = () => ({ - "app/fixtures/class-composition/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - import { padding } from "./padding.css"; - - export const root = style([ - padding, - { background: 'peachpuff' }, - ]); - `, - "app/fixtures/class-composition/padding.css.ts": js` - import { style } from "@vanilla-extract/css"; - - export const padding = style({ - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/routes/class-composition-test.jsx": js` - import * as styles from "../fixtures/class-composition/styles.css"; - - export default function() { - return ( -
- Class composition test -
- ) - } - `, - }); - test("class composition", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/class-composition-test"); - let locator = await page.locator("[data-testid='class-composition']"); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + let classCompositionFixture = () => ({ + "app/fixtures/class-composition/styles.css.ts": js` + import { style } from "@vanilla-extract/css"; + import { padding } from "./padding.css"; + + export const root = style([ + padding, + { background: 'peachpuff' }, + ]); + `, + "app/fixtures/class-composition/padding.css.ts": js` + import { style } from "@vanilla-extract/css"; + + export const padding = style({ + padding: ${JSON.stringify(TEST_PADDING_VALUE)} + }); + `, + "app/routes/class-composition-test.jsx": js` + import * as styles from "../fixtures/class-composition/styles.css"; + + export default function() { + return ( +
+ Class composition test +
+ ) + } + `, + }); + test("class composition", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/class-composition-test"); + let locator = await page.locator("[data-testid='class-composition']"); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let rootRelativeClassCompositionFixture = () => ({ - "app/fixtures/root-relative-class-composition/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - import { padding } from "~/fixtures/root-relative-class-composition/padding.css"; - - export const root = style([ - padding, - { background: 'peachpuff' }, - ]); - `, - "app/fixtures/root-relative-class-composition/padding.css.ts": js` - import { style } from "@vanilla-extract/css"; - - export const padding = style({ - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/routes/root-relative-class-composition-test.jsx": js` - import * as styles from "../fixtures/root-relative-class-composition/styles.css"; - - export default function() { - return ( -
- Root-relative class composition test -
- ) - } - `, - }); - test("root-relative class composition", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/root-relative-class-composition-test"); - let locator = await page.locator( - "[data-testid='root-relative-class-composition']" - ); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + let rootRelativeClassCompositionFixture = () => ({ + "app/fixtures/root-relative-class-composition/styles.css.ts": js` + import { style } from "@vanilla-extract/css"; + import { padding } from "~/fixtures/root-relative-class-composition/padding.css"; + + export const root = style([ + padding, + { background: 'peachpuff' }, + ]); + `, + "app/fixtures/root-relative-class-composition/padding.css.ts": js` + import { style } from "@vanilla-extract/css"; + + export const padding = style({ + padding: ${JSON.stringify(TEST_PADDING_VALUE)} + }); + `, + "app/routes/root-relative-class-composition-test.jsx": js` + import * as styles from "../fixtures/root-relative-class-composition/styles.css"; + + export default function() { + return ( +
+ Root-relative class composition test +
+ ) + } + `, + }); + test("root-relative class composition", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/root-relative-class-composition-test"); + let locator = await page.locator( + "[data-testid='root-relative-class-composition']" + ); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let sideEffectImportsFixture = () => ({ - "app/fixtures/side-effect-imports/styles.css.ts": js` - import { globalStyle } from "@vanilla-extract/css"; - - globalStyle(".side-effect-imports", { - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/routes/side-effect-imports-test.jsx": js` - import "../fixtures/side-effect-imports/styles.css"; - - export default function() { - return ( -
- Side-effect imports test -
- ) - } - `, - }); - test("side-effect imports", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/side-effect-imports-test"); - let locator = await page.locator( - "[data-testid='side-effect-imports']" - ); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + let sideEffectImportsFixture = () => ({ + "app/fixtures/side-effect-imports/styles.css.ts": js` + import { globalStyle } from "@vanilla-extract/css"; + + globalStyle(".side-effect-imports", { + padding: ${JSON.stringify(TEST_PADDING_VALUE)} + }); + `, + "app/routes/side-effect-imports-test.jsx": js` + import "../fixtures/side-effect-imports/styles.css"; + + export default function() { + return ( +
+ Side-effect imports test +
+ ) + } + `, + }); + test("side-effect imports", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/side-effect-imports-test"); + let locator = await page.locator("[data-testid='side-effect-imports']"); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let sideEffectImportsWithinChildCompilationFixture = () => ({ - "app/fixtures/side-effect-imports-within-child-compilation/styles.css.ts": js` - import "./nested-side-effect.css"; - `, - "app/fixtures/side-effect-imports-within-child-compilation/nested-side-effect.css.ts": js` - import { globalStyle } from "@vanilla-extract/css"; - - globalStyle(".side-effect-imports-within-child-compilation", { - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/routes/side-effect-imports-within-child-compilation-test.jsx": js` - import "../fixtures/side-effect-imports-within-child-compilation/styles.css"; - - export default function() { - return ( -
- Side-effect imports within child compilation test -
- ) - } - `, - }); - test("side-effect imports within child compilation", async ({ - page, - }) => { - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/side-effect-imports-within-child-compilation-test"); - let locator = await page.locator( - "[data-testid='side-effect-imports-within-child-compilation']" - ); - let padding = await locator.evaluate( - (element) => window.getComputedStyle(element).padding - ); - expect(padding).toBe(TEST_PADDING_VALUE); - }); + let sideEffectImportsWithinChildCompilationFixture = () => ({ + "app/fixtures/side-effect-imports-within-child-compilation/styles.css.ts": js` + import "./nested-side-effect.css"; + `, + "app/fixtures/side-effect-imports-within-child-compilation/nested-side-effect.css.ts": js` + import { globalStyle } from "@vanilla-extract/css"; + + globalStyle(".side-effect-imports-within-child-compilation", { + padding: ${JSON.stringify(TEST_PADDING_VALUE)} + }); + `, + "app/routes/side-effect-imports-within-child-compilation-test.jsx": js` + import "../fixtures/side-effect-imports-within-child-compilation/styles.css"; + + export default function() { + return ( +
+ Side-effect imports within child compilation test +
+ ) + } + `, + }); + test("side-effect imports within child compilation", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/side-effect-imports-within-child-compilation-test"); + let locator = await page.locator( + "[data-testid='side-effect-imports-within-child-compilation']" + ); + let padding = await locator.evaluate( + (element) => window.getComputedStyle(element).padding + ); + expect(padding).toBe(TEST_PADDING_VALUE); + }); - let stableIdentifiersFixture = () => ({ - "app/fixtures/stable-identifiers/styles_a.css.ts": js` - import { style } from "@vanilla-extract/css"; - import { shared } from "./shared.css"; - - export const root = shared; - `, - "app/fixtures/stable-identifiers/styles_b.css.ts": js` - import { style } from "@vanilla-extract/css"; - import { shared } from "./shared.css"; - - export const root = shared; - `, - "app/fixtures/stable-identifiers/shared.css.ts": js` - import { style } from "@vanilla-extract/css"; - - export const shared = style({ - padding: ${JSON.stringify(TEST_PADDING_VALUE)}, - background: 'peachpuff', - }); - `, - "app/routes/stable-identifiers-test.jsx": js` - import * as styles_a from "../fixtures/stable-identifiers/styles_a.css"; - import * as styles_b from "../fixtures/stable-identifiers/styles_b.css"; - - const styles = new Set([styles_a.root, styles_b.root]); - - export default function() { - return ( -
- Stable identifiers test -
- ) - } - `, - }); - test("stable identifiers", async ({ page }) => { - // This test ensures that file scoping is working as expected and - // identifiers are stable across different .css.ts contexts. We test this by - // using the same shared style in two different .css.ts files and then - // asserting that it's the same class name. - let app = new PlaywrightFixture(appFixture, page); - await app.goto("/stable-identifiers-test"); - let locator = await page.locator( - "[data-testid='stable-identifiers']" - ); - let { padding, classList } = await locator.evaluate((element) => ({ - padding: window.getComputedStyle(element).padding, - classList: Array.from(element.classList), - })); - expect(padding).toBe(TEST_PADDING_VALUE); - expect(classList.length).toBe(1); - }); + let stableIdentifiersFixture = () => ({ + "app/fixtures/stable-identifiers/styles_a.css.ts": js` + import { style } from "@vanilla-extract/css"; + import { shared } from "./shared.css"; + + export const root = shared; + `, + "app/fixtures/stable-identifiers/styles_b.css.ts": js` + import { style } from "@vanilla-extract/css"; + import { shared } from "./shared.css"; + + export const root = shared; + `, + "app/fixtures/stable-identifiers/shared.css.ts": js` + import { style } from "@vanilla-extract/css"; + + export const shared = style({ + padding: ${JSON.stringify(TEST_PADDING_VALUE)}, + background: 'peachpuff', + }); + `, + "app/routes/stable-identifiers-test.jsx": js` + import * as styles_a from "../fixtures/stable-identifiers/styles_a.css"; + import * as styles_b from "../fixtures/stable-identifiers/styles_b.css"; + + const styles = new Set([styles_a.root, styles_b.root]); + + export default function() { + return ( +
+ Stable identifiers test +
+ ) + } + `, + }); + test("stable identifiers", async ({ page }) => { + // This test ensures that file scoping is working as expected and + // identifiers are stable across different .css.ts contexts. We test this by + // using the same shared style in two different .css.ts files and then + // asserting that it's the same class name. + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/stable-identifiers-test"); + let locator = await page.locator("[data-testid='stable-identifiers']"); + let { padding, classList } = await locator.evaluate((element) => ({ + padding: window.getComputedStyle(element).padding, + classList: Array.from(element.classList), + })); + expect(padding).toBe(TEST_PADDING_VALUE); + expect(classList.length).toBe(1); + }); - let imageUrlsViaCssUrlFixture = () => ({ - "app/fixtures/imageUrlsViaCssUrl/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - - export const root = style({ - backgroundColor: 'peachpuff', - backgroundImage: 'url("./image.svg")', - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/fixtures/imageUrlsViaCssUrl/image.svg": ` - - - - `, - "app/routes/image-urls-via-css-url-test.jsx": js` - import * as styles from "../fixtures/imageUrlsViaCssUrl/styles.css"; - - export default function() { - return ( -
- Image URLs via CSS URL test -
- ) - } - `, - }); - test("image URLs via CSS URL", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); + let imageUrlsViaCssUrlFixture = () => ({ + "app/fixtures/imageUrlsViaCssUrl/styles.css.ts": js` + import { style } from "@vanilla-extract/css"; + + export const root = style({ + backgroundColor: 'peachpuff', + backgroundImage: 'url("./image.svg")', + padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); - await app.goto("/image-urls-via-css-url-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-css-url']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); + `, + "app/fixtures/imageUrlsViaCssUrl/image.svg": ` + + + + `, + "app/routes/image-urls-via-css-url-test.jsx": js` + import * as styles from "../fixtures/imageUrlsViaCssUrl/styles.css"; + + export default function() { + return ( +
+ Image URLs via CSS URL test +
+ ) + } + `, + }); + test("image URLs via CSS URL", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); }); + await app.goto("/image-urls-via-css-url-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-css-url']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaRootRelativeCssUrlFixture = () => ({ - "app/fixtures/imageUrlsViaRootRelativeCssUrl/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - - export const root = style({ - backgroundColor: 'peachpuff', - backgroundImage: 'url("~/fixtures/imageUrlsViaRootRelativeCssUrl/image.svg")', - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/fixtures/imageUrlsViaRootRelativeCssUrl/image.svg": ` - - - - `, - "app/routes/image-urls-via-root-relative-css-url-test.jsx": js` - import * as styles from "../fixtures/imageUrlsViaRootRelativeCssUrl/styles.css"; - - export default function() { - return ( -
- Image URLs via CSS URL test -
- ) - } - `, - }); - test("image URLs via root-relative CSS URL", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); + let imageUrlsViaRootRelativeCssUrlFixture = () => ({ + "app/fixtures/imageUrlsViaRootRelativeCssUrl/styles.css.ts": js` + import { style } from "@vanilla-extract/css"; + + export const root = style({ + backgroundColor: 'peachpuff', + backgroundImage: 'url("~/fixtures/imageUrlsViaRootRelativeCssUrl/image.svg")', + padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); - await app.goto("/image-urls-via-root-relative-css-url-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-root-relative-css-url']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); + `, + "app/fixtures/imageUrlsViaRootRelativeCssUrl/image.svg": ` + + + + `, + "app/routes/image-urls-via-root-relative-css-url-test.jsx": js` + import * as styles from "../fixtures/imageUrlsViaRootRelativeCssUrl/styles.css"; + + export default function() { + return ( +
+ Image URLs via CSS URL test +
+ ) + } + `, + }); + test("image URLs via root-relative CSS URL", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); }); + await app.goto("/image-urls-via-root-relative-css-url-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-root-relative-css-url']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaJsImportFixture = () => ({ - "app/fixtures/imageUrlsViaJsImport/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - import href from "./image.svg"; - - export const root = style({ - backgroundColor: 'peachpuff', - backgroundImage: 'url(' + href + ')', - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/fixtures/imageUrlsViaJsImport/image.svg": ` - - - - `, - "app/routes/image-urls-via-js-import-test.jsx": js` - import * as styles from "../fixtures/imageUrlsViaJsImport/styles.css"; - - export default function() { - return ( -
- Image URLs via JS import test -
- ) - } - `, - }); - test("image URLs via JS import", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); + let imageUrlsViaJsImportFixture = () => ({ + "app/fixtures/imageUrlsViaJsImport/styles.css.ts": js` + import { style } from "@vanilla-extract/css"; + import href from "./image.svg"; + + export const root = style({ + backgroundColor: 'peachpuff', + backgroundImage: 'url(' + href + ')', + padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); - await app.goto("/image-urls-via-js-import-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-js-import']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); + `, + "app/fixtures/imageUrlsViaJsImport/image.svg": ` + + + + `, + "app/routes/image-urls-via-js-import-test.jsx": js` + import * as styles from "../fixtures/imageUrlsViaJsImport/styles.css"; + + export default function() { + return ( +
+ Image URLs via JS import test +
+ ) + } + `, + }); + test("image URLs via JS import", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); }); + await app.goto("/image-urls-via-js-import-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-js-import']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaRootRelativeJsImportFixture = () => ({ - "app/fixtures/imageUrlsViaRootRelativeJsImport/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - import href from "~/fixtures/imageUrlsViaRootRelativeJsImport/image.svg"; - - export const root = style({ - backgroundColor: 'peachpuff', - backgroundImage: 'url(' + href + ')', - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - }); - `, - "app/fixtures/imageUrlsViaRootRelativeJsImport/image.svg": ` - - - - `, - "app/routes/image-urls-via-root-relative-js-import-test.jsx": js` - import * as styles from "../fixtures/imageUrlsViaRootRelativeJsImport/styles.css"; - - export default function() { - return ( -
- Image URLs via root-relative JS import test -
- ) - } - `, - }); - test("image URLs via root-relative JS import", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); + let imageUrlsViaRootRelativeJsImportFixture = () => ({ + "app/fixtures/imageUrlsViaRootRelativeJsImport/styles.css.ts": js` + import { style } from "@vanilla-extract/css"; + import href from "~/fixtures/imageUrlsViaRootRelativeJsImport/image.svg"; + + export const root = style({ + backgroundColor: 'peachpuff', + backgroundImage: 'url(' + href + ')', + padding: ${JSON.stringify(TEST_PADDING_VALUE)} }); - await app.goto("/image-urls-via-root-relative-js-import-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-root-relative-js-import']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); + `, + "app/fixtures/imageUrlsViaRootRelativeJsImport/image.svg": ` + + + + `, + "app/routes/image-urls-via-root-relative-js-import-test.jsx": js` + import * as styles from "../fixtures/imageUrlsViaRootRelativeJsImport/styles.css"; + + export default function() { + return ( +
+ Image URLs via root-relative JS import test +
+ ) + } + `, + }); + test("image URLs via root-relative JS import", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); }); + await app.goto("/image-urls-via-root-relative-js-import-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-root-relative-js-import']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaClassCompositionFixture = () => ({ - "app/fixtures/imageUrlsViaClassComposition/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - import { backgroundImage } from "./nested/backgroundImage.css"; - - export const root = style([ - backgroundImage, - { - backgroundColor: 'peachpuff', - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - } - ]); - `, - "app/fixtures/imageUrlsViaClassComposition/nested/backgroundImage.css.ts": js` - import { style } from "@vanilla-extract/css"; - - export const backgroundImage = style({ - backgroundImage: 'url(../image.svg)', - }); - `, - "app/fixtures/imageUrlsViaClassComposition/image.svg": ` - - - - `, - "app/routes/image-urls-via-class-composition-test.jsx": js` - import * as styles from "../fixtures/imageUrlsViaClassComposition/styles.css"; - - export default function() { - return ( -
- Image URLs via class composition test -
- ) + let imageUrlsViaClassCompositionFixture = () => ({ + "app/fixtures/imageUrlsViaClassComposition/styles.css.ts": js` + import { style } from "@vanilla-extract/css"; + import { backgroundImage } from "./nested/backgroundImage.css"; + + export const root = style([ + backgroundImage, + { + backgroundColor: 'peachpuff', + padding: ${JSON.stringify(TEST_PADDING_VALUE)} } - `, - }); - test("image URLs via class composition", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); + ]); + `, + "app/fixtures/imageUrlsViaClassComposition/nested/backgroundImage.css.ts": js` + import { style } from "@vanilla-extract/css"; + + export const backgroundImage = style({ + backgroundImage: 'url(../image.svg)', }); - await app.goto("/image-urls-via-class-composition-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-class-composition']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); + `, + "app/fixtures/imageUrlsViaClassComposition/image.svg": ` + + + + `, + "app/routes/image-urls-via-class-composition-test.jsx": js` + import * as styles from "../fixtures/imageUrlsViaClassComposition/styles.css"; + + export default function() { + return ( +
+ Image URLs via class composition test +
+ ) + } + `, + }); + test("image URLs via class composition", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); }); + await app.goto("/image-urls-via-class-composition-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-class-composition']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); + }); - let imageUrlsViaJsImportClassCompositionFixture = () => ({ - "app/fixtures/imageUrlsViaJsImportClassComposition/styles.css.ts": js` - import { style } from "@vanilla-extract/css"; - import { backgroundImage } from "./nested/backgroundImage.css"; - - export const root = style([ - backgroundImage, - { - backgroundColor: 'peachpuff', - padding: ${JSON.stringify(TEST_PADDING_VALUE)} - } - ]); - `, - "app/fixtures/imageUrlsViaJsImportClassComposition/nested/backgroundImage.css.ts": js` - import { style } from "@vanilla-extract/css"; - import href from "../image.svg"; - - export const backgroundImage = style({ - backgroundImage: 'url(' + href + ')', - }); - `, - "app/fixtures/imageUrlsViaJsImportClassComposition/image.svg": ` - - - - `, - "app/routes/image-urls-via-js-import-class-composition-test.jsx": js` - import * as styles from "../fixtures/imageUrlsViaJsImportClassComposition/styles.css"; - - export default function() { - return ( -
- Image URLs via class composition test -
- ) + let imageUrlsViaJsImportClassCompositionFixture = () => ({ + "app/fixtures/imageUrlsViaJsImportClassComposition/styles.css.ts": js` + import { style } from "@vanilla-extract/css"; + import { backgroundImage } from "./nested/backgroundImage.css"; + + export const root = style([ + backgroundImage, + { + backgroundColor: 'peachpuff', + padding: ${JSON.stringify(TEST_PADDING_VALUE)} } - `, - }); - test("image URLs via JS import class composition", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - let imgStatus: number | null = null; - app.page.on("response", (res) => { - if (res.url().endsWith(".svg")) imgStatus = res.status(); + ]); + `, + "app/fixtures/imageUrlsViaJsImportClassComposition/nested/backgroundImage.css.ts": js` + import { style } from "@vanilla-extract/css"; + import href from "../image.svg"; + + export const backgroundImage = style({ + backgroundImage: 'url(' + href + ')', }); - await app.goto("/image-urls-via-js-import-class-composition-test"); - let locator = await page.locator( - "[data-testid='image-urls-via-js-import-class-composition']" - ); - let backgroundImage = await locator.evaluate( - (element) => window.getComputedStyle(element).backgroundImage - ); - expect(backgroundImage).toContain(".svg"); - expect(imgStatus).toBe(200); + `, + "app/fixtures/imageUrlsViaJsImportClassComposition/image.svg": ` + + + + `, + "app/routes/image-urls-via-js-import-class-composition-test.jsx": js` + import * as styles from "../fixtures/imageUrlsViaJsImportClassComposition/styles.css"; + + export default function() { + return ( +
+ Image URLs via class composition test +
+ ) + } + `, + }); + test("image URLs via JS import class composition", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + let imgStatus: number | null = null; + app.page.on("response", (res) => { + if (res.url().endsWith(".svg")) imgStatus = res.status(); }); + await app.goto("/image-urls-via-js-import-class-composition-test"); + let locator = await page.locator( + "[data-testid='image-urls-via-js-import-class-composition']" + ); + let backgroundImage = await locator.evaluate( + (element) => window.getComputedStyle(element).backgroundImage + ); + expect(backgroundImage).toContain(".svg"); + expect(imgStatus).toBe(200); }); }); }); From cb2c7b8117b1dd05a7f4338e3db0417672f12291 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Thu, 9 Mar 2023 17:25:05 +1100 Subject: [PATCH 15/21] Bump to latest Vanilla Extract snapshot release --- package.json | 4 ++-- packages/remix-dev/package.json | 2 +- yarn.lock | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 3d823064fd4..50c32606c6c 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "@types/semver": "^7.3.4", "@types/ssri": "^7.1.0", "@types/use-sync-external-store": "^0.0.3", - "@vanilla-extract/css": "0.0.0-create-compiler-api-2023282247", + "@vanilla-extract/css": "0.0.0-create-compiler-api-20232961929", "abort-controller": "^3.0.0", "abortcontroller-polyfill": "^1.7.3", "aws-sdk": "^2.1055.0", @@ -137,7 +137,7 @@ "unist-util-visit": "^4.1.1" }, "resolutions": { - "@vanilla-extract/css": "0.0.0-create-compiler-api-2023282247" + "@vanilla-extract/css": "0.0.0-create-compiler-api-20232961929" }, "engines": { "node": ">=14" diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json index 438a341f8f3..fe33a0eea61 100644 --- a/packages/remix-dev/package.json +++ b/packages/remix-dev/package.json @@ -30,7 +30,7 @@ "@esbuild-plugins/node-modules-polyfill": "^0.1.4", "@npmcli/package-json": "^2.0.0", "@remix-run/server-runtime": "1.14.0", - "@vanilla-extract/integration": "0.0.0-create-compiler-api-2023282247", + "@vanilla-extract/integration": "0.0.0-create-compiler-api-20232961929", "arg": "^5.0.1", "cacache": "^15.0.5", "chalk": "^4.1.2", diff --git a/yarn.lock b/yarn.lock index 17344b07891..886ed362762 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3499,10 +3499,10 @@ dependencies: "@babel/core" "^7.20.7" -"@vanilla-extract/css@0.0.0-create-compiler-api-2023282247", "@vanilla-extract/css@^0.0.0-create-compiler-api-2023282247": - version "0.0.0-create-compiler-api-2023282247" - resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-0.0.0-create-compiler-api-2023282247.tgz#4884cce2e10219214d2148e0502cc8cc7cb9ea0d" - integrity sha512-uNGJ5geyUe5jCDm0q4YPbvmhpplDzIHBZu9q/v9THyttwr3GH3CRUCBwVdjr+se9XCksJ7qjJcP55yphwihKew== +"@vanilla-extract/css@0.0.0-create-compiler-api-20232961929", "@vanilla-extract/css@^0.0.0-create-compiler-api-20232961929": + version "0.0.0-create-compiler-api-20232961929" + resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-0.0.0-create-compiler-api-20232961929.tgz#b74d601fac2a6e102312cb311810291dd2511711" + integrity sha512-cz7CLwpMLRmpCxBzPU7GQiFpoxWfNvpOHdlxOAnKlWMX4rG//StpBSMV+Y7Exhqscfu5F39w2nbsC+I0uYEx5A== dependencies: "@emotion/hash" "^0.9.0" "@vanilla-extract/private" "^1.0.3" @@ -3516,15 +3516,15 @@ media-query-parser "^2.0.2" outdent "^0.8.0" -"@vanilla-extract/integration@0.0.0-create-compiler-api-2023282247": - version "0.0.0-create-compiler-api-2023282247" - resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-0.0.0-create-compiler-api-2023282247.tgz#57486b4bdce1c2b95474d78fdafeaf6e55c29c13" - integrity sha512-mCJQJHEeW2vDVwIMDmG8+zcA/O8r0o6ArHyv2oGEAFN33E/11Er41VWE0olbvW+HF6ckkZjeRWWdWlBaxMDA+g== +"@vanilla-extract/integration@0.0.0-create-compiler-api-20232961929": + version "0.0.0-create-compiler-api-20232961929" + resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-0.0.0-create-compiler-api-20232961929.tgz#eb91b35e98049df9962bd075a3c012df53f358d9" + integrity sha512-RJxW/m4lBb5KTXaBHlYpxi83tfGlRuF1QrEz+mnJRC9qwCoXdjJte76ix4obed9W2DFS0AsqHXZlWwU4VGzy2Q== dependencies: "@babel/core" "^7.20.7" "@babel/plugin-syntax-typescript" "^7.20.0" "@vanilla-extract/babel-plugin-debug-ids" "^1.0.2" - "@vanilla-extract/css" "^0.0.0-create-compiler-api-2023282247" + "@vanilla-extract/css" "^0.0.0-create-compiler-api-20232961929" esbuild "0.17.6" eval "0.1.6" find-up "^5.0.0" From 66752ff6f6e3e0e56c5eea88d4aa041b8fdbb1e4 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Fri, 10 Mar 2023 08:33:23 +1100 Subject: [PATCH 16/21] Bump Vanilla Extract --- package.json | 4 ++-- packages/remix-dev/package.json | 2 +- yarn.lock | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 50c32606c6c..774fcbd1849 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "@types/semver": "^7.3.4", "@types/ssri": "^7.1.0", "@types/use-sync-external-store": "^0.0.3", - "@vanilla-extract/css": "0.0.0-create-compiler-api-20232961929", + "@vanilla-extract/css": "0.0.0-create-compiler-api-202329212823", "abort-controller": "^3.0.0", "abortcontroller-polyfill": "^1.7.3", "aws-sdk": "^2.1055.0", @@ -137,7 +137,7 @@ "unist-util-visit": "^4.1.1" }, "resolutions": { - "@vanilla-extract/css": "0.0.0-create-compiler-api-20232961929" + "@vanilla-extract/css": "0.0.0-create-compiler-api-202329212823" }, "engines": { "node": ">=14" diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json index fe33a0eea61..2db0b19205a 100644 --- a/packages/remix-dev/package.json +++ b/packages/remix-dev/package.json @@ -30,7 +30,7 @@ "@esbuild-plugins/node-modules-polyfill": "^0.1.4", "@npmcli/package-json": "^2.0.0", "@remix-run/server-runtime": "1.14.0", - "@vanilla-extract/integration": "0.0.0-create-compiler-api-20232961929", + "@vanilla-extract/integration": "0.0.0-create-compiler-api-202329212823", "arg": "^5.0.1", "cacache": "^15.0.5", "chalk": "^4.1.2", diff --git a/yarn.lock b/yarn.lock index 886ed362762..e0f4fae6533 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3499,10 +3499,10 @@ dependencies: "@babel/core" "^7.20.7" -"@vanilla-extract/css@0.0.0-create-compiler-api-20232961929", "@vanilla-extract/css@^0.0.0-create-compiler-api-20232961929": - version "0.0.0-create-compiler-api-20232961929" - resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-0.0.0-create-compiler-api-20232961929.tgz#b74d601fac2a6e102312cb311810291dd2511711" - integrity sha512-cz7CLwpMLRmpCxBzPU7GQiFpoxWfNvpOHdlxOAnKlWMX4rG//StpBSMV+Y7Exhqscfu5F39w2nbsC+I0uYEx5A== +"@vanilla-extract/css@0.0.0-create-compiler-api-202329212823", "@vanilla-extract/css@^0.0.0-create-compiler-api-202329212823": + version "0.0.0-create-compiler-api-202329212823" + resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-0.0.0-create-compiler-api-202329212823.tgz#8d7c3ef67b789d212ed8c7498154ab65363025a6" + integrity sha512-tUG3roPsKK6cC8r332wkXuupVIUmI1BOYzMKaQ6j0At4Apla9e0EDHU2f/E2AZAvj621bibXjHCHgk9pQLG+hQ== dependencies: "@emotion/hash" "^0.9.0" "@vanilla-extract/private" "^1.0.3" @@ -3516,15 +3516,15 @@ media-query-parser "^2.0.2" outdent "^0.8.0" -"@vanilla-extract/integration@0.0.0-create-compiler-api-20232961929": - version "0.0.0-create-compiler-api-20232961929" - resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-0.0.0-create-compiler-api-20232961929.tgz#eb91b35e98049df9962bd075a3c012df53f358d9" - integrity sha512-RJxW/m4lBb5KTXaBHlYpxi83tfGlRuF1QrEz+mnJRC9qwCoXdjJte76ix4obed9W2DFS0AsqHXZlWwU4VGzy2Q== +"@vanilla-extract/integration@0.0.0-create-compiler-api-202329212823": + version "0.0.0-create-compiler-api-202329212823" + resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-0.0.0-create-compiler-api-202329212823.tgz#c461cfe1a263fad040da5c0146f2d43d9cc0c187" + integrity sha512-NjWfVkED0IzSn+F8Hkud6rw4ISvgLQNR7BZwqYnEdGFyG5bdtCorOiBY161IDeQ+9lr9duHnJoU6Qf26cENXxQ== dependencies: "@babel/core" "^7.20.7" "@babel/plugin-syntax-typescript" "^7.20.0" "@vanilla-extract/babel-plugin-debug-ids" "^1.0.2" - "@vanilla-extract/css" "^0.0.0-create-compiler-api-20232961929" + "@vanilla-extract/css" "^0.0.0-create-compiler-api-202329212823" esbuild "0.17.6" eval "0.1.6" find-up "^5.0.0" From 54d1964d6008fb134630aa19d4fd8c855c6d632d Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Fri, 10 Mar 2023 11:31:16 +1100 Subject: [PATCH 17/21] Translate root relative watchFile paths --- .../compiler/plugins/vanillaExtractPluginCached.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/remix-dev/compiler/plugins/vanillaExtractPluginCached.ts b/packages/remix-dev/compiler/plugins/vanillaExtractPluginCached.ts index 06113529ea1..068c44d860c 100644 --- a/packages/remix-dev/compiler/plugins/vanillaExtractPluginCached.ts +++ b/packages/remix-dev/compiler/plugins/vanillaExtractPluginCached.ts @@ -1,4 +1,4 @@ -import { dirname, join } from "path"; +import { dirname, resolve } from "path"; import type { Compiler } from "@vanilla-extract/integration"; import { cssFileFilter, createCompiler } from "@vanilla-extract/integration"; import type { Plugin } from "esbuild"; @@ -89,7 +89,7 @@ export function vanillaExtractPluginCached({ async ({ path }) => { let [relativeFilePath] = path.split(".vanilla.css"); let { css, filePath } = compiler.getCssForFile(relativeFilePath); - let resolveDir = dirname(join(root, filePath)); + let resolveDir = dirname(resolve(root, filePath)); if (postcssProcessor) { css = ( @@ -118,7 +118,11 @@ export function vanillaExtractPluginCached({ contents: source, resolveDir: dirname(filePath), loader: "js", - watchFiles: Array.from(watchFiles || []), + watchFiles: (Array.from(watchFiles) || []).map((watchFile) => + watchFile.startsWith("~") + ? resolve(root, watchFile.replace("~", ".")) + : watchFile + ), }; }); }, From 4c23416ae27a5fc3ea66526ae5c3188fdc65b16b Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Fri, 10 Mar 2023 15:55:42 +1100 Subject: [PATCH 18/21] Bump to stable Vanilla Extract versions --- package.json | 5 +---- packages/remix-dev/package.json | 2 +- yarn.lock | 18 +++++++++--------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 774fcbd1849..bfd33eadc26 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "@types/semver": "^7.3.4", "@types/ssri": "^7.1.0", "@types/use-sync-external-store": "^0.0.3", - "@vanilla-extract/css": "0.0.0-create-compiler-api-202329212823", + "@vanilla-extract/css": "^1.1.0", "abort-controller": "^3.0.0", "abortcontroller-polyfill": "^1.7.3", "aws-sdk": "^2.1055.0", @@ -136,9 +136,6 @@ "unist-util-remove": "^3.1.0", "unist-util-visit": "^4.1.1" }, - "resolutions": { - "@vanilla-extract/css": "0.0.0-create-compiler-api-202329212823" - }, "engines": { "node": ">=14" } diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json index f9f99250d3e..0a05b82cc4d 100644 --- a/packages/remix-dev/package.json +++ b/packages/remix-dev/package.json @@ -30,7 +30,7 @@ "@esbuild-plugins/node-modules-polyfill": "^0.1.4", "@npmcli/package-json": "^2.0.0", "@remix-run/server-runtime": "1.14.1", - "@vanilla-extract/integration": "0.0.0-create-compiler-api-202329212823", + "@vanilla-extract/integration": "^6.2.0", "arg": "^5.0.1", "cacache": "^15.0.5", "chalk": "^4.1.2", diff --git a/yarn.lock b/yarn.lock index e0f4fae6533..4df4be56129 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3499,10 +3499,10 @@ dependencies: "@babel/core" "^7.20.7" -"@vanilla-extract/css@0.0.0-create-compiler-api-202329212823", "@vanilla-extract/css@^0.0.0-create-compiler-api-202329212823": - version "0.0.0-create-compiler-api-202329212823" - resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-0.0.0-create-compiler-api-202329212823.tgz#8d7c3ef67b789d212ed8c7498154ab65363025a6" - integrity sha512-tUG3roPsKK6cC8r332wkXuupVIUmI1BOYzMKaQ6j0At4Apla9e0EDHU2f/E2AZAvj621bibXjHCHgk9pQLG+hQ== +"@vanilla-extract/css@^1.1.0", "@vanilla-extract/css@^1.10.0": + version "1.10.0" + resolved "https://registry.npmjs.org/@vanilla-extract/css/-/css-1.10.0.tgz#4ed13c89c5f4e452f306440415d4591bba8ac01b" + integrity sha512-s/EFfLDKbU1c2jnELNl+l14AufvIyryDh09ZZxRRqKjRKitiKvEjoiUy964pGKmfHngc9O0mkbzqrbhWaH+96Q== dependencies: "@emotion/hash" "^0.9.0" "@vanilla-extract/private" "^1.0.3" @@ -3516,15 +3516,15 @@ media-query-parser "^2.0.2" outdent "^0.8.0" -"@vanilla-extract/integration@0.0.0-create-compiler-api-202329212823": - version "0.0.0-create-compiler-api-202329212823" - resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-0.0.0-create-compiler-api-202329212823.tgz#c461cfe1a263fad040da5c0146f2d43d9cc0c187" - integrity sha512-NjWfVkED0IzSn+F8Hkud6rw4ISvgLQNR7BZwqYnEdGFyG5bdtCorOiBY161IDeQ+9lr9duHnJoU6Qf26cENXxQ== +"@vanilla-extract/integration@^6.2.0": + version "6.2.0" + resolved "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-6.2.0.tgz#b45927c5e9efb78a8c3c66ccc2aacdfb996a6b9e" + integrity sha512-sHF571lXE7tdk0Sx3kcbbopmpyiYfRIxhHET2vGjH0Mddch1NK93VztWyliaBdPltR++OuvYruzzYAt3Ob18VQ== dependencies: "@babel/core" "^7.20.7" "@babel/plugin-syntax-typescript" "^7.20.0" "@vanilla-extract/babel-plugin-debug-ids" "^1.0.2" - "@vanilla-extract/css" "^0.0.0-create-compiler-api-202329212823" + "@vanilla-extract/css" "^1.10.0" esbuild "0.17.6" eval "0.1.6" find-up "^5.0.0" From 29cdc634c9c35f1359c57f13388c23270cfa8bd4 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Fri, 10 Mar 2023 15:57:18 +1100 Subject: [PATCH 19/21] Update changeset --- .changeset/vanilla-extract-cache.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/vanilla-extract-cache.md b/.changeset/vanilla-extract-cache.md index cb8630c9123..4453697c320 100644 --- a/.changeset/vanilla-extract-cache.md +++ b/.changeset/vanilla-extract-cache.md @@ -2,4 +2,4 @@ "@remix-run/dev": minor --- -Add experimental support for Vanilla Extract caching which can be enabled by setting `future.unstable_vanillaExtract: { cache: true }` in `remix.config`. This is considered experimental because it's using a brand new Vanilla Extract compiler under the hood. +Add experimental support for Vanilla Extract caching which can be enabled by setting `future.unstable_vanillaExtract: { cache: true }` in `remix.config`. This is considered experimental due to the use of a brand new Vanilla Extract compiler under the hood. Note that in order to use this feature, you must be using at least `v1.10.0` of `@vanilla-extract/css`. From 7d5f1a8bb6c96edb7093ec47e2c69b3f89afdfe9 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Tue, 14 Mar 2023 10:25:23 +1100 Subject: [PATCH 20/21] Remove loop from deterministic build tests --- .../deterministic-build-output-test.ts | 344 ++++++++---------- 1 file changed, 160 insertions(+), 184 deletions(-) diff --git a/integration/deterministic-build-output-test.ts b/integration/deterministic-build-output-test.ts index d100853fa6e..5a1797ae6e1 100644 --- a/integration/deterministic-build-output-test.ts +++ b/integration/deterministic-build-output-test.ts @@ -6,201 +6,177 @@ import path from "path"; import type { FixtureInit } from "./helpers/create-fixture"; import { createFixtureProject, js, css } from "./helpers/create-fixture"; -const testCases: Array<{ name: string; init: FixtureInit }> = [ - { - name: "all future flags enabled", - init: { - future: { - unstable_cssModules: true, - unstable_cssSideEffectImports: true, - unstable_postcss: true, - unstable_vanillaExtract: true, - v2_routeConvention: true, - }, - files: { - "app/routes/_index.mdx": "# hello world", - "app/routes/foo.tsx": js` - export * from "~/foo/bar.server"; - import styles from "~/styles/foo.module.css"; - import { vanilla } from "~/styles/vanilla.css"; - import "~/styles/side-effect.css"; - export default () =>
YAY
; - `, - "app/foo/bar.server.ts": "export const meta = () => []", - "app/styles/foo.module.css": css` - .foo { - background-image: url(~/images/foo.svg); - composes: bar from "~/styles/bar.module.css"; - composes: baz from "./baz.module.css"; - } - `, - "app/styles/bar.module.css": css` - .bar { - background-color: peachpuff; - } - `, - "app/styles/baz.module.css": css` - .baz { - color: coral; - } - `, - "app/images/foo.svg": ` - - - - `, - "app/styles/vanilla.css.ts": css` - import { style } from "@vanilla-extract/css"; - import { chocolate } from "./chocolate.css"; - import imageUrl from "~/images/foo.svg"; +test("builds deterministically under different paths", async () => { + // This test validates various flavors of remix virtual modules to ensure + // we get identical builds regardless of the parent paths. If a virtual + // module resolves or imports from absolute paths (e.g. via `path.resolve`), + // the build hashes may change even though the output is identical. This + // can cause broken apps (i.e. manifest mismatch) if the server and client + // are built separately. - export const vanilla = style([ - chocolate, - { - backgroundImage: [ - "url(" + imageUrl + ")", - "url(~/images/foo.svg)", - ], - } - ]); - `, - "app/styles/chocolate.css.ts": css` - import { style } from "@vanilla-extract/css"; + // Virtual modules tested: + // * browserRouteModulesPlugin (implicitly tested by root route) + // * cssEntryModulePlugin (implicitly tested by build) + // * cssModulesPlugin (via app/routes/foo.tsx' CSS Modules import) + // * cssSideEffectImportsPlugin (via app/routes/foo.tsx' CSS side-effect import) + // * emptyModulesPlugin (via app/routes/foo.tsx' server import) + // * mdx (via app/routes/_index.mdx) + // * serverAssetsManifestPlugin (implicitly tested by build) + // * serverEntryModulePlugin (implicitly tested by build) + // * serverRouteModulesPlugin (implicitly tested by build) + // * vanillaExtractPlugin (via app/routes/foo.tsx' .css.ts file import) + let init: FixtureInit = { + future: { + unstable_cssModules: true, + unstable_cssSideEffectImports: true, + unstable_postcss: true, + unstable_vanillaExtract: true, + v2_routeConvention: true, + }, + files: { + "app/routes/_index.mdx": "# hello world", + "app/routes/foo.tsx": js` + export * from "~/foo/bar.server"; + import styles from "~/styles/foo.module.css"; + import { vanilla } from "~/styles/vanilla.css"; + import "~/styles/side-effect.css"; + export default () =>
YAY
; + `, + "app/foo/bar.server.ts": "export const meta = () => []", + "app/styles/foo.module.css": css` + .foo { + background-image: url(~/images/foo.svg); + composes: bar from "~/styles/bar.module.css"; + composes: baz from "./baz.module.css"; + } + `, + "app/styles/bar.module.css": css` + .bar { + background-color: peachpuff; + } + `, + "app/styles/baz.module.css": css` + .baz { + color: coral; + } + `, + "app/images/foo.svg": ` + + + + `, + "app/styles/vanilla.css.ts": css` + import { style } from "@vanilla-extract/css"; + import { chocolate } from "./chocolate.css"; + import imageUrl from "~/images/foo.svg"; - export const chocolate = style({ - color: "chocolate", - }); - `, - "app/styles/side-effect.css": css` - .side-effect { - color: mintcream; + export const vanilla = style([ + chocolate, + { + backgroundImage: [ + "url(" + imageUrl + ")", + "url(~/images/foo.svg)", + ], } - `, - }, + ]); + `, + "app/styles/chocolate.css.ts": css` + import { style } from "@vanilla-extract/css"; + + export const chocolate = style({ + color: "chocolate", + }); + `, + "app/styles/side-effect.css": css` + .side-effect { + color: mintcream; + } + `, }, - }, - { - name: "Vanilla Extract with cache enabled", - init: { - future: { - unstable_cssModules: true, - unstable_cssSideEffectImports: true, - unstable_postcss: true, - unstable_vanillaExtract: { cache: true }, - v2_routeConvention: true, - }, - files: { - "app/routes/_index.mdx": "# hello world", - "app/routes/foo.tsx": js` - export * from "~/foo/bar.server"; - import styles from "~/styles/foo.module.css"; - import { vanilla } from "~/styles/vanilla.css"; - import "~/styles/side-effect.css"; - export default () =>
YAY
; - `, - "app/foo/bar.server.ts": "export const meta = () => []", - "app/styles/foo.module.css": css` - .foo { - background-image: url(~/images/foo.svg); - composes: bar from "~/styles/bar.module.css"; - composes: baz from "./baz.module.css"; - } - `, - "app/styles/bar.module.css": css` - .bar { - background-color: peachpuff; - } - `, - "app/styles/baz.module.css": css` - .baz { - color: coral; - } - `, - "app/images/foo.svg": ` - - - - `, - "app/styles/vanilla.css.ts": css` - import { style } from "@vanilla-extract/css"; - import { chocolate } from "./chocolate.css"; - import imageUrl from "~/images/foo.svg"; + }; + let dir1 = await createFixtureProject(init); + let dir2 = await createFixtureProject(init); - export const vanilla = style([ - chocolate, - { - backgroundImage: [ - "url(" + imageUrl + ")", - "url(~/images/foo.svg)", - ], - } - ]); - `, - "app/styles/chocolate.css.ts": css` - import { style } from "@vanilla-extract/css"; + expect(dir1).not.toEqual(dir2); - export const chocolate = style({ - color: "chocolate", - }); - `, - "app/styles/side-effect.css": css` - .side-effect { - color: mintcream; - } - `, - }, + let files1 = await globby(["build/index.js", "public/build/**/*.{js,css}"], { + cwd: dir1, + }); + files1 = files1.sort(); + let files2 = await globby(["build/index.js", "public/build/**/*.{js,css}"], { + cwd: dir2, + }); + files2 = files2.sort(); + + expect(files1.length).toBeGreaterThan(0); + expect(files1).toEqual(files2); + files1.forEach((file, i) => { + expect(fs.readFileSync(path.join(dir1, file))).toEqual( + fs.readFileSync(path.join(dir2, files2[i])) + ); + }); +}); + +test("builds Vanilla Extract files deterministically under different paths with Vanilla Extract cache enabled", async () => { + let init: FixtureInit = { + future: { + unstable_vanillaExtract: { cache: true }, + v2_routeConvention: true, }, - }, -]; + files: { + "app/routes/foo.tsx": js` + export * from "~/foo/bar.server"; + import { vanilla } from "~/styles/vanilla.css"; + export default () =>
YAY
; + `, + "app/images/foo.svg": ` + + + + `, + "app/styles/vanilla.css.ts": css` + import { style } from "@vanilla-extract/css"; + import { chocolate } from "./chocolate.css"; + import imageUrl from "~/images/foo.svg"; -testCases.forEach((testCase) => { - test.describe(testCase.name, () => { - test("builds deterministically under different paths", async () => { - // This test validates various flavors of remix virtual modules to ensure - // we get identical builds regardless of the parent paths. If a virtual - // module resolves or imports from absolute paths (e.g. via `path.resolve`), - // the build hashes may change even though the output is identical. This - // can cause broken apps (i.e. manifest mismatch) if the server and client - // are built separately. + export const vanilla = style([ + chocolate, + { + backgroundImage: [ + "url(" + imageUrl + ")", + "url(~/images/foo.svg)", + ], + } + ]); + `, + "app/styles/chocolate.css.ts": css` + import { style } from "@vanilla-extract/css"; - // Virtual modules tested: - // * browserRouteModulesPlugin (implicitly tested by root route) - // * cssEntryModulePlugin (implicitly tested by build) - // * cssModulesPlugin (via app/routes/foo.tsx' CSS Modules import) - // * cssSideEffectImportsPlugin (via app/routes/foo.tsx' CSS side-effect import) - // * emptyModulesPlugin (via app/routes/foo.tsx' server import) - // * mdx (via app/routes/_index.mdx) - // * serverAssetsManifestPlugin (implicitly tested by build) - // * serverEntryModulePlugin (implicitly tested by build) - // * serverRouteModulesPlugin (implicitly tested by build) - // * vanillaExtractPlugin (via app/routes/foo.tsx' .css.ts file import) - let dir1 = await createFixtureProject(testCase.init); - let dir2 = await createFixtureProject(testCase.init); + export const chocolate = style({ + color: "chocolate", + }); + `, + }, + }; + let dir1 = await createFixtureProject(init); + let dir2 = await createFixtureProject(init); - expect(dir1).not.toEqual(dir2); + expect(dir1).not.toEqual(dir2); - let files1 = await globby( - ["build/index.js", "public/build/**/*.{js,css}"], - { - cwd: dir1, - } - ); - files1 = files1.sort(); - let files2 = await globby( - ["build/index.js", "public/build/**/*.{js,css}"], - { - cwd: dir2, - } - ); - files2 = files2.sort(); + let files1 = await globby(["build/index.js", "public/build/**/*.{js,css}"], { + cwd: dir1, + }); + files1 = files1.sort(); + let files2 = await globby(["build/index.js", "public/build/**/*.{js,css}"], { + cwd: dir2, + }); + files2 = files2.sort(); - expect(files1.length).toBeGreaterThan(0); - expect(files1).toEqual(files2); - files1.forEach((file, i) => { - expect(fs.readFileSync(path.join(dir1, file))).toEqual( - fs.readFileSync(path.join(dir2, files2[i])) - ); - }); - }); + expect(files1.length).toBeGreaterThan(0); + expect(files1).toEqual(files2); + files1.forEach((file, i) => { + expect(fs.readFileSync(path.join(dir1, file))).toEqual( + fs.readFileSync(path.join(dir2, files2[i])) + ); }); }); From 53a7a106333a49376b056d73b678da8b6cd44a1f Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Tue, 14 Mar 2023 11:00:46 +1100 Subject: [PATCH 21/21] Fix tests --- integration/deterministic-build-output-test.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/integration/deterministic-build-output-test.ts b/integration/deterministic-build-output-test.ts index 5a1797ae6e1..451f63b89cc 100644 --- a/integration/deterministic-build-output-test.ts +++ b/integration/deterministic-build-output-test.ts @@ -65,7 +65,7 @@ test("builds deterministically under different paths", async () => { `, - "app/styles/vanilla.css.ts": css` + "app/styles/vanilla.css.ts": js` import { style } from "@vanilla-extract/css"; import { chocolate } from "./chocolate.css"; import imageUrl from "~/images/foo.svg"; @@ -80,7 +80,7 @@ test("builds deterministically under different paths", async () => { } ]); `, - "app/styles/chocolate.css.ts": css` + "app/styles/chocolate.css.ts": js` import { style } from "@vanilla-extract/css"; export const chocolate = style({ @@ -125,7 +125,6 @@ test("builds Vanilla Extract files deterministically under different paths with }, files: { "app/routes/foo.tsx": js` - export * from "~/foo/bar.server"; import { vanilla } from "~/styles/vanilla.css"; export default () =>
YAY
; `, @@ -134,7 +133,7 @@ test("builds Vanilla Extract files deterministically under different paths with `, - "app/styles/vanilla.css.ts": css` + "app/styles/vanilla.css.ts": js` import { style } from "@vanilla-extract/css"; import { chocolate } from "./chocolate.css"; import imageUrl from "~/images/foo.svg"; @@ -149,7 +148,7 @@ test("builds Vanilla Extract files deterministically under different paths with } ]); `, - "app/styles/chocolate.css.ts": css` + "app/styles/chocolate.css.ts": js` import { style } from "@vanilla-extract/css"; export const chocolate = style({