sku 16.3.0-replace-pnpm-plugin-20260909044129 → 16.3.0

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +24 -16
  2. package/dist/context/configSchema.mjs +4 -0
  3. package/dist/context/createSkuContext.mjs +2 -0
  4. package/dist/context/defaultSkuConfig.mjs +1 -0
  5. package/dist/entries/ssr-client.d.mts +1 -0
  6. package/dist/entries/ssr-client.mjs +12 -14
  7. package/dist/entries/ssr-server.d.mts +1 -0
  8. package/dist/entries/ssr-server.mjs +1 -0
  9. package/dist/entries/vite-client.d.mts +1 -0
  10. package/dist/entries/vite-client.mjs +1 -0
  11. package/dist/entries/vite-render.d.mts +1 -0
  12. package/dist/entries/vite-render.mjs +1 -0
  13. package/dist/package.mjs +4 -0
  14. package/dist/packages/sku/package.mjs +2 -3
  15. package/dist/postinstall.mjs +2 -2
  16. package/dist/private/utils/src/index.mjs +2 -4
  17. package/dist/private/utils/src/packageManager/index.mjs +3 -4
  18. package/dist/private/utils/src/packageManager/packageManager.mjs +5 -1
  19. package/dist/private/utils/src/packageManager/skuPackageManager.mjs +3 -0
  20. package/dist/program/commands/configure/configure.action.mjs +3 -3
  21. package/dist/program/commands/configure/configure.command.mjs +1 -1
  22. package/dist/program/commands/serve/serve.command.mjs +1 -1
  23. package/dist/program/commands/translations/helpers/translation-helpers.mjs +1 -1
  24. package/dist/services/packageManager/getPnpmConfigDependencies.mjs +12 -0
  25. package/dist/services/packageManager/pnpmConfig.mjs +14 -0
  26. package/dist/services/vite/plugins/entrySideEffects.mjs +35 -0
  27. package/dist/services/vite/plugins/ssr.mjs +3 -0
  28. package/dist/services/vite/plugins/ssrCss/constants.mjs +1 -1
  29. package/dist/services/vite/plugins/ssrCss/plugin.mjs +2 -2
  30. package/dist/services/vite/plugins/static.mjs +2 -1
  31. package/dist/services/vite/skuPlugin.mjs +2 -0
  32. package/dist/services/vite/ssr/createDevSsrServer.mjs +3 -2
  33. package/dist/services/vite/ssr/createDocumentAttempt.mjs +12 -15
  34. package/dist/services/vite/ssr/documentAssets.d.mts +12 -0
  35. package/dist/services/vite/ssr/documentAssets.mjs +18 -0
  36. package/dist/services/vite/ssr/render.mjs +2 -1
  37. package/dist/services/vite/ssr/types.d.mts +5 -0
  38. package/dist/types/types.d.mts +18 -3
  39. package/dist/utils/configure.mjs +2 -2
  40. package/dist/utils/configureApp.mjs +15 -9
  41. package/dist/utils/validatePeerDeps.mjs +1 -1
  42. package/dist/webpack/server.mjs +12 -3
  43. package/package.json +2 -3
  44. package/dist/private/utils/src/packageManager/ensurePnpmWorkspaceConfig.mjs +0 -50
  45. package/dist/private/utils/src/packageManager/pnpmWorkspaceDefaults.mjs +0 -73
  46. package/dist/private/utils/src/packageManager/removePnpmPluginSku.mjs +0 -19
  47. package/dist/private/utils/src/packageManager/syncArraySettings.mjs +0 -75
  48. package/dist/private/utils/src/packageManager/syncObjectSettings.mjs +0 -67
  49. package/dist/private/utils/src/packageManager/syncShared.mjs +0 -21
  50. package/dist/private/utils/src/packageManager/syncSingleValueSettings.mjs +0 -58
  51. package/dist/services/vite/ssr/Document.mjs +0 -24
package/CHANGELOG.md CHANGED
@@ -1,24 +1,32 @@
1
1
  # sku
2
2
 
3
- ## 16.3.0-replace-pnpm-plugin-20260909044129
3
+ ## 16.3.0
4
4
 
5
5
  ### Minor Changes
6
6
 
7
- - Migrate from `pnpm-plugin-sku` to static `pnpm-workspace.yaml` configuration. ([#1718](https://github.com/seek-oss/sku/pull/1718))
8
-
9
- ### Summary of Changes
10
- - **Static Workspace Configuration**: Sku's recommended pnpm settings are now written directly into `pnpm-workspace.yaml` with `[sku_managed]` comment markers instead of being injected at runtime via `pnpm-plugin-sku`.
11
- - **Automatic Migration**: On the first run of a configuration-enabled sku command or postinstall, `pnpm-plugin-sku` is removed from `configDependencies` in `pnpm-workspace.yaml` (and the `configDependencies` field is deleted if empty).
12
- - **Two Sync Modes**:
13
- - **Additive Sync (configuration-enabled sku commands & postinstall)**: Adds missing managed single-value settings and `allowBuilds` keys, unions and deduplicates array settings (`publicHoistPattern`, `minimumReleaseAgeExclude`, `trustPolicyExclude`), and never overwrites existing config values or removes user-owned entries.
14
- - **Enforce Mode (`sku configure`)**: Overwrites managed single-value settings and marked `allowBuilds` keys to match sku defaults in both directions. Unmarked `allowBuilds` overrides are preserved. Removes retired sku defaults that still carry a `[sku_managed]` marker.
15
- - **Managed Comments**: Comments on entries adopted or overwritten by sku are replaced with the `[sku_managed]` marker, alongside any explanatory comment sku provides (for example `# 3 days [sku_managed]`).
16
- - **Mutation Logging**: File creation, additions, adoptions, duplicate removal, migrations, updates, and retirements are logged; aligned files remain silent.
17
- - **Drift Warnings**: Regular sku commands warn when managed values differ from sku defaults or when retired entries still have a `[sku_managed]` marker, suggesting `sku configure` to align.
18
- - **Opt-outs and Escape Hatches**:
19
- - `skuSkipConfigure: true` in `package.json` disables the sync on regular sku commands (`skuSkipPostInstall: true` disables it on postinstall). Manual `sku configure` always syncs.
20
- - To keep an entry that sku has retired, delete its `[sku_managed]` marker (or re-add it without a marker) to designate it as user-managed.
21
- - **New Project Scaffolding**: `@sku-lib/create` now uses the shared sync engine to emit `pnpm-workspace.yaml` on project creation, without installing `pnpm-plugin-sku` or gating on pnpm versions.
7
+ - Managed Data Mode root layouts now need to render the full `<html>`, `<head>`, and `<body>`, not just inside the `<body>`. Allowing it to render into any part of document. ([#1720](https://github.com/seek-oss/sku/pull/1720))
8
+
9
+ - Add `entrySideEffects` so apps can import isomorphic modules (such as Braid reset) before any consumer module. ([#1717](https://github.com/seek-oss/sku/pull/1717))
10
+
11
+ - Webpack SSR: Pass the listening server and port to `onStart` ([#1730](https://github.com/seek-oss/sku/pull/1730))
12
+
13
+ `onStart` still receives the Express app as its first argument. A new second argument carries `{ httpServer, port }`, so apps can set keep-alive timeouts and close the server on shutdown.
14
+
15
+ ```tsx
16
+ import type { Server } from 'sku';
17
+
18
+ export default (): Server => ({
19
+ renderCallback,
20
+ onStart: (app, { httpServer, port }) => {
21
+ httpServer.keepAliveTimeout = 20_000;
22
+ process.on('SIGTERM', () => {
23
+ httpServer.close(() => process.exit(0));
24
+ });
25
+ },
26
+ });
27
+ ```
28
+
29
+ See the [Webpack SSR](https://seek-oss.github.io/sku/ssr/webpack-ssr) docs for more details.
22
30
 
23
31
  ## 16.2.0
24
32
 
@@ -122,6 +122,10 @@ var configSchema_default = validator.compile({
122
122
  type: "array",
123
123
  items: "string"
124
124
  },
125
+ entrySideEffects: {
126
+ type: "array",
127
+ items: "string"
128
+ },
125
129
  libraryName: {
126
130
  type: "string",
127
131
  optional: true
@@ -107,6 +107,7 @@ const createSkuContext = async ({ configPath, port: portArg, strictPort }) => {
107
107
  const libraryFile = skuConfig.libraryFile;
108
108
  const isLibrary = Boolean(skuConfig.libraryEntry);
109
109
  const polyfills = skuConfig.polyfills;
110
+ const entrySideEffects = skuConfig.entrySideEffects;
110
111
  const webpackDecorator = skuConfig.dangerouslySetWebpackConfig;
111
112
  const jestDecorator = skuConfig.dangerouslySetJestConfig;
112
113
  const eslintDecorator = skuConfig.dangerouslySetESLintConfig;
@@ -157,6 +158,7 @@ const createSkuContext = async ({ configPath, port: portArg, strictPort }) => {
157
158
  libraryFile,
158
159
  isLibrary,
159
160
  polyfills,
161
+ entrySideEffects,
160
162
  webpackDecorator,
161
163
  jestDecorator,
162
164
  eslintDecorator,
@@ -26,6 +26,7 @@ var defaultSkuConfig_default = {
26
26
  public: "public",
27
27
  publicPath: "/",
28
28
  polyfills: [],
29
+ entrySideEffects: [],
29
30
  libraryName: void 0,
30
31
  libraryFile: void 0,
31
32
  sourceMapsProd: true,
@@ -1 +1,2 @@
1
+ import "virtual:sku/entry-side-effects";
1
2
  import "virtual:sku/polyfills";
@@ -1,15 +1,16 @@
1
- import { Document } from "../services/vite/ssr/Document.mjs";
2
1
  import { buildSiteRouteTrees } from "../services/vite/ssr/buildSiteRouteTrees.mjs";
3
2
  import { readRoutesEntry } from "../services/vite/ssr/readRoutesEntry.mjs";
4
3
  import { assertSiteName, selectForSite } from "../services/vite/ssr/selectForSite.mjs";
4
+ import "virtual:sku/entry-side-effects";
5
5
  import "virtual:sku/polyfills";
6
6
  import * as clientEntry from "__sku_alias__clientEntry";
7
- import { jsx } from "react/jsx-runtime";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { hydrateRoot } from "react-dom/client";
9
9
  import { RouterProvider, createBrowserRouter, matchRoutes } from "react-router";
10
10
  import * as routesEntry from "__sku_alias__routesEntry";
11
11
  import { SkuProvider } from "#runtime/skuContext";
12
12
  import { registerSiteRouteTree } from "#runtime/preloadRoute";
13
+ import { DocumentAssetLinks } from "#runtime/documentAssets";
13
14
  //#region src/services/vite/entries/ssr-client.tsx
14
15
  const { routes, mapRoutePath } = readRoutesEntry(routesEntry);
15
16
  const entry = clientEntry.default;
@@ -41,18 +42,15 @@ const hydrate = async () => {
41
42
  }) } : {},
42
43
  ...instrumentations === void 0 ? {} : { instrumentations }
43
44
  });
44
- hydrateRoot(document, /* @__PURE__ */ jsx(Document, {
45
- assets: window.__SKU_DOCUMENT_ASSETS__ ?? {
46
- css: [],
47
- modulePreloads: []
48
- },
49
- children: /* @__PURE__ */ jsx(SkuProvider, {
50
- site,
51
- clientContext,
52
- reactContext,
53
- children: /* @__PURE__ */ jsx(RouterProvider, { router })
54
- })
55
- }));
45
+ hydrateRoot(document, /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(DocumentAssetLinks, { assets: window.__SKU_DOCUMENT_ASSETS__ ?? {
46
+ css: [],
47
+ modulePreloads: []
48
+ } }), /* @__PURE__ */ jsx(SkuProvider, {
49
+ site,
50
+ clientContext,
51
+ reactContext,
52
+ children: /* @__PURE__ */ jsx(RouterProvider, { router })
53
+ })] }));
56
54
  };
57
55
  hydrate().catch((error) => {
58
56
  console.error(error);
@@ -1,4 +1,5 @@
1
1
  import { RenderAssets, RenderManifest, RenderOptions, RenderResult, SkuMiddleware, SkuOnListen } from "../services/vite/ssr/types.mjs";
2
+ import "virtual:sku/entry-side-effects";
2
3
  import { Request as Request$1 } from "express";
3
4
  //#region src/services/vite/entries/ssr-server.d.ts
4
5
  declare const middleware: SkuMiddleware | undefined, onListen: SkuOnListen | undefined;
@@ -2,6 +2,7 @@ import { buildSiteRouteTrees } from "../services/vite/ssr/buildSiteRouteTrees.mj
2
2
  import { readRoutesEntry } from "../services/vite/ssr/readRoutesEntry.mjs";
3
3
  import { buildSiteStaticHandlers } from "../services/vite/ssr/buildSiteStaticHandlers.mjs";
4
4
  import { render as render$1 } from "../services/vite/ssr/render.mjs";
5
+ import "virtual:sku/entry-side-effects";
5
6
  import * as routesEntry from "__sku_alias__routesEntry";
6
7
  import * as serverEntry from "__sku_alias__serverEntry";
7
8
  //#region src/services/vite/entries/ssr-server.tsx
@@ -1 +1,2 @@
1
+ import "virtual:sku/entry-side-effects";
1
2
  import "virtual:sku/polyfills";
@@ -1,3 +1,4 @@
1
+ import "virtual:sku/entry-side-effects";
1
2
  import "virtual:sku/polyfills";
2
3
  import client from "__sku_alias__clientEntry";
3
4
  import dedent from "dedent";
@@ -1,4 +1,5 @@
1
1
  import { ViteRenderFunction } from "../types/types.mjs";
2
+ import "virtual:sku/entry-side-effects";
2
3
  //#region src/services/vite/entries/vite-render.d.ts
3
4
  declare const viteRender: ViteRenderFunction;
4
5
  //#endregion
@@ -1,5 +1,6 @@
1
1
  import { createPreRenderedHtml } from "../services/vite/helpers/html/createPreRenderedHtml.mjs";
2
2
  import { createDebug } from "obug";
3
+ import "virtual:sku/entry-side-effects";
3
4
  import { createCollector } from "@sku-lib/vite/collector";
4
5
  import render from "__sku_alias__renderEntry";
5
6
  //#region src/services/vite/entries/vite-render.tsx
@@ -0,0 +1,4 @@
1
+ //#region ../../package.json
2
+ var packageManager = "pnpm@11.24.0";
3
+ //#endregion
4
+ export { packageManager };
@@ -1,7 +1,7 @@
1
1
  //#region package.json
2
2
  var package_default = {
3
3
  name: "sku",
4
- version: "16.2.0",
4
+ version: "16.3.0",
5
5
  description: "Front-end development toolkit, powered by Webpack, Babel, Vanilla Extract and Jest",
6
6
  types: "./dist/index.d.mts",
7
7
  bin: { "sku": "bin/bin.js" },
@@ -158,8 +158,7 @@ var package_default = {
158
158
  "webpack-bundle-analyzer": "^5.1.1",
159
159
  "webpack-dev-server": "catalog:",
160
160
  "webpack-merge": "^6.0.1",
161
- "webpack-node-externals": "^3.0.0",
162
- "yaml": "^2.8.3"
161
+ "webpack-node-externals": "^3.0.0"
163
162
  },
164
163
  devDependencies: {
165
164
  "@sku-private/tsdown": "workspace:*",
@@ -4,7 +4,7 @@ import "./private/utils/src/index.mjs";
4
4
  import { banner } from "./private/utils/src/console/banner.mjs";
5
5
  import "./private/utils/src/console/index.mjs";
6
6
  import { createSkuContext } from "./context/createSkuContext.mjs";
7
- import { configureApp } from "./utils/configureApp.mjs";
7
+ import configureApp_default from "./utils/configureApp.mjs";
8
8
  import { createDebug } from "obug";
9
9
  //#region src/postinstall.ts
10
10
  /**
@@ -17,7 +17,7 @@ const postinstall = async ({ localCwd, packageJson, hasSkuDep }) => {
17
17
  try {
18
18
  log("postinstall", "running configure");
19
19
  const skuContext = await createSkuContext({});
20
- await configureApp(skuContext);
20
+ configureApp_default(skuContext);
21
21
  } catch (error) {
22
22
  console.error("An error occurred running postinstall script. Please check that sku.config.js is correct and try again.");
23
23
  console.error(error);
@@ -1,9 +1,7 @@
1
1
  import "./path/toPosixPath.mjs";
2
2
  import { cwd, getPathFromCwd, requireFromCwd, setCwd, writeFileToCWD } from "./filesystem/cwd.mjs";
3
3
  import "./filesystem/index.mjs";
4
- import { getAddCommand, getExecuteCommand, getRunCommand, getWhyCommand, isPnpm, packageManager, rootDir } from "./packageManager/packageManager.mjs";
5
- import { MANAGED_BY_SKU_MARKER, arraySettings, defaultPnpmWorkspaceConfig, objectSettings, pnpmWorkspaceSettings, singleValueSettings } from "./packageManager/pnpmWorkspaceDefaults.mjs";
6
- import { ensurePnpmWorkspaceConfig } from "./packageManager/ensurePnpmWorkspaceConfig.mjs";
4
+ import { getAddCommand, getExecuteCommand, getRunCommand, getWhyCommand, isAtLeastPnpmV10, isAtLeastRecommendedPnpmVersion, isPnpm, packageManager, rootDir } from "./packageManager/packageManager.mjs";
7
5
  import "./packageManager/index.mjs";
8
6
  import { makeUrl, serverUrls } from "./serverUrls.mjs";
9
- export { MANAGED_BY_SKU_MARKER, arraySettings, cwd, defaultPnpmWorkspaceConfig, ensurePnpmWorkspaceConfig, getAddCommand, getExecuteCommand, getPathFromCwd, getRunCommand, getWhyCommand, isPnpm, makeUrl, objectSettings, packageManager, pnpmWorkspaceSettings, requireFromCwd, rootDir, serverUrls, setCwd, singleValueSettings, writeFileToCWD };
7
+ export { cwd, getAddCommand, getExecuteCommand, getPathFromCwd, getRunCommand, getWhyCommand, isAtLeastPnpmV10, isAtLeastRecommendedPnpmVersion, isPnpm, makeUrl, packageManager, requireFromCwd, rootDir, serverUrls, setCwd, writeFileToCWD };
@@ -1,4 +1,3 @@
1
- import { getAddCommand, getExecuteCommand, getRunCommand, getWhyCommand, isPnpm, packageManager, rootDir } from "./packageManager.mjs";
2
- import { MANAGED_BY_SKU_MARKER, arraySettings, defaultPnpmWorkspaceConfig, objectSettings, pnpmWorkspaceSettings, singleValueSettings } from "./pnpmWorkspaceDefaults.mjs";
3
- import { ensurePnpmWorkspaceConfig } from "./ensurePnpmWorkspaceConfig.mjs";
4
- export { MANAGED_BY_SKU_MARKER, arraySettings, defaultPnpmWorkspaceConfig, ensurePnpmWorkspaceConfig, getAddCommand, getExecuteCommand, getRunCommand, getWhyCommand, isPnpm, objectSettings, packageManager, pnpmWorkspaceSettings, rootDir, singleValueSettings };
1
+ import { getAddCommand, getExecuteCommand, getRunCommand, getWhyCommand, isAtLeastPnpmV10, isAtLeastRecommendedPnpmVersion, isPnpm, packageManager, rootDir } from "./packageManager.mjs";
2
+ import "./skuPackageManager.mjs";
3
+ export { getAddCommand, getExecuteCommand, getRunCommand, getWhyCommand, isAtLeastPnpmV10, isAtLeastRecommendedPnpmVersion, isPnpm, packageManager, rootDir };
@@ -4,6 +4,7 @@ import { detectSync } from "../../../../node_modules/.pnpm/package-manager-detec
4
4
  import { caution, strong } from "../console/styles.mjs";
5
5
  import { dirname } from "node:path";
6
6
  import * as find from "empathic/find";
7
+ import semver from "semver";
7
8
  //#region ../../private/utils/src/packageManager/packageManager.ts
8
9
  const lockfileByPackageManager = {
9
10
  pnpm: "pnpm-lock.yaml",
@@ -71,6 +72,9 @@ const resolvePackageManager = () => {
71
72
  };
72
73
  };
73
74
  const { rootDir, packageManager, packageManagerVersion } = resolvePackageManager();
75
+ const isAtLeastPnpmV10 = () => packageManager === "pnpm" && packageManagerVersion && semver.satisfies(packageManagerVersion, ">=10.0.0");
76
+ const recommendedPnpmVersion = "10.13.0";
77
+ const isAtLeastRecommendedPnpmVersion = () => Boolean(packageManager === "pnpm" && packageManagerVersion && semver.satisfies(packageManagerVersion, `>=${recommendedPnpmVersion}`));
74
78
  const getCommand = (agent, command, args) => {
75
79
  const resolvedCommand = resolveCommand(agent, command, args);
76
80
  if (!resolvedCommand) throw new Error(`Unable to resolve command: ${agent} ${command} ${args}`);
@@ -112,4 +116,4 @@ const getWhyCommand = () => {
112
116
  return `${packageManager} ${isPnpm ? "why -r" : "why"}`;
113
117
  };
114
118
  //#endregion
115
- export { getAddCommand, getCommand, getExecuteCommand, getRunCommand, getWhyCommand, isPnpm, isYarn, packageManager, rootDir };
119
+ export { getAddCommand, getCommand, getExecuteCommand, getRunCommand, getWhyCommand, isAtLeastPnpmV10, isAtLeastRecommendedPnpmVersion, isPnpm, isYarn, packageManager, packageManagerVersion, rootDir };
@@ -0,0 +1,3 @@
1
+ import "../../../../package.mjs";
2
+ //#endregion
3
+ export {};
@@ -1,7 +1,7 @@
1
- import { configureApp } from "../../../utils/configureApp.mjs";
1
+ import configureApp_default from "../../../utils/configureApp.mjs";
2
2
  //#region src/program/commands/configure/configure.action.ts
3
- const configureAction = async ({ skuContext }) => {
4
- await configureApp(skuContext, { mode: "enforce" });
3
+ const configureAction = ({ skuContext }) => {
4
+ configureApp_default(skuContext);
5
5
  };
6
6
  //#endregion
7
7
  export { configureAction };
@@ -2,7 +2,7 @@ import { Command } from "commander";
2
2
  //#region src/program/commands/configure/configure.command.ts
3
3
  const configureCommand = new Command("configure").description("Emit and update configuration files for your project.").action(async (options) => {
4
4
  const { configureAction } = await import("./configure.action.mjs");
5
- await configureAction(options);
5
+ configureAction(options);
6
6
  });
7
7
  //#endregion
8
8
  export { configureCommand };
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  const serveCommand = new Command("serve").description("Serve a production build of a statically-rendered application from your local machine.").addOption(siteOption).addOption(portOption).addOption(strictPortOption).addOption(listUrlsOption).action(async ({ site, skuContext }, command) => {
7
7
  const { serveAction } = await import("./serve.action.mjs");
8
8
  const { environment } = command.optsWithGlobals();
9
- await serveAction({
9
+ serveAction({
10
10
  site,
11
11
  environment,
12
12
  skuContext
@@ -1,6 +1,6 @@
1
1
  import { getVocabConfig } from "../../../../services/vocab/config.mjs";
2
- import { resolveConfig } from "@vocab/core";
3
2
  import { execSync } from "node:child_process";
3
+ import { resolveConfig } from "@vocab/core";
4
4
  //#region src/program/commands/translations/helpers/translation-helpers.ts
5
5
  const ensureBranch = async () => {
6
6
  const branch = getGitBranch();
@@ -0,0 +1,12 @@
1
+ import { execAsync } from "../../utils/execAsync.mjs";
2
+ //#region src/services/packageManager/getPnpmConfigDependencies.ts
3
+ const getPnpmConfigDependencies = async () => {
4
+ const rawResult = await execAsync(`pnpm config get --json`);
5
+ if (!rawResult) return [];
6
+ const result = JSON.parse(rawResult);
7
+ const configDependencies = result["config-dependencies"] ?? result.configDependencies;
8
+ if (!configDependencies) return [];
9
+ return Object.keys(configDependencies);
10
+ };
11
+ //#endregion
12
+ export { getPnpmConfigDependencies };
@@ -0,0 +1,14 @@
1
+ import { accent } from "../../private/utils/src/console/styles.mjs";
2
+ import { banner } from "../../private/utils/src/console/banner.mjs";
3
+ import "../../private/utils/src/console/index.mjs";
4
+ //#region src/services/packageManager/pnpmConfig.ts
5
+ const validatePnpmConfig = async ({ hasRecommendedPnpmVersionInstalled, pnpmPluginSkuInstalled }) => {
6
+ if (!pnpmPluginSkuInstalled || !hasRecommendedPnpmVersionInstalled) {
7
+ const messages = [];
8
+ if (!hasRecommendedPnpmVersionInstalled) messages.push(`Please ensure you are on ${accent("PNPM v10.13.0")} or later.`);
9
+ messages.push(`Please delete your top-level ${accent("node_modules")} and run "${accent("pnpm add --config pnpm-plugin-sku && pnpm install")}".`);
10
+ banner("caution", "pnpm-plugin-sku is not configured correctly", messages);
11
+ }
12
+ };
13
+ //#endregion
14
+ export { validatePnpmConfig };
@@ -0,0 +1,35 @@
1
+ import { cwd } from "../../../private/utils/src/filesystem/cwd.mjs";
2
+ import "../../../private/utils/src/index.mjs";
3
+ import { makePluginName } from "../helpers/makePluginName.mjs";
4
+ import { exactRegex } from "../../../node_modules/.pnpm/rolldown@1.2.2/node_modules/rolldown/dist/filter-index.mjs";
5
+ import { createRequire } from "node:module";
6
+ //#region src/services/vite/plugins/entrySideEffects.ts
7
+ const require = createRequire(import.meta.url);
8
+ const ENTRY_SIDE_EFFECTS_VIRTUAL_ID = "virtual:sku/entry-side-effects";
9
+ const isFileSpecifier = (specifier) => specifier.startsWith(".") || specifier.startsWith("/");
10
+ const loadEntrySideEffectsModule = (specifiers) => specifiers.map((specifier) => {
11
+ const resolved = require.resolve(specifier, { paths: [cwd()] });
12
+ return `import "${isFileSpecifier(specifier) ? resolved : specifier}";`;
13
+ }).join("\n");
14
+ const entrySideEffectsPlugin = (skuContext) => {
15
+ const resolvedVirtualModuleId = `\0${ENTRY_SIDE_EFFECTS_VIRTUAL_ID}`;
16
+ const moduleCode = loadEntrySideEffectsModule(skuContext.entrySideEffects);
17
+ return {
18
+ name: makePluginName("entry-side-effects"),
19
+ config: () => skuContext.entrySideEffects.length === 0 ? void 0 : { optimizeDeps: { include: skuContext.entrySideEffects } },
20
+ resolveId: {
21
+ filter: { id: exactRegex(ENTRY_SIDE_EFFECTS_VIRTUAL_ID) },
22
+ handler() {
23
+ return resolvedVirtualModuleId;
24
+ }
25
+ },
26
+ load: {
27
+ filter: { id: exactRegex(resolvedVirtualModuleId) },
28
+ handler() {
29
+ return moduleCode;
30
+ }
31
+ }
32
+ };
33
+ };
34
+ //#endregion
35
+ export { ENTRY_SIDE_EFFECTS_VIRTUAL_ID, entrySideEffectsPlugin, loadEntrySideEffectsModule };
@@ -1,6 +1,7 @@
1
1
  import { makePluginName } from "../helpers/makePluginName.mjs";
2
2
  import { SSR_CLIENT_CHUNK_NAME } from "../ssr/resolveAssets.mjs";
3
3
  import { createOutDir } from "../helpers/bundleConfig.mjs";
4
+ import { ENTRY_SIDE_EFFECTS_VIRTUAL_ID } from "./entrySideEffects.mjs";
4
5
  import { CLIENT_MANIFEST_RELATIVE_PATH } from "../ssr/clientManifestPath.mjs";
5
6
  import { resolveConfigSiteNames } from "../ssr/resolveConfigSiteNames.mjs";
6
7
  import { lazyRouteModuleIdPlugin } from "./lazyRouteModuleId/lazyRouteModuleIdPlugin.mjs";
@@ -25,6 +26,7 @@ const ssrPlugins = (skuContext) => {
25
26
  skuContext.paths.clientEntry,
26
27
  skuContext.paths.routesEntry,
27
28
  ssrClientDevEntry,
29
+ ssrClientEntry,
28
30
  ssrServerEntry
29
31
  ] },
30
32
  ssr: { external: ["vite"] }
@@ -69,6 +71,7 @@ const ssrPlugins = (skuContext) => {
69
71
  lazyRouteModuleIdPlugin(),
70
72
  vitePluginSsrCss({
71
73
  entries: [
74
+ ENTRY_SIDE_EFFECTS_VIRTUAL_ID,
72
75
  skuContext.paths.serverEntry,
73
76
  skuContext.paths.routesEntry,
74
77
  ssrServerEntry
@@ -1,6 +1,6 @@
1
1
  //#region src/services/vite/plugins/ssrCss/constants.ts
2
2
  const SSR_CSS_VIRTUAL_ENTRY = "virtual:ssr-css.css";
3
- /** Dev-server URL for the collected SSR stylesheet (Document / transformIndexHtml). */
3
+ /** Dev-server URL for the collected SSR stylesheet (sku hoist / transformIndexHtml). */
4
4
  const SSR_CSS_VIRTUAL_HREF = `/@id/__x00__${SSR_CSS_VIRTUAL_ENTRY}`;
5
5
  //#endregion
6
6
  export { SSR_CSS_VIRTUAL_ENTRY, SSR_CSS_VIRTUAL_HREF };
@@ -1,12 +1,12 @@
1
- import { SSR_CSS_VIRTUAL_ENTRY, SSR_CSS_VIRTUAL_HREF } from "./constants.mjs";
2
1
  import { collectStyle } from "./collect.mjs";
2
+ import { SSR_CSS_VIRTUAL_ENTRY, SSR_CSS_VIRTUAL_HREF } from "./constants.mjs";
3
3
  //#region src/services/vite/plugins/ssrCss/plugin.ts
4
4
  const PLUGIN_NAME = "vite-plugin-ssr-css";
5
5
  /**
6
6
  * This plugin provides virtual:ssr-css.css to collect styles reachable from entries.
7
7
  * When `injectHtml` is true (static Vite), ViteDevServer.transformIndexHtml injects
8
8
  * the stylesheet link plus HMR cleanup. SSR sets `injectHtml: false` and puts
9
- * `SSR_CSS_VIRTUAL_HREF` in Document `assets.css` instead.
9
+ * `SSR_CSS_VIRTUAL_HREF` in sku-hoisted `assets.css` instead.
10
10
  *
11
11
  * This plugin has been forked from `hi-ogawa/vite-plugins`, with some adjustments to make it work with Sku + Braid.
12
12
  * @see https://github.com/hi-ogawa/vite-plugins/blob/main/packages/ssr-css/README.md
@@ -1,5 +1,6 @@
1
1
  import { makePluginName } from "../helpers/makePluginName.mjs";
2
2
  import { createOutDir, renderEntryChunkName } from "../helpers/bundleConfig.mjs";
3
+ import { ENTRY_SIDE_EFFECTS_VIRTUAL_ID } from "./entrySideEffects.mjs";
3
4
  import { vitePluginSsrCss } from "./ssrCss/plugin.mjs";
4
5
  import { telemetryPlugin } from "./telemetry.mjs";
5
6
  import { middlewarePlugin } from "./middleware.mjs";
@@ -42,7 +43,7 @@ const staticPlugins = ({ skuContext, environment }) => {
42
43
  } }
43
44
  } })
44
45
  },
45
- vitePluginSsrCss({ entries: [skuContext.paths.renderEntry] }),
46
+ vitePluginSsrCss({ entries: [ENTRY_SIDE_EFFECTS_VIRTUAL_ID, skuContext.paths.renderEntry] }),
46
47
  environment !== void 0 && middlewarePlugin({
47
48
  skuContext,
48
49
  environment
@@ -2,6 +2,7 @@ import { httpsDevServerPlugin } from "./plugins/httpsDevServer.mjs";
2
2
  import { preloadPlugin } from "./plugins/preloadPlugin/preloadPlugin.mjs";
3
3
  import { setNoExternalPlugin } from "./plugins/setNoExternal.mjs";
4
4
  import { polyfillsPlugin } from "./plugins/polyfills.mjs";
5
+ import { entrySideEffectsPlugin } from "./plugins/entrySideEffects.mjs";
5
6
  import { dangerouslySetViteConfigPlugin } from "./plugins/dangerouslySetViteConfig.mjs";
6
7
  import { configPlugin } from "./plugins/config.mjs";
7
8
  import { buildPlugin } from "./plugins/build.mjs";
@@ -27,6 +28,7 @@ const skuPlugin = ({ skuContext, environment }) => {
27
28
  convertFromWebpack: skuContext.convertLoadable,
28
29
  commandName: skuContext.commandName
29
30
  }),
31
+ entrySideEffectsPlugin(skuContext),
30
32
  polyfillsPlugin(skuContext),
31
33
  !isSsr && staticPlugins({
32
34
  skuContext,
@@ -1,5 +1,5 @@
1
- import { SSR_CSS_VIRTUAL_HREF } from "../plugins/ssrCss/constants.mjs";
2
1
  import { getAppHosts } from "../../../context/hosts.mjs";
2
+ import { SSR_CSS_VIRTUAL_HREF } from "../plugins/ssrCss/constants.mjs";
3
3
  import { metricsMeasurers } from "../../telemetry/metricsMeasurers.mjs";
4
4
  import { createConfig } from "../helpers/config/createConfig.mjs";
5
5
  import createServer$1 from "../../../utils/createServer.mjs";
@@ -52,7 +52,8 @@ const createDevSsrServer = async ({ skuContext, environment }) => {
52
52
  const assets = {
53
53
  bootstrapModules: [`/@vite/client`, `/@fs/${clientEntry}`],
54
54
  css: [SSR_CSS_VIRTUAL_HREF],
55
- modulePreloads: []
55
+ modulePreloads: [],
56
+ ssrCssHref: SSR_CSS_VIRTUAL_HREF
56
57
  };
57
58
  const render = async (...args) => {
58
59
  return (await vite.ssrLoadModule(serverEntry)).render(...args);
@@ -1,11 +1,11 @@
1
- import { Document } from "./Document.mjs";
2
1
  import { abortReason } from "./abortReason.mjs";
3
2
  import { bindCommit } from "./bindCommit.mjs";
4
3
  import { buildBootstrapScriptContent } from "./bootstrap.mjs";
5
4
  import { renderToPipeableStream } from "react-dom/server";
6
- import { jsx } from "react/jsx-runtime";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
7
6
  import { StaticRouterProvider, createStaticRouter } from "react-router";
8
7
  import { SkuProvider } from "#runtime/skuContext";
8
+ import { DocumentAssetLinks } from "#runtime/documentAssets";
9
9
  import { InsertHtmlProvider, createInsertHtmlQueue } from "#runtime/insertHtml";
10
10
  //#region src/services/vite/ssr/createDocumentAttempt.tsx
11
11
  const createDocumentAttempt = ({ renderContext, dataRoutes, documentAssets, assets, site, clientContext, reactContext, routeHeaders, waitForAll, nonce, options }) => {
@@ -54,21 +54,18 @@ const createDocumentAttempt = ({ renderContext, dataRoutes, documentAssets, asse
54
54
  queue: insertHtmlQueue
55
55
  })
56
56
  });
57
- streamRef.current = renderToPipeableStream(/* @__PURE__ */ jsx(InsertHtmlProvider, {
57
+ streamRef.current = renderToPipeableStream(/* @__PURE__ */ jsxs(InsertHtmlProvider, {
58
58
  insertHtml: insertHtmlQueue.insertHtml,
59
- children: /* @__PURE__ */ jsx(Document, {
60
- assets: documentAssets,
61
- children: /* @__PURE__ */ jsx(SkuProvider, {
62
- site,
63
- clientContext,
64
- reactContext,
65
- children: /* @__PURE__ */ jsx(StaticRouterProvider, {
66
- router,
67
- context: renderContext,
68
- hydrate: false
69
- })
59
+ children: [/* @__PURE__ */ jsx(DocumentAssetLinks, { assets: documentAssets }), /* @__PURE__ */ jsx(SkuProvider, {
60
+ site,
61
+ clientContext,
62
+ reactContext,
63
+ children: /* @__PURE__ */ jsx(StaticRouterProvider, {
64
+ router,
65
+ context: renderContext,
66
+ hydrate: false
70
67
  })
71
- })
68
+ })]
72
69
  }), {
73
70
  bootstrapModules: assets.bootstrapModules,
74
71
  bootstrapScriptContent,
@@ -0,0 +1,12 @@
1
+ import { DocumentAssets } from "./types.mjs";
2
+ //#region src/services/vite/ssr/documentAssets.d.ts
3
+ declare const SKU_STYLESHEET_PRECEDENCE = "sku";
4
+ /**
5
+ * Sku-owned CSS and modulepreload links. Mounted beside the router so React
6
+ * hoists them into the app `<head>`.
7
+ */
8
+ declare const DocumentAssetLinks: ({ assets }: {
9
+ assets: DocumentAssets;
10
+ }) => import("react").JSX.Element;
11
+ //#endregion
12
+ export { DocumentAssetLinks, SKU_STYLESHEET_PRECEDENCE };
@@ -0,0 +1,18 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ //#region src/services/vite/ssr/documentAssets.tsx
3
+ const SKU_STYLESHEET_PRECEDENCE = "sku";
4
+ /**
5
+ * Sku-owned CSS and modulepreload links. Mounted beside the router so React
6
+ * hoists them into the app `<head>`.
7
+ */
8
+ const DocumentAssetLinks = ({ assets }) => /* @__PURE__ */ jsxs(Fragment, { children: [assets.modulePreloads.map((href) => /* @__PURE__ */ jsx("link", {
9
+ rel: "modulepreload",
10
+ href
11
+ }, href)), assets.css.map((href) => /* @__PURE__ */ jsx("link", {
12
+ rel: "stylesheet",
13
+ href,
14
+ precedence: "sku",
15
+ ...href === assets.ssrCssHref ? { "data-ssr-css": true } : {}
16
+ }, href))] });
17
+ //#endregion
18
+ export { DocumentAssetLinks, SKU_STYLESHEET_PRECEDENCE };
@@ -36,7 +36,8 @@ const renderDocument = async ({ siteStaticHandlers, request, req, assets, getSit
36
36
  });
37
37
  let documentAssets = {
38
38
  css: assets.css,
39
- modulePreloads: assets.modulePreloads
39
+ modulePreloads: assets.modulePreloads,
40
+ ssrCssHref: assets.ssrCssHref
40
41
  };
41
42
  if (renderManifest) documentAssets = resolveAssets({
42
43
  manifest: renderManifest.manifest,
@@ -10,6 +10,11 @@ import { Express, Request as Request$1, RequestHandler } from "express";
10
10
  interface DocumentAssets {
11
11
  css: string[];
12
12
  modulePreloads: string[];
13
+ /**
14
+ * Start-only virtual stylesheet href. Sku document asset links mark this URL
15
+ * with `data-ssr-css` so the client can drop it after HMR.
16
+ */
17
+ ssrCssHref?: string;
13
18
  }
14
19
  interface RenderAssets extends DocumentAssets {
15
20
  bootstrapModules: string[];
@@ -1,6 +1,8 @@
1
1
  import { Plugin, PluginOption } from "vite";
2
2
  import { JSX, ReactNode } from "react";
3
3
  import { ChunkExtractor } from "@loadable/server";
4
+ import { Server } from "node:http";
5
+ import { Server as Server$1 } from "node:https";
4
6
  import { Express, RequestHandler } from "express";
5
7
  import { Linter } from "eslint";
6
8
  import { TestUserConfig } from "vitest/node";
@@ -27,9 +29,12 @@ interface RenderCallbackParams {
27
29
  extractor: ChunkExtractor;
28
30
  registerScript?: (script: string) => void;
29
31
  }
30
- interface Server {
32
+ interface Server$2 {
31
33
  renderCallback: (params: RenderCallbackParams, ...requestHandlerParams: Parameters<RequestHandler>) => void;
32
- onStart?: (app: Express) => void;
34
+ onStart?: (app: Express, server: {
35
+ httpServer: Server | Server$1;
36
+ port: number;
37
+ }) => void | Promise<void>;
33
38
  middleware?: RequestHandler | RequestHandler[];
34
39
  }
35
40
  interface RenderableRoute {
@@ -508,6 +513,16 @@ interface ViteSkuConfig {
508
513
  * @default: []
509
514
  */
510
515
  vitePlugins?: PluginOption[];
516
+ /**
517
+ * An array of isomorphic modules to import before any consumer module.
518
+ *
519
+ * Use this for CSS resets (for example `braid-design-system/reset`) that must
520
+ * evaluate first. Specifiers resolve from the app, in array order.
521
+ *
522
+ * @default []
523
+ * @link https://seek-oss.github.io/sku/configuration#entrysideeffects
524
+ */
525
+ entrySideEffects?: string[];
511
526
  /**
512
527
  * **SSR only** (`buildType: 'ssr'`)
513
528
  *
@@ -587,4 +602,4 @@ type SkuConfig = SkuConfigBase & (({
587
602
  bundler: 'vite';
588
603
  } & ViteSkuConfig));
589
604
  //#endregion
590
- export { Render, RenderAppProps, RenderCallbackParams, RenderableRoute, Server, SkuConfig, SkuConfigBase, SkuLanguage, SkuProvider, SkuRoute, SkuRouteObject, SkuSiteObject, TransformOutputPathFunctionParams, ViteRenderFunction, ViteSkuConfig, WebpackSkuConfig };
605
+ export { Render, RenderAppProps, RenderCallbackParams, RenderableRoute, Server$2 as Server, SkuConfig, SkuConfigBase, SkuLanguage, SkuProvider, SkuRoute, SkuRouteObject, SkuSiteObject, TransformOutputPathFunctionParams, ViteRenderFunction, ViteSkuConfig, WebpackSkuConfig };
@@ -17,8 +17,8 @@ const configureProject = async (skuContext) => {
17
17
  log(`"skuSkipConfigure" set in ${packageJson}, skipping sku configuration`);
18
18
  return;
19
19
  }
20
- const { configureApp } = await import("./configureApp.mjs");
21
- await configureApp(skuContext);
20
+ const { default: configure } = await import("./configureApp.mjs");
21
+ await configure(skuContext);
22
22
  };
23
23
  const validatePeerDeps = (skuContext) => {
24
24
  if (skipValidatePeerDeps) {
@@ -1,6 +1,5 @@
1
1
  import { getPathFromCwd, writeFileToCWD } from "../private/utils/src/filesystem/cwd.mjs";
2
- import { isPnpm, rootDir } from "../private/utils/src/packageManager/packageManager.mjs";
3
- import { ensurePnpmWorkspaceConfig } from "../private/utils/src/packageManager/ensurePnpmWorkspaceConfig.mjs";
2
+ import { isAtLeastPnpmV10, isAtLeastRecommendedPnpmVersion, rootDir } from "../private/utils/src/packageManager/packageManager.mjs";
4
3
  import "../private/utils/src/index.mjs";
5
4
  import options from "../config/prettier.mjs";
6
5
  import { bundleReportFolder } from "../services/webpack/config/plugins/bundleAnalyzer.mjs";
@@ -8,6 +7,8 @@ import { createTSConfig } from "../services/typescript/tsconfig.mjs";
8
7
  import getCertificate from "./certificate.mjs";
9
8
  import { syncPathAliasImports } from "./pathAliasImports.mjs";
10
9
  import { validateSkuConfigFormat } from "./validateSkuConfigFormat.mjs";
10
+ import { getPnpmConfigDependencies } from "../services/packageManager/getPnpmConfigDependencies.mjs";
11
+ import { validatePnpmConfig } from "../services/packageManager/pnpmConfig.mjs";
11
12
  import { warnOnLegacyReact } from "./warnOnLegacyReact.mjs";
12
13
  import path from "node:path";
13
14
  import { rm } from "node:fs/promises";
@@ -17,7 +18,7 @@ import ensureGitignore from "ensure-gitignore";
17
18
  const coverageFolder = "coverage";
18
19
  const convertToForwardSlashPaths = (pathStr) => pathStr.replace(/\\/g, "/");
19
20
  const addSep = (p) => `${p}${path.sep}`;
20
- async function configureApp(skuContext, options$1) {
21
+ var configureApp_default = async (skuContext) => {
21
22
  const { paths, httpsDevServer, languages, hosts } = skuContext;
22
23
  validateSkuConfigFormat(paths.appSkuConfigPath);
23
24
  const targetDirectories = [.../* @__PURE__ */ new Set([addSep(paths.relativeTarget)])];
@@ -64,11 +65,16 @@ async function configureApp(skuContext, options$1) {
64
65
  comment: "managed by sku",
65
66
  patterns: gitIgnorePatterns.map(convertToForwardSlashPaths)
66
67
  });
67
- if (rootDir && isPnpm) await ensurePnpmWorkspaceConfig({
68
- targetDir: rootDir,
69
- mode: options$1?.mode ?? "additive"
70
- });
68
+ if (rootDir && isAtLeastPnpmV10()) {
69
+ const pnpmConfigDependencies = await getPnpmConfigDependencies();
70
+ const hasRecommendedPnpmVersionInstalled = isAtLeastRecommendedPnpmVersion();
71
+ const pnpmPluginSkuInstalled = pnpmConfigDependencies.includes("pnpm-plugin-sku");
72
+ await validatePnpmConfig({
73
+ hasRecommendedPnpmVersionInstalled,
74
+ pnpmPluginSkuInstalled
75
+ });
76
+ }
71
77
  warnOnLegacyReact();
72
- }
78
+ };
73
79
  //#endregion
74
- export { configureApp };
80
+ export { configureApp_default as default };
@@ -7,8 +7,8 @@ import "../private/utils/src/console/index.mjs";
7
7
  import telemetry_default from "../services/telemetry/index.mjs";
8
8
  import { readFileSync } from "node:fs";
9
9
  import { readFile } from "node:fs/promises";
10
- import { fdir } from "fdir";
11
10
  import semver from "semver";
11
+ import { fdir } from "fdir";
12
12
  //#region src/utils/validatePeerDeps.ts
13
13
  const asyncMap = (list, fn) => Promise.all(list.map((item) => fn(item)));
14
14
  const singletonPackages = ["@vanilla-extract/css"];
@@ -15,11 +15,20 @@ const { values } = parseArgs({
15
15
  strict: false
16
16
  });
17
17
  const { port } = values;
18
- const startCallback = () => {
18
+ let server;
19
+ const startCallback = async () => {
19
20
  console.log("sku SSR server started on port", port);
20
- if (typeof onStart === "function") onStart(app);
21
+ if (typeof onStart !== "function") return;
22
+ try {
23
+ await onStart(app, {
24
+ httpServer: server,
25
+ port: Number(port)
26
+ });
27
+ } catch (error) {
28
+ console.error(error);
29
+ process.exit(1);
30
+ }
21
31
  };
22
- let server;
23
32
  if (__SKU_DEV_HTTPS__) {
24
33
  const pems = fs.readFileSync(".ssl/self-signed.pem");
25
34
  server = https.createServer({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sku",
3
- "version": "16.3.0-replace-pnpm-plugin-20260909044129",
3
+ "version": "16.3.0",
4
4
  "description": "Front-end development toolkit, powered by Webpack, Babel, Vanilla Extract and Jest",
5
5
  "types": "./dist/index.d.mts",
6
6
  "bin": {
@@ -169,8 +169,7 @@
169
169
  "webpack-bundle-analyzer": "^5.1.1",
170
170
  "webpack-dev-server": "^5.2.4",
171
171
  "webpack-merge": "^6.0.1",
172
- "webpack-node-externals": "^3.0.0",
173
- "yaml": "^2.8.3"
172
+ "webpack-node-externals": "^3.0.0"
174
173
  },
175
174
  "devDependencies": {
176
175
  "@sku-private/tsdown": "0.0.0",
@@ -1,50 +0,0 @@
1
- import { caution } from "../console/styles.mjs";
2
- import { rootDir } from "./packageManager.mjs";
3
- import { defaultPnpmWorkspaceConfig } from "./pnpmWorkspaceDefaults.mjs";
4
- import { removePnpmPluginSku } from "./removePnpmPluginSku.mjs";
5
- import { syncArraySettings } from "./syncArraySettings.mjs";
6
- import { syncObjectSettings } from "./syncObjectSettings.mjs";
7
- import { syncSingleValueSettings } from "./syncSingleValueSettings.mjs";
8
- import { join } from "node:path";
9
- import { existsSync } from "node:fs";
10
- import { readFile, writeFile } from "node:fs/promises";
11
- import { Document, isMap, parseDocument } from "yaml";
12
- //#region ../../private/utils/src/packageManager/ensurePnpmWorkspaceConfig.ts
13
- async function ensurePnpmWorkspaceConfig({ mode = "additive", create = false, targetDir = rootDir ?? process.cwd() } = {}) {
14
- const filePath = join(targetDir, "pnpm-workspace.yaml");
15
- const fileExisted = existsSync(filePath);
16
- if (!fileExisted && !create) return;
17
- let originalContent = "";
18
- let doc;
19
- if (fileExisted) {
20
- originalContent = await readFile(filePath, "utf-8");
21
- doc = parseDocument(originalContent);
22
- if (!doc.contents) doc.contents = doc.createNode({});
23
- else if (!isMap(doc.contents)) throw new Error(`Cannot sync ${filePath}: the document must contain a YAML mapping`);
24
- } else doc = new Document(structuredClone(defaultPnpmWorkspaceConfig));
25
- let modified = false;
26
- const recordMutation = (message) => {
27
- modified = true;
28
- console.log(message);
29
- };
30
- if (!fileExisted) recordMutation("created pnpm-workspace.yaml");
31
- const warn = (message) => {
32
- console.warn(caution(message));
33
- };
34
- const context = {
35
- doc,
36
- mode,
37
- recordMutation,
38
- warn
39
- };
40
- removePnpmPluginSku(doc, recordMutation);
41
- syncSingleValueSettings(context);
42
- syncObjectSettings(context);
43
- syncArraySettings(context);
44
- if (modified) {
45
- const newContent = doc.toString();
46
- if (newContent !== originalContent) await writeFile(filePath, newContent, "utf-8");
47
- }
48
- }
49
- //#endregion
50
- export { ensurePnpmWorkspaceConfig };
@@ -1,73 +0,0 @@
1
- //#region ../../private/utils/src/packageManager/pnpmWorkspaceDefaults.ts
2
- const MANAGED_BY_SKU_MARKER = "[sku_managed]";
3
- /** Overwritten wholesale by `sku configure`: sku's value always wins. */
4
- const singleValueSetting = (value, comment) => ({
5
- kind: "value",
6
- value,
7
- comment
8
- });
9
- /** A flat map merged per key. Marked keys are sku-owned, the rest are the user's. */
10
- const objectSetting = (entries) => ({
11
- kind: "object",
12
- entries
13
- });
14
- /** Unioned and deduped. Marked entries are sku-owned, the rest are the user's. */
15
- const arraySetting = (entries) => ({
16
- kind: "array",
17
- entries: entries.map((entry) => typeof entry === "string" ? { value: entry } : entry)
18
- });
19
- const minutesPerDay = 1440;
20
- const minimumReleaseAgeInDays = 3;
21
- /**
22
- * Sku's recommended pnpm settings. Each entry declares its own value, merge
23
- * policy and comments, and everything the sync needs is derived from here.
24
- */
25
- const pnpmWorkspaceSettings = {
26
- allowBuilds: objectSetting({
27
- "@parcel/watcher": true,
28
- "@swc/core": true,
29
- "core-js-pure": false,
30
- esbuild: true,
31
- sku: true,
32
- "unrs-resolver": true
33
- }),
34
- blockExoticSubdeps: singleValueSetting(true),
35
- minimumReleaseAge: singleValueSetting(minimumReleaseAgeInDays * minutesPerDay, `${minimumReleaseAgeInDays} days`),
36
- minimumReleaseAgeExclude: arraySetting([
37
- "@braid-design-system/*",
38
- "@capsizecss/*",
39
- "@seek/*",
40
- "@sku-lib/*",
41
- "@vanilla-extract/*",
42
- "@vocab/*",
43
- "braid-design-system",
44
- "browserslist-config-seek",
45
- "eslint-config-seek",
46
- "sku"
47
- ]),
48
- publicHoistPattern: arraySetting(["eslint", "prettier"]),
49
- strictDepBuilds: singleValueSetting(false),
50
- trustPolicy: singleValueSetting("off"),
51
- trustPolicyExclude: arraySetting([{
52
- value: "semver@6.3.1",
53
- comment: "dependency of eslint-plugin-react"
54
- }])
55
- };
56
- const keyedSettings = Object.keys(pnpmWorkspaceSettings).map((key) => ({
57
- key,
58
- ...pnpmWorkspaceSettings[key]
59
- }));
60
- const singleValueSettings = keyedSettings.filter((setting) => setting.kind === "value");
61
- const objectSettings = keyedSettings.filter((setting) => setting.kind === "object");
62
- const arraySettings = keyedSettings.filter((setting) => setting.kind === "array");
63
- const settingValue = (setting) => {
64
- switch (setting.kind) {
65
- case "value": return setting.value;
66
- case "object": return { ...setting.entries };
67
- case "array": return setting.entries.map(({ value }) => value);
68
- }
69
- };
70
- /** The settings as plain values, for scaffolding a `pnpm-workspace.yaml` from scratch. */
71
- const defaultPnpmWorkspaceConfig = Object.fromEntries(keyedSettings.map((setting) => [setting.key, settingValue(setting)]));
72
- //#endregion
73
- export { MANAGED_BY_SKU_MARKER, arraySettings, defaultPnpmWorkspaceConfig, objectSettings, pnpmWorkspaceSettings, singleValueSettings };
@@ -1,19 +0,0 @@
1
- import { getNodeKey } from "./syncShared.mjs";
2
- import { isMap, isPair, isSeq } from "yaml";
3
- //#region ../../private/utils/src/packageManager/removePnpmPluginSku.ts
4
- /**
5
- * Removes the pnpm-plugin-sku from the configDependencies in pnpm-workspace.yaml
6
- */
7
- const removePnpmPluginSku = (doc, recordMutation) => {
8
- if (!doc.has("configDependencies")) return;
9
- const cd = doc.get("configDependencies", true);
10
- if (!isMap(cd) && !isSeq(cd)) return;
11
- const items = cd.items;
12
- const remainingItems = items.filter((item) => getNodeKey(isPair(item) ? item.key : item) !== "pnpm-plugin-sku");
13
- if (remainingItems.length === items.length) return;
14
- cd.items = remainingItems;
15
- recordMutation("removed pnpm-plugin-sku from configDependencies in pnpm-workspace.yaml");
16
- if (remainingItems.length === 0) doc.delete("configDependencies");
17
- };
18
- //#endregion
19
- export { removePnpmPluginSku };
@@ -1,75 +0,0 @@
1
- import { MANAGED_BY_SKU_MARKER, arraySettings } from "./pnpmWorkspaceDefaults.mjs";
2
- import { hasManagedMarker, setManagedComment } from "./syncShared.mjs";
3
- import { isScalar, isSeq } from "yaml";
4
- //#region ../../private/utils/src/packageManager/syncArraySettings.ts
5
- const deduplicateArrayItems = (seqNode, key, context) => {
6
- const seenValues = /* @__PURE__ */ new Map();
7
- const deduplicatedItems = [];
8
- for (const item of seqNode.items) if (isScalar(item) && typeof item.value === "string") {
9
- const existingIndex = seenValues.get(item.value);
10
- if (existingIndex !== void 0) {
11
- const existingItem = deduplicatedItems[existingIndex];
12
- if (isScalar(existingItem) && hasManagedMarker(existingItem.comment) && !hasManagedMarker(item.comment)) deduplicatedItems[existingIndex] = item;
13
- context.recordMutation(`removed duplicate ${item.value} from ${key} in pnpm-workspace.yaml`);
14
- continue;
15
- }
16
- seenValues.set(item.value, deduplicatedItems.length);
17
- deduplicatedItems.push(item);
18
- } else deduplicatedItems.push(item);
19
- seqNode.items = deduplicatedItems;
20
- };
21
- /**
22
- * Adopts default entries and flags retired ones in an existing array.
23
- *
24
- * @returns Whether the item should be removed from the sequence.
25
- */
26
- const processSingleArrayItem = (item, defaultComments, key, context) => {
27
- if (!isScalar(item) || typeof item.value !== "string") return false;
28
- const val = item.value;
29
- if (defaultComments.has(val)) {
30
- if (setManagedComment(item, defaultComments.get(val))) context.recordMutation(`adopted ${val} in ${key} in pnpm-workspace.yaml`);
31
- return false;
32
- }
33
- if (hasManagedMarker(item.comment)) {
34
- if (context.mode === "enforce") return true;
35
- context.warn(`pnpm-workspace.yaml: "${val}" in ${key} is marked with "${MANAGED_BY_SKU_MARKER}", but is no longer a sku default. Run "sku configure" to remove it, or delete its "${MANAGED_BY_SKU_MARKER}" marker to keep it as a user-managed entry.`);
36
- }
37
- return false;
38
- };
39
- const processExistingArrayItems = (seqNode, defaultComments, key, context) => {
40
- const indicesToRemove = [];
41
- for (const [i, item] of seqNode.items.entries()) if (processSingleArrayItem(item, defaultComments, key, context)) indicesToRemove.push(i);
42
- for (const idx of indicesToRemove.toReversed()) {
43
- const item = seqNode.items[idx];
44
- const val = isScalar(item) ? String(item.value) : "";
45
- seqNode.items.splice(idx, 1);
46
- context.recordMutation(`removed retired entry ${val} from ${key} in pnpm-workspace.yaml`);
47
- }
48
- };
49
- const appendMissingArrayDefaults = (seqNode, entries, key, context) => {
50
- const existingValues = /* @__PURE__ */ new Set();
51
- for (const item of seqNode.items) if (isScalar(item) && typeof item.value === "string") existingValues.add(item.value);
52
- for (const { value, comment } of entries) if (!existingValues.has(value)) {
53
- const newItem = context.doc.createNode(value);
54
- setManagedComment(newItem, comment);
55
- seqNode.items.push(newItem);
56
- existingValues.add(value);
57
- context.recordMutation(`added ${value} to ${key} in pnpm-workspace.yaml`);
58
- }
59
- };
60
- const syncArraySettings = (context) => {
61
- for (const { key, entries } of arraySettings) {
62
- const defaultComments = new Map(entries.map(({ value, comment }) => [value, comment]));
63
- if (!context.doc.has(key)) {
64
- context.doc.set(key, context.doc.createNode([]));
65
- context.recordMutation(`added ${key} to pnpm-workspace.yaml`);
66
- }
67
- const seqNode = context.doc.get(key, true);
68
- if (!isSeq(seqNode)) continue;
69
- deduplicateArrayItems(seqNode, key, context);
70
- processExistingArrayItems(seqNode, defaultComments, key, context);
71
- appendMissingArrayDefaults(seqNode, entries, key, context);
72
- }
73
- };
74
- //#endregion
75
- export { syncArraySettings };
@@ -1,67 +0,0 @@
1
- import { MANAGED_BY_SKU_MARKER, objectSettings } from "./pnpmWorkspaceDefaults.mjs";
2
- import { clearCommentBefore, getNodeKey, hasManagedMarker, setManagedComment } from "./syncShared.mjs";
3
- import { isMap, isScalar } from "yaml";
4
- //#region ../../private/utils/src/packageManager/syncObjectSettings.ts
5
- const markPairAsManaged = (pair, explanatory) => {
6
- const modified = setManagedComment(pair.value, explanatory);
7
- return clearCommentBefore(pair.key) || modified;
8
- };
9
- const syncExistingObjectPair = (pair, key, subKey, defaultVal, context) => {
10
- const { doc, mode, recordMutation, warn } = context;
11
- if (!isScalar(pair.value)) return;
12
- const currentVal = pair.value.value;
13
- if (currentVal === defaultVal) {
14
- if (markPairAsManaged(pair)) recordMutation(`adopted ${key}.${subKey}: ${String(currentVal)} in pnpm-workspace.yaml`);
15
- return;
16
- }
17
- if (!hasManagedMarker(pair.value.comment)) return;
18
- if (mode === "enforce") {
19
- pair.value = doc.createNode(defaultVal);
20
- setManagedComment(pair.value);
21
- clearCommentBefore(pair.key);
22
- recordMutation(`updated ${key}.${subKey}: ${String(currentVal)} → ${defaultVal} in pnpm-workspace.yaml`);
23
- return;
24
- }
25
- warn(`pnpm-workspace.yaml: "${key}.${subKey}" has value ${String(currentVal)}, recommended is ${defaultVal}. Run "sku configure" to align.`);
26
- };
27
- const syncObjectPair = (mapNode, key, subKey, defaultVal, context) => {
28
- const pair = mapNode.items.find((item) => getNodeKey(item.key) === subKey);
29
- if (!pair) {
30
- const valNode = context.doc.createNode(defaultVal);
31
- setManagedComment(valNode);
32
- mapNode.set(subKey, valNode);
33
- context.recordMutation(`added ${key}.${subKey}: ${defaultVal} to pnpm-workspace.yaml`);
34
- return;
35
- }
36
- syncExistingObjectPair(pair, key, subKey, defaultVal, context);
37
- };
38
- const cleanRetiredObjectKeys = (mapNode, key, defaultObj, context) => {
39
- const { mode, recordMutation, warn } = context;
40
- const itemsToRemove = [];
41
- for (const pair of mapNode.items) {
42
- const subKey = getNodeKey(pair.key);
43
- if (!(subKey in defaultObj)) {
44
- if (isScalar(pair.value) && hasManagedMarker(pair.value.comment)) if (mode === "enforce") itemsToRemove.push(subKey);
45
- else warn(`pnpm-workspace.yaml: "${subKey}" in ${key} is marked with "${MANAGED_BY_SKU_MARKER}", but is no longer a sku default. Run "sku configure" to remove it, or delete its "${MANAGED_BY_SKU_MARKER}" marker to keep it as a user-managed entry.`);
46
- }
47
- }
48
- for (const subKey of itemsToRemove) {
49
- mapNode.delete(subKey);
50
- recordMutation(`removed retired entry ${key}.${subKey} from pnpm-workspace.yaml`);
51
- }
52
- };
53
- const syncObjectSettings = (context) => {
54
- const { doc } = context;
55
- for (const { key, entries } of objectSettings) {
56
- if (!doc.has(key)) {
57
- doc.set(key, doc.createNode({}));
58
- context.recordMutation(`added ${key} to pnpm-workspace.yaml`);
59
- }
60
- const mapNode = doc.get(key, true);
61
- if (!isMap(mapNode)) continue;
62
- for (const [subKey, defaultVal] of Object.entries(entries)) syncObjectPair(mapNode, key, subKey, defaultVal, context);
63
- cleanRetiredObjectKeys(mapNode, key, entries, context);
64
- }
65
- };
66
- //#endregion
67
- export { syncObjectSettings };
@@ -1,21 +0,0 @@
1
- import { MANAGED_BY_SKU_MARKER } from "./pnpmWorkspaceDefaults.mjs";
2
- import { isScalar } from "yaml";
3
- //#region ../../private/utils/src/packageManager/syncShared.ts
4
- const getNodeKey = (node) => isScalar(node) ? String(node.value) : String(node);
5
- const hasManagedMarker = (comment) => Boolean(comment?.includes(MANAGED_BY_SKU_MARKER));
6
- const formatComment = (explanatory) => explanatory ? ` ${explanatory} ${MANAGED_BY_SKU_MARKER}` : ` ${MANAGED_BY_SKU_MARKER}`;
7
- const clearCommentBefore = (node) => {
8
- if (!isScalar(node) || !node.commentBefore) return false;
9
- node.commentBefore = void 0;
10
- return true;
11
- };
12
- const setManagedComment = (node, explanatory) => {
13
- if (!isScalar(node)) return false;
14
- const comment = formatComment(explanatory);
15
- const modified = node.comment !== comment || Boolean(node.commentBefore);
16
- node.comment = comment;
17
- node.commentBefore = void 0;
18
- return modified;
19
- };
20
- //#endregion
21
- export { clearCommentBefore, getNodeKey, hasManagedMarker, setManagedComment };
@@ -1,58 +0,0 @@
1
- import { singleValueSettings } from "./pnpmWorkspaceDefaults.mjs";
2
- import { clearCommentBefore, getNodeKey, setManagedComment } from "./syncShared.mjs";
3
- import { isMap, isScalar } from "yaml";
4
- //#region ../../private/utils/src/packageManager/syncSingleValueSettings.ts
5
- const findMapPair = (doc, key) => {
6
- if (!isMap(doc.contents)) return;
7
- return doc.contents.items.find((pair) => getNodeKey(pair.key) === key);
8
- };
9
- const markSingleValueAsManaged = (node, explanatory, doc, key) => {
10
- const modified = setManagedComment(node, explanatory);
11
- const pair = findMapPair(doc, key);
12
- return (pair ? clearCommentBefore(pair.key) : false) || modified;
13
- };
14
- const handleMatchingSingleValue = (node, explanatory, currentValue, doc, key, context) => {
15
- if (isScalar(node)) {
16
- if (markSingleValueAsManaged(node, explanatory, doc, key)) context.recordMutation(`adopted ${key}: ${String(currentValue)} in pnpm-workspace.yaml`);
17
- return;
18
- }
19
- const wrapped = doc.createNode(currentValue);
20
- setManagedComment(wrapped, explanatory);
21
- doc.set(key, wrapped);
22
- context.recordMutation(`adopted ${key}: ${String(currentValue)} in pnpm-workspace.yaml`);
23
- };
24
- const updateExistingSingleValue = (key, defaultValue, explanatory, context) => {
25
- const { doc, mode, recordMutation, warn } = context;
26
- const node = doc.get(key, true);
27
- const currentValue = isScalar(node) ? node.value : doc.get(key);
28
- if (currentValue === defaultValue) {
29
- handleMatchingSingleValue(node, explanatory, currentValue, doc, key, context);
30
- return;
31
- }
32
- if (mode === "enforce") {
33
- const updatedNode = doc.createNode(defaultValue);
34
- setManagedComment(updatedNode, explanatory);
35
- doc.set(key, updatedNode);
36
- const pair = findMapPair(doc, key);
37
- if (pair) clearCommentBefore(pair.key);
38
- recordMutation(`updated ${key}: ${String(currentValue)} → ${defaultValue} in pnpm-workspace.yaml`);
39
- return;
40
- }
41
- warn(`pnpm-workspace.yaml: "${key}" has value ${String(currentValue)}, recommended is ${defaultValue}. Run "sku configure" to align.`);
42
- };
43
- const syncSingleValue = ({ key, value: defaultValue, comment }, context) => {
44
- const { doc, recordMutation } = context;
45
- if (!doc.has(key)) {
46
- const node = doc.createNode(defaultValue);
47
- setManagedComment(node, comment);
48
- doc.set(key, node);
49
- recordMutation(`added ${key}: ${defaultValue} to pnpm-workspace.yaml`);
50
- return;
51
- }
52
- updateExistingSingleValue(key, defaultValue, comment, context);
53
- };
54
- const syncSingleValueSettings = (context) => {
55
- for (const setting of singleValueSettings) syncSingleValue(setting, context);
56
- };
57
- //#endregion
58
- export { syncSingleValueSettings };
@@ -1,24 +0,0 @@
1
- import { SSR_CSS_VIRTUAL_HREF } from "../plugins/ssrCss/constants.mjs";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- //#region src/services/vite/ssr/Document.tsx
4
- const Document = ({ children, assets }) => /* @__PURE__ */ jsxs("html", {
5
- lang: "en",
6
- children: [/* @__PURE__ */ jsxs("head", { children: [
7
- /* @__PURE__ */ jsx("meta", { charSet: "utf-8" }),
8
- /* @__PURE__ */ jsx("meta", {
9
- name: "viewport",
10
- content: "width=device-width, initial-scale=1"
11
- }),
12
- assets.modulePreloads.map((href) => /* @__PURE__ */ jsx("link", {
13
- rel: "modulepreload",
14
- href
15
- }, href)),
16
- assets.css.map((href) => /* @__PURE__ */ jsx("link", {
17
- rel: "stylesheet",
18
- href,
19
- ...href === SSR_CSS_VIRTUAL_HREF ? { "data-ssr-css": true } : {}
20
- }, href))
21
- ] }), /* @__PURE__ */ jsx("body", { children })]
22
- });
23
- //#endregion
24
- export { Document };