diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 289972ab3ec60d..76faba2173450c 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -2183,6 +2183,10 @@ async function compileLightningCSS( if (filePath === filename) { return src } + // This happens with html-proxy (#13776) + if (!filePath.endsWith('.css')) { + return src + } return fs.readFileSync(toAbsolute(filePath), 'utf-8') }, async resolve(id, from) { diff --git a/playground/css-lightningcss-proxy/__tests__/css-lightningcss-proxy.spec.ts b/playground/css-lightningcss-proxy/__tests__/css-lightningcss-proxy.spec.ts new file mode 100644 index 00000000000000..c42f09e8bbad9e --- /dev/null +++ b/playground/css-lightningcss-proxy/__tests__/css-lightningcss-proxy.spec.ts @@ -0,0 +1,13 @@ +import { describe, expect, test } from 'vitest' +import { port } from './serve' +import { getColor, page } from '~utils' + +const url = `http://localhost:${port}` + +describe('injected inline style', () => { + test('injected inline style is present', async () => { + await page.goto(url) + const el = await page.$('.ssr-proxy') + expect(await getColor(el)).toBe('coral') + }) +}) diff --git a/playground/css-lightningcss-proxy/__tests__/serve.ts b/playground/css-lightningcss-proxy/__tests__/serve.ts new file mode 100644 index 00000000000000..ee933ecd507a8c --- /dev/null +++ b/playground/css-lightningcss-proxy/__tests__/serve.ts @@ -0,0 +1,38 @@ +// this is automatically detected by playground/vitestSetup.ts and will replace +// the default e2e test serve behavior + +import path from 'node:path' +import kill from 'kill-port' +import { hmrPorts, ports, rootDir } from '~utils' + +export const port = ports['css/lightningcss-proxy'] + +export async function serve(): Promise<{ close(): Promise }> { + await kill(port) + + const { createServer } = await import(path.resolve(rootDir, 'server.js')) + const { app, vite } = await createServer( + rootDir, + hmrPorts['css/lightningcss-proxy'], + ) + + return new Promise((resolve, reject) => { + try { + const server = app.listen(port, () => { + resolve({ + // for test teardown + async close() { + await new Promise((resolve) => { + server.close(resolve) + }) + if (vite) { + await vite.close() + } + }, + }) + }) + } catch (e) { + reject(e) + } + }) +} diff --git a/playground/css-lightningcss-proxy/index.html b/playground/css-lightningcss-proxy/index.html new file mode 100644 index 00000000000000..a017cc0d01b93c --- /dev/null +++ b/playground/css-lightningcss-proxy/index.html @@ -0,0 +1,5 @@ + +
+

Injected inline style with SSR Proxy

+

This should be coral

+
diff --git a/playground/css-lightningcss-proxy/package.json b/playground/css-lightningcss-proxy/package.json new file mode 100644 index 00000000000000..c0eb81eccb5e83 --- /dev/null +++ b/playground/css-lightningcss-proxy/package.json @@ -0,0 +1,15 @@ +{ + "name": "@vitejs/test-css-lightningcss-proxy", + "private": true, + "type": "module", + "scripts": { + "dev": "node server", + "serve": "NODE_ENV=production node server", + "debug": "node --inspect-brk server", + "preview": "vite preview" + }, + "devDependencies": { + "lightningcss": "^1.21.5", + "express": "^4.18.2" + } +} diff --git a/playground/css-lightningcss-proxy/server.js b/playground/css-lightningcss-proxy/server.js new file mode 100644 index 00000000000000..a131dfe74e3b23 --- /dev/null +++ b/playground/css-lightningcss-proxy/server.js @@ -0,0 +1,89 @@ +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import express from 'express' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const isTest = process.env.VITEST + +const DYNAMIC_STYLES = ` + +` + +export async function createServer(root = process.cwd(), hmrPort) { + const resolve = (p) => path.resolve(__dirname, p) + + const app = express() + + /** + * @type {import('vite').ViteDevServer} + */ + const vite = await ( + await import('vite') + ).createServer({ + root, + logLevel: isTest ? 'error' : 'info', + css: { + transformer: 'lightningcss', + lightningcss: { + drafts: { nesting: true }, + }, + }, + server: { + middlewareMode: true, + watch: { + // During tests we edit the files too fast and sometimes chokidar + // misses change events, so enforce polling for consistency + usePolling: true, + interval: 100, + }, + hmr: { + port: hmrPort, + }, + }, + appType: 'custom', + }) + // use vite's connect instance as middleware + app.use(vite.middlewares) + + app.use('*', async (req, res, next) => { + try { + let [url] = req.originalUrl.split('?') + if (url.endsWith('/')) url += 'index.html' + + if (url.startsWith('/favicon.ico')) { + return res.status(404).end('404') + } + + const htmlLoc = resolve(`.${url}`) + let template = fs.readFileSync(htmlLoc, 'utf-8') + + template = template.replace('', DYNAMIC_STYLES) + + // Force calling transformIndexHtml with url === '/', to simulate + // usage by ecosystem that was recommended in the SSR documentation + // as `const url = req.originalUrl` + const html = await vite.transformIndexHtml('/', template) + + res.status(200).set({ 'Content-Type': 'text/html' }).end(html) + } catch (e) { + vite && vite.ssrFixStacktrace(e) + console.log(e.stack) + res.status(500).end(e.stack) + } + }) + + return { app, vite } +} + +if (!isTest) { + createServer().then(({ app }) => + app.listen(5173, () => { + console.log('http://localhost:5173') + }), + ) +} diff --git a/playground/test-utils.ts b/playground/test-utils.ts index f780024547b180..df68dce9c5e66f 100644 --- a/playground/test-utils.ts +++ b/playground/test-utils.ts @@ -35,6 +35,7 @@ export const ports = { 'css/postcss-caching': 5005, 'css/postcss-plugins-different-dir': 5006, 'css/dynamic-import': 5007, + 'css/lightningcss-proxy': 5008, } export const hmrPorts = { 'optimize-missing-deps': 24680, @@ -43,6 +44,7 @@ export const hmrPorts = { 'ssr-html': 24683, 'ssr-noexternal': 24684, 'ssr-pug': 24685, + 'css/lightningcss-proxy': 24686, } const hexToNameMap: Record = {} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ab2d78d7ace4c5..8567da79f5124b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -545,6 +545,15 @@ importers: specifier: ^1.21.5 version: 1.21.5 + playground/css-lightningcss-proxy: + devDependencies: + express: + specifier: ^4.18.2 + version: 4.18.2 + lightningcss: + specifier: ^1.21.5 + version: 1.21.5 + playground/css-sourcemap: devDependencies: less: @@ -4465,7 +4474,7 @@ packages: dev: true /array-flatten@1.1.1: - resolution: {integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=} + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} /array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} @@ -5191,7 +5200,7 @@ packages: dev: true /cookie-signature@1.0.6: - resolution: {integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw=} + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} /cookie@0.4.2: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} @@ -5484,7 +5493,7 @@ packages: dev: true /ee-first@1.1.1: - resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=} + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} /electron-to-chromium@1.4.433: resolution: {integrity: sha512-MGO1k0w1RgrfdbLVwmXcDhHHuxCn2qRgR7dYsJvWFKDttvYPx6FNzCGG0c/fBBvzK2LDh3UV7Tt9awnHnvAAUQ==} @@ -6412,7 +6421,7 @@ packages: dev: false /fresh@0.5.2: - resolution: {integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=} + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} /fs-extra@11.1.1: @@ -7672,7 +7681,7 @@ packages: dev: true /media-typer@0.3.0: - resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=} + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} /memorystream@0.3.1: @@ -7698,7 +7707,7 @@ packages: dev: true /merge-descriptors@1.0.1: - resolution: {integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=} + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -8372,7 +8381,7 @@ packages: dev: true /path-to-regexp@0.1.7: - resolution: {integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=} + resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} /path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} @@ -10144,7 +10153,7 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} /utils-merge@1.0.1: - resolution: {integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=} + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} /uuid@3.4.0: