@valbuild/cli 0.138.0 → 0.138.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @valbuild/cli
2
2
 
3
+ ## 0.138.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#758](https://github.com/valbuild/val/pull/758) [`af57406`](https://github.com/valbuild/val/commit/af57406fb679f5917559a8c97507b7c42f2b48fe) Thanks [@freekh](https://github.com/freekh)! - `val publish` no longer stores a project's stylesheets as its source. It still compiles them, so the site's CSS is unchanged, but the source a managed project's Studio builds from comes without them — as the platform's own publish has always stored it.
8
+
9
+ A stored stylesheet broke every Studio publish that followed: a browser build cannot run a Tailwind `@plugin` (the starter's `src/styles.css` has `@plugin "@tailwindcss/typography"`), so it refused the stylesheet and the publish failed with "build failed 3 times". Without one, the Studio ships the live site's CSS, which is right — a Studio edit never changes a stylesheet.
10
+
11
+ - Updated dependencies []:
12
+ - @valbuild/server@0.138.1
13
+ - @valbuild/language-server@0.138.1
14
+
3
15
  ## 0.138.0
4
16
 
5
17
  ### Minor Changes
@@ -2351,6 +2351,25 @@ const CODE_FILE = /\.(tsx?|jsx?|mjs|cjs|css)$/;
2351
2351
  */
2352
2352
  const JSON_FILE = /\.json$/;
2353
2353
 
2354
+ /**
2355
+ * The project's source as it is STORED, which is what the Studio builds from:
2356
+ * every file this build read, less the stylesheets.
2357
+ *
2358
+ * This build compiles them, because it can run what a stylesheet asks for -- a
2359
+ * Tailwind `@plugin` is a module resolved and executed from `node_modules`. A
2360
+ * build in the browser cannot, and refuses the stylesheet rather than ship a
2361
+ * page that is quietly unstyled; the starter's `src/styles.css` has
2362
+ * `@plugin "@tailwindcss/typography"`. So a stored stylesheet made every
2363
+ * Studio publish after the first one fail. Without it, the Studio's build has
2364
+ * no CSS of its own and ships the live site's (`liveStylesheet` in the
2365
+ * Studio), which is right: a Studio save changes content and uploaded files,
2366
+ * never a stylesheet. It is also what the platform's own publish has always
2367
+ * stored.
2368
+ */
2369
+ function withoutStylesheets(sources) {
2370
+ return Object.fromEntries(Object.entries(sources).filter(([key]) => !key.endsWith(".css")));
2371
+ }
2372
+
2354
2373
  /**
2355
2374
  * The project's own files: its source as text, and the binaries it imports
2356
2375
  * (an image, a font) base64, as `BuildInput.assets` takes them. `public/` is
@@ -2487,6 +2506,7 @@ async function buildArtifacts(options) {
2487
2506
  // Less the one about the layer, which is the thing this goes on to build.
2488
2507
  warnings.push(...((wiring === null || wiring === void 0 ? void 0 : wiring.warnings) ?? []).filter(warning => !warning.includes("dependency layer built for it")));
2489
2508
  const sources = (wiring === null || wiring === void 0 ? void 0 : wiring.files) ?? onDisk;
2509
+ const projectSource = withoutStylesheets(sources);
2490
2510
 
2491
2511
  // The dependency layer: from what the project imports, of what it declares.
2492
2512
  log("Building the dependency layer");
@@ -2526,9 +2546,10 @@ async function buildArtifacts(options) {
2526
2546
  env: publicEnv(options.env ?? process.env),
2527
2547
  publicFiles: readPublicFiles(root),
2528
2548
  assets,
2529
- // The project's own files, without the generated tree: what the next
2530
- // publish -- the Studio's included -- starts from.
2531
- projectSource: sources,
2549
+ // The project's own files, without the generated tree or the
2550
+ // stylesheets: what the next publish -- the Studio's included -- starts
2551
+ // from. See `withoutStylesheets`.
2552
+ projectSource,
2532
2553
  loadCssModule: node.cssModuleLoader(root),
2533
2554
  ...(splitter ? {
2534
2555
  routeSplitter: splitter
@@ -2536,7 +2557,7 @@ async function buildArtifacts(options) {
2536
2557
  rsc: target.project.rsc
2537
2558
  });
2538
2559
  const artifacts = await builder.publishArtifacts(built, {
2539
- projectSource: sources
2560
+ projectSource
2540
2561
  });
2541
2562
  const dir = options.outDir ?? fs__default$1["default"].mkdtempSync(path__default["default"].join(os__default["default"].tmpdir(), "val-publish-"));
2542
2563
  for (const artifact of artifacts) {
@@ -2351,6 +2351,25 @@ const CODE_FILE = /\.(tsx?|jsx?|mjs|cjs|css)$/;
2351
2351
  */
2352
2352
  const JSON_FILE = /\.json$/;
2353
2353
 
2354
+ /**
2355
+ * The project's source as it is STORED, which is what the Studio builds from:
2356
+ * every file this build read, less the stylesheets.
2357
+ *
2358
+ * This build compiles them, because it can run what a stylesheet asks for -- a
2359
+ * Tailwind `@plugin` is a module resolved and executed from `node_modules`. A
2360
+ * build in the browser cannot, and refuses the stylesheet rather than ship a
2361
+ * page that is quietly unstyled; the starter's `src/styles.css` has
2362
+ * `@plugin "@tailwindcss/typography"`. So a stored stylesheet made every
2363
+ * Studio publish after the first one fail. Without it, the Studio's build has
2364
+ * no CSS of its own and ships the live site's (`liveStylesheet` in the
2365
+ * Studio), which is right: a Studio save changes content and uploaded files,
2366
+ * never a stylesheet. It is also what the platform's own publish has always
2367
+ * stored.
2368
+ */
2369
+ function withoutStylesheets(sources) {
2370
+ return Object.fromEntries(Object.entries(sources).filter(([key]) => !key.endsWith(".css")));
2371
+ }
2372
+
2354
2373
  /**
2355
2374
  * The project's own files: its source as text, and the binaries it imports
2356
2375
  * (an image, a font) base64, as `BuildInput.assets` takes them. `public/` is
@@ -2487,6 +2506,7 @@ async function buildArtifacts(options) {
2487
2506
  // Less the one about the layer, which is the thing this goes on to build.
2488
2507
  warnings.push(...((wiring === null || wiring === void 0 ? void 0 : wiring.warnings) ?? []).filter(warning => !warning.includes("dependency layer built for it")));
2489
2508
  const sources = (wiring === null || wiring === void 0 ? void 0 : wiring.files) ?? onDisk;
2509
+ const projectSource = withoutStylesheets(sources);
2490
2510
 
2491
2511
  // The dependency layer: from what the project imports, of what it declares.
2492
2512
  log("Building the dependency layer");
@@ -2526,9 +2546,10 @@ async function buildArtifacts(options) {
2526
2546
  env: publicEnv(options.env ?? process.env),
2527
2547
  publicFiles: readPublicFiles(root),
2528
2548
  assets,
2529
- // The project's own files, without the generated tree: what the next
2530
- // publish -- the Studio's included -- starts from.
2531
- projectSource: sources,
2549
+ // The project's own files, without the generated tree or the
2550
+ // stylesheets: what the next publish -- the Studio's included -- starts
2551
+ // from. See `withoutStylesheets`.
2552
+ projectSource,
2532
2553
  loadCssModule: node.cssModuleLoader(root),
2533
2554
  ...(splitter ? {
2534
2555
  routeSplitter: splitter
@@ -2536,7 +2557,7 @@ async function buildArtifacts(options) {
2536
2557
  rsc: target.project.rsc
2537
2558
  });
2538
2559
  const artifacts = await builder.publishArtifacts(built, {
2539
- projectSource: sources
2560
+ projectSource
2540
2561
  });
2541
2562
  const dir = options.outDir ?? fs__default$1["default"].mkdtempSync(path__default["default"].join(os__default["default"].tmpdir(), "val-publish-"));
2542
2563
  for (const artifact of artifacts) {
@@ -2316,6 +2316,25 @@ const CODE_FILE = /\.(tsx?|jsx?|mjs|cjs|css)$/;
2316
2316
  */
2317
2317
  const JSON_FILE = /\.json$/;
2318
2318
 
2319
+ /**
2320
+ * The project's source as it is STORED, which is what the Studio builds from:
2321
+ * every file this build read, less the stylesheets.
2322
+ *
2323
+ * This build compiles them, because it can run what a stylesheet asks for -- a
2324
+ * Tailwind `@plugin` is a module resolved and executed from `node_modules`. A
2325
+ * build in the browser cannot, and refuses the stylesheet rather than ship a
2326
+ * page that is quietly unstyled; the starter's `src/styles.css` has
2327
+ * `@plugin "@tailwindcss/typography"`. So a stored stylesheet made every
2328
+ * Studio publish after the first one fail. Without it, the Studio's build has
2329
+ * no CSS of its own and ships the live site's (`liveStylesheet` in the
2330
+ * Studio), which is right: a Studio save changes content and uploaded files,
2331
+ * never a stylesheet. It is also what the platform's own publish has always
2332
+ * stored.
2333
+ */
2334
+ function withoutStylesheets(sources) {
2335
+ return Object.fromEntries(Object.entries(sources).filter(([key]) => !key.endsWith(".css")));
2336
+ }
2337
+
2319
2338
  /**
2320
2339
  * The project's own files: its source as text, and the binaries it imports
2321
2340
  * (an image, a font) base64, as `BuildInput.assets` takes them. `public/` is
@@ -2452,6 +2471,7 @@ async function buildArtifacts(options) {
2452
2471
  // Less the one about the layer, which is the thing this goes on to build.
2453
2472
  warnings.push(...((wiring === null || wiring === void 0 ? void 0 : wiring.warnings) ?? []).filter(warning => !warning.includes("dependency layer built for it")));
2454
2473
  const sources = (wiring === null || wiring === void 0 ? void 0 : wiring.files) ?? onDisk;
2474
+ const projectSource = withoutStylesheets(sources);
2455
2475
 
2456
2476
  // The dependency layer: from what the project imports, of what it declares.
2457
2477
  log("Building the dependency layer");
@@ -2491,9 +2511,10 @@ async function buildArtifacts(options) {
2491
2511
  env: publicEnv(options.env ?? process.env),
2492
2512
  publicFiles: readPublicFiles(root),
2493
2513
  assets,
2494
- // The project's own files, without the generated tree: what the next
2495
- // publish -- the Studio's included -- starts from.
2496
- projectSource: sources,
2514
+ // The project's own files, without the generated tree or the
2515
+ // stylesheets: what the next publish -- the Studio's included -- starts
2516
+ // from. See `withoutStylesheets`.
2517
+ projectSource,
2497
2518
  loadCssModule: node.cssModuleLoader(root),
2498
2519
  ...(splitter ? {
2499
2520
  routeSplitter: splitter
@@ -2501,7 +2522,7 @@ async function buildArtifacts(options) {
2501
2522
  rsc: target.project.rsc
2502
2523
  });
2503
2524
  const artifacts = await builder.publishArtifacts(built, {
2504
- projectSource: sources
2525
+ projectSource
2505
2526
  });
2506
2527
  const dir = options.outDir ?? fs$1.mkdtempSync(path.join(os.tmpdir(), "val-publish-"));
2507
2528
  for (const artifact of artifacts) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@valbuild/cli",
3
3
  "private": false,
4
- "version": "0.138.0",
4
+ "version": "0.138.1",
5
5
  "description": "Val CLI tools",
6
6
  "repository": {
7
7
  "type": "git",
@@ -28,8 +28,8 @@
28
28
  "zod-validation-error": "^5.0.0",
29
29
  "@valbuild/core": "0.138.0",
30
30
  "@valbuild/eslint-plugin": "0.125.0",
31
- "@valbuild/language-server": "0.138.0",
32
- "@valbuild/server": "0.138.0",
31
+ "@valbuild/language-server": "0.138.1",
32
+ "@valbuild/server": "0.138.1",
33
33
  "@valbuild/shared": "0.138.0"
34
34
  },
35
35
  "peerDependencies": {
@@ -86,6 +86,10 @@ type Report = {
86
86
  uploadedLayerRev: string | null;
87
87
  /** Whether the source artifact holds the project's own route file. */
88
88
  sourceHasRoute: boolean;
89
+ /** Whether the source artifact holds a stylesheet -- it must not. */
90
+ sourceHasStylesheet: boolean;
91
+ /** Whether the stylesheet was compiled into the site's CSS all the same. */
92
+ cssHasRule: boolean;
89
93
  /** Whether the client build carries the page's text. */
90
94
  clientHasPage: boolean;
91
95
  /** Whether the imported image reached the build, inlined. */
@@ -183,6 +187,14 @@ async function publishOnce(
183
187
  ? "src/routes/index.tsx" in
184
188
  (JSON.parse(source.toString("utf8")) as Record<string, string>)
185
189
  : false,
190
+ sourceHasStylesheet: source
191
+ ? Object.keys(
192
+ JSON.parse(source.toString("utf8")) as Record<string, string>,
193
+ ).some((key) => key.endsWith(".css"))
194
+ : false,
195
+ cssHasRule: (fake.stored.get("css")?.toString("utf8") ?? "").includes(
196
+ "rebeccapurple",
197
+ ),
186
198
  clientHasPage: clientText.includes("hello from the checkout"),
187
199
  clientHasLogo: clientText.includes(
188
200
  `data:image/png;base64,${LOGO.toString("base64")}`,
@@ -97,6 +97,29 @@ const CODE_FILE = /\.(tsx?|jsx?|mjs|cjs|css)$/;
97
97
  */
98
98
  const JSON_FILE = /\.json$/;
99
99
 
100
+ /**
101
+ * The project's source as it is STORED, which is what the Studio builds from:
102
+ * every file this build read, less the stylesheets.
103
+ *
104
+ * This build compiles them, because it can run what a stylesheet asks for -- a
105
+ * Tailwind `@plugin` is a module resolved and executed from `node_modules`. A
106
+ * build in the browser cannot, and refuses the stylesheet rather than ship a
107
+ * page that is quietly unstyled; the starter's `src/styles.css` has
108
+ * `@plugin "@tailwindcss/typography"`. So a stored stylesheet made every
109
+ * Studio publish after the first one fail. Without it, the Studio's build has
110
+ * no CSS of its own and ships the live site's (`liveStylesheet` in the
111
+ * Studio), which is right: a Studio save changes content and uploaded files,
112
+ * never a stylesheet. It is also what the platform's own publish has always
113
+ * stored.
114
+ */
115
+ export function withoutStylesheets(
116
+ sources: Record<string, string>,
117
+ ): Record<string, string> {
118
+ return Object.fromEntries(
119
+ Object.entries(sources).filter(([key]) => !key.endsWith(".css")),
120
+ );
121
+ }
122
+
100
123
  /**
101
124
  * The project's own files: its source as text, and the binaries it imports
102
125
  * (an image, a font) base64, as `BuildInput.assets` takes them. `public/` is
@@ -244,6 +267,7 @@ export async function buildArtifacts(options: {
244
267
  ),
245
268
  );
246
269
  const sources = wiring?.files ?? onDisk;
270
+ const projectSource = withoutStylesheets(sources);
247
271
 
248
272
  // The dependency layer: from what the project imports, of what it declares.
249
273
  log("Building the dependency layer");
@@ -295,15 +319,16 @@ export async function buildArtifacts(options: {
295
319
  env: publicEnv(options.env ?? process.env),
296
320
  publicFiles: readPublicFiles(root),
297
321
  assets,
298
- // The project's own files, without the generated tree: what the next
299
- // publish -- the Studio's included -- starts from.
300
- projectSource: sources,
322
+ // The project's own files, without the generated tree or the
323
+ // stylesheets: what the next publish -- the Studio's included -- starts
324
+ // from. See `withoutStylesheets`.
325
+ projectSource,
301
326
  loadCssModule: node.cssModuleLoader(root),
302
327
  ...(splitter ? { routeSplitter: splitter } : {}),
303
328
  rsc: target.project.rsc,
304
329
  });
305
330
  const artifacts: PublishArtifact[] = await builder.publishArtifacts(built, {
306
- projectSource: sources,
331
+ projectSource,
307
332
  });
308
333
 
309
334
  const dir =
@@ -29,6 +29,8 @@ type Run = {
29
29
  buildTargetCalls: number;
30
30
  uploadedLayerRev: string | null;
31
31
  sourceHasRoute: boolean;
32
+ sourceHasStylesheet: boolean;
33
+ cssHasRule: boolean;
32
34
  clientHasPage: boolean;
33
35
  clientHasLogo: boolean;
34
36
  buildRouteBuilt: boolean;
@@ -76,6 +78,14 @@ test("the stored source is the project's own files", () => {
76
78
  expect(probe.fresh.sourceHasRoute).toBe(true);
77
79
  });
78
80
 
81
+ test("a stylesheet is built, and not stored as source", () => {
82
+ // The Studio builds from the stored source, in a browser that cannot run a
83
+ // Tailwind `@plugin`; a stored stylesheet failed every Studio publish after
84
+ // the first. Without one it ships the live site's CSS, compiled here.
85
+ expect(probe.fresh.cssHasRule).toBe(true);
86
+ expect(probe.fresh.sourceHasStylesheet).toBe(false);
87
+ });
88
+
79
89
  test("an image the project imports reaches the build", () => {
80
90
  expect(probe.fresh.clientHasLogo).toBe(true);
81
91
  });