|
78 | 78 | // generated entries and client assets carry no reference to the |
79 | 79 | // server-components runtime when the option is off. |
80 | 80 | // |
| 81 | +// - `start.css.filter` (css-filter mode, CSS_FILTER=<shape> in |
| 82 | +// vite.config.ts): the dev CSS crawl's include/exclude semantics against |
| 83 | +// a temp node_modules package written by the test — `exclude` prunes an |
| 84 | +// app graph (replacing the default node_modules exclusion), `include` |
| 85 | +// opts the package's graph in on top of the default baseline with app |
| 86 | +// CSS surviving (the PR #316 use case), a file matching both patterns |
| 87 | +// stays excluded, and the filterless default prunes node_modules, |
81 | 88 | // - the response-head lifecycle in dev, prod, and preview (App.tsx's |
82 | 89 | // path-keyed surfaces): httpStatus(404)/httpHeader reach the wire, a |
83 | 90 | // pre-flush Location is a real 3xx with no body, a post-flush Location |
|
105 | 112 | // |
106 | 113 | // Requires the plugin built (pnpm build at the repo root) and Google Chrome. |
107 | 114 | // Usage: node test/run.mjs |
108 | | -// [dev|prod|document|entries|endpoint|configure|no-middleware|middleware|preview|base|builder-order|builder-prepare|babel-hmr|frames] |
| 115 | +// [dev|prod|document|css-filter|entries|endpoint|configure|no-middleware|middleware|preview|base|builder-order|builder-prepare|babel-hmr|frames] |
109 | 116 | // (default: all) |
110 | 117 |
|
111 | 118 | import { spawn, execSync } from 'node:child_process'; |
112 | 119 | import { fileURLToPath, pathToFileURL } from 'node:url'; |
113 | 120 | import path from 'node:path'; |
114 | | -import { rmSync, existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; |
| 121 | +import { mkdirSync, rmSync, existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; |
115 | 122 | import http from 'node:http'; |
116 | 123 | import { |
117 | 124 | createServer, |
@@ -1127,30 +1134,131 @@ async function runDocumentMode() { |
1127 | 1134 | } |
1128 | 1135 | } |
1129 | 1136 |
|
| 1137 | +// Distinctive rule from the temp test-css-lib package's stylesheet: proves a |
| 1138 | +// node_modules graph's CSS was opted into the dev SSR crawl by |
| 1139 | +// `start.css.filter.include`. Keep in sync with CSS_LIB_FIXTURES below. |
| 1140 | +const LIB_CSS_COLOR = 'rgb(7, 140, 210)'; |
| 1141 | + |
| 1142 | +// Temp fixtures for the css-filter mode (written before the sub-runs, |
| 1143 | +// removed after): a real — not symlinked — node_modules package whose JS |
| 1144 | +// imports its own CSS (the JS module is what the filter sees; CSS files |
| 1145 | +// themselves bypass it), plus an app wrapper that pulls the package into |
| 1146 | +// the entry graph. Real directory matters: Vite resolves symlinks, and a |
| 1147 | +// `file:` dependency would resolve outside node_modules, dodging the |
| 1148 | +// default exclusion under test. |
| 1149 | +const CSS_LIB_FIXTURES = { |
| 1150 | + 'node_modules/test-css-lib/package.json': JSON.stringify( |
| 1151 | + { name: 'test-css-lib', version: '0.0.0', type: 'module', main: 'index.js' }, |
| 1152 | + null, |
| 1153 | + 2, |
| 1154 | + ), |
| 1155 | + 'node_modules/test-css-lib/index.js': `import './styles.css';\nexport const cssLibReady = true;\n`, |
| 1156 | + 'node_modules/test-css-lib/styles.css': `#lib-probe {\n color: ${LIB_CSS_COLOR};\n}\n`, |
| 1157 | + 'src/CssLibApp.tsx': `import 'test-css-lib'; |
| 1158 | +import App from './App'; |
| 1159 | +
|
| 1160 | +export default function CssLibApp() { |
| 1161 | + return <App />; |
| 1162 | +} |
| 1163 | +`, |
| 1164 | +}; |
| 1165 | + |
1130 | 1166 | async function runCssFilterMode() { |
1131 | 1167 | const mode = 'css-filter'; |
1132 | 1168 | console.log(`\n=== ${mode.toUpperCase()} ===`); |
1133 | | - const port = 3172; |
1134 | | - const origin = `http://localhost:${port}`; |
1135 | | - const server = startProcess('pnpm', ['exec', 'vite', '--port', String(port), '--strictPort'], { |
1136 | | - cwd: exampleDir, |
1137 | | - env: { ...process.env, CSS_FILTER: '1' }, |
1138 | | - }); |
1139 | | - let serverLog = ''; |
1140 | | - server.stdout.on('data', (d) => (serverLog += d)); |
1141 | | - server.stderr.on('data', (d) => (serverLog += d)); |
| 1169 | + |
| 1170 | + for (const [file, source] of Object.entries(CSS_LIB_FIXTURES)) { |
| 1171 | + mkdirSync(path.dirname(path.join(exampleDir, file)), { recursive: true }); |
| 1172 | + writeFileSync(path.join(exampleDir, file), source); |
| 1173 | + } |
| 1174 | + |
| 1175 | + // One dev server per filter shape (the option is config-time); each |
| 1176 | + // sub-run asserts on the streamed dev SSR HTML only. |
| 1177 | + const subRuns = [ |
| 1178 | + { |
| 1179 | + filter: 'exclude', |
| 1180 | + port: 3172, |
| 1181 | + checks: (html) => { |
| 1182 | + record(mode, 'exclude', 'excluded module graph is not crawled for CSS', !html.includes(APP_CSS_COLOR)); |
| 1183 | + record(mode, 'exclude', 'filter does not prevent app rendering', html.includes('SSR Start Mode')); |
| 1184 | + }, |
| 1185 | + }, |
| 1186 | + { |
| 1187 | + filter: 'include', |
| 1188 | + port: 3173, |
| 1189 | + checks: (html) => { |
| 1190 | + record( |
| 1191 | + mode, |
| 1192 | + 'include', |
| 1193 | + 'included node_modules graph is crawled for CSS', |
| 1194 | + html.includes(LIB_CSS_COLOR), |
| 1195 | + ); |
| 1196 | + record( |
| 1197 | + mode, |
| 1198 | + 'include', |
| 1199 | + 'include-only filter keeps collecting app CSS', |
| 1200 | + html.includes(APP_CSS_COLOR), |
| 1201 | + ); |
| 1202 | + record(mode, 'include', 'filter does not prevent app rendering', html.includes('SSR Start Mode')); |
| 1203 | + }, |
| 1204 | + }, |
| 1205 | + { |
| 1206 | + filter: 'conflict', |
| 1207 | + port: 3174, |
| 1208 | + checks: (html) => { |
| 1209 | + record( |
| 1210 | + mode, |
| 1211 | + 'conflict', |
| 1212 | + 'file matching include and exclude stays excluded', |
| 1213 | + !html.includes(APP_CSS_COLOR), |
| 1214 | + ); |
| 1215 | + record(mode, 'conflict', 'filter does not prevent app rendering', html.includes('SSR Start Mode')); |
| 1216 | + }, |
| 1217 | + }, |
| 1218 | + { |
| 1219 | + filter: 'default', |
| 1220 | + port: 3175, |
| 1221 | + checks: (html) => { |
| 1222 | + record( |
| 1223 | + mode, |
| 1224 | + 'default', |
| 1225 | + 'node_modules graph is pruned without a filter', |
| 1226 | + !html.includes(LIB_CSS_COLOR), |
| 1227 | + ); |
| 1228 | + record(mode, 'default', 'app CSS is collected without a filter', html.includes(APP_CSS_COLOR)); |
| 1229 | + }, |
| 1230 | + }, |
| 1231 | + ]; |
1142 | 1232 |
|
1143 | 1233 | try { |
1144 | | - await waitForHttp(origin + '/src/api.ts', 30000); |
1145 | | - const { html } = await fetchStreamed(origin + '/'); |
1146 | | - record(mode, 'css', 'excluded module graph is not crawled for CSS', !html.includes(APP_CSS_COLOR)); |
1147 | | - record(mode, 'ssr', 'filter does not prevent app rendering', html.includes('SSR Start Mode')); |
1148 | | - } catch (error) { |
1149 | | - record(mode, 'run', 'mode completed', false, String(error) + serverLog.slice(-2000)); |
| 1234 | + for (const { filter, port, checks } of subRuns) { |
| 1235 | + const origin = `http://localhost:${port}`; |
| 1236 | + const server = startProcess( |
| 1237 | + 'pnpm', |
| 1238 | + ['exec', 'vite', '--port', String(port), '--strictPort'], |
| 1239 | + { |
| 1240 | + cwd: exampleDir, |
| 1241 | + env: { ...process.env, CSS_FILTER: filter }, |
| 1242 | + }, |
| 1243 | + ); |
| 1244 | + let serverLog = ''; |
| 1245 | + server.stdout.on('data', (d) => (serverLog += d)); |
| 1246 | + server.stderr.on('data', (d) => (serverLog += d)); |
| 1247 | + try { |
| 1248 | + await waitForHttp(origin + '/src/api.ts', 30000); |
| 1249 | + const { html } = await fetchStreamed(origin + '/'); |
| 1250 | + checks(html); |
| 1251 | + } catch (error) { |
| 1252 | + record(mode, filter, 'sub-run completed', false, String(error) + serverLog.slice(-2000)); |
| 1253 | + } finally { |
| 1254 | + try { |
| 1255 | + process.kill(-server.pid, 'SIGTERM'); |
| 1256 | + } catch {} |
| 1257 | + } |
| 1258 | + } |
1150 | 1259 | } finally { |
1151 | | - try { |
1152 | | - process.kill(-server.pid, 'SIGTERM'); |
1153 | | - } catch {} |
| 1260 | + rmSync(path.join(exampleDir, 'node_modules/test-css-lib'), { recursive: true, force: true }); |
| 1261 | + rmSync(path.join(exampleDir, 'src/CssLibApp.tsx'), { force: true }); |
1154 | 1262 | } |
1155 | 1263 | } |
1156 | 1264 |
|
|
0 commit comments