@canopy-iiif/app 1.8.0 → 1.8.2

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/lib/build/dev.js CHANGED
@@ -23,6 +23,11 @@ const APP_COMPONENTS_DIR = path.join(process.cwd(), "app", "components");
23
23
 
24
24
  function resolveTailwindCli() {
25
25
  const root = process.cwd();
26
+ const binName = process.platform === "win32" ? "tailwindcss.cmd" : "tailwindcss";
27
+ const bin = path.join(root, "node_modules", ".bin", binName);
28
+ if (fs.existsSync(bin)) {
29
+ return { cmd: bin, args: [] };
30
+ }
26
31
  let cliEntry = null;
27
32
  try {
28
33
  cliEntry = require.resolve("@tailwindcss/cli/dist/index.mjs", { paths: [root] });
@@ -32,14 +37,7 @@ function resolveTailwindCli() {
32
37
  if (cliEntry) {
33
38
  return { cmd: process.execPath || "node", args: [cliEntry] };
34
39
  }
35
- const bin = path.join(
36
- root,
37
- "node_modules",
38
- ".bin",
39
- process.platform === "win32" ? "tailwindcss.cmd" : "tailwindcss"
40
- );
41
- if (fs.existsSync(bin)) return { cmd: bin, args: [] };
42
- return { cmd: "tailwindcss", args: [] };
40
+ return null;
43
41
  }
44
42
  const PORT = Number(process.env.PORT || 5001);
45
43
  const BUILD_MODULE_PATH = path.resolve(__dirname, "build.js");
@@ -965,7 +963,7 @@ async function dev() {
965
963
  const cli = resolveTailwindCli();
966
964
  if (!cli) {
967
965
  throw new Error(
968
- "[tailwind] Tailwind CLI not found. Install the 'tailwindcss' package in the workspace."
966
+ "[tailwind] Tailwind CLI not found. Install '@tailwindcss/cli' (and tailwindcss) in this workspace."
969
967
  );
970
968
  }
971
969
 
@@ -978,6 +976,46 @@ async function dev() {
978
976
  }
979
977
  };
980
978
 
979
+ const tailwindCmd = (args = []) => {
980
+ const parts = [cli.cmd];
981
+ if (Array.isArray(cli.args) && cli.args.length) parts.push(...cli.args);
982
+ if (Array.isArray(args) && args.length) parts.push(...args);
983
+ return parts.filter(Boolean).join(" ");
984
+ };
985
+
986
+ const formatSpawnOutput = (result) => {
987
+ if (!result) return "";
988
+ const messages = [];
989
+ if (result.stderr && result.stderr.length) {
990
+ const text = String(result.stderr).trim();
991
+ if (text) messages.push(`stderr: ${text}`);
992
+ }
993
+ if (result.stdout && result.stdout.length) {
994
+ const text = String(result.stdout).trim();
995
+ if (text) messages.push(`stdout: ${text}`);
996
+ }
997
+ return messages.join("\n");
998
+ };
999
+
1000
+ const tailwindFailureMessage = (label, result, args) => {
1001
+ const details = [
1002
+ label,
1003
+ ` input: ${prettyPath(inputCss)}`,
1004
+ ` config: ${configPath ? prettyPath(configPath) : "<unknown>"}`,
1005
+ ` cli: ${tailwindCmd(args)}`,
1006
+ ];
1007
+ const extra = formatSpawnOutput(result);
1008
+ if (extra) {
1009
+ details.push(
1010
+ extra
1011
+ .split(/\r?\n/)
1012
+ .map((line) => ` ${line}`)
1013
+ .join("\n")
1014
+ );
1015
+ }
1016
+ return details.join("\n");
1017
+ };
1018
+
981
1019
  const baseArgs = [
982
1020
  "-i",
983
1021
  inputCss,
@@ -993,10 +1031,13 @@ async function dev() {
993
1031
  env: { ...process.env, BROWSERSLIST_IGNORE_OLD_DATA: "1" },
994
1032
  });
995
1033
  if (!initial || initial.status !== 0) {
996
- if (initial && initial.stderr) {
997
- try { process.stderr.write(initial.stderr); } catch (_) {}
998
- }
999
- throw new Error("[tailwind] Initial Tailwind build failed.");
1034
+ throw new Error(
1035
+ tailwindFailureMessage(
1036
+ "[tailwind] Initial Tailwind build failed.",
1037
+ initial,
1038
+ baseArgs
1039
+ )
1040
+ );
1000
1041
  }
1001
1042
  injectThemeTokens(outputCss);
1002
1043
  stripTailwindThemeLayer(outputCss);
@@ -1047,10 +1088,13 @@ async function dev() {
1047
1088
  env: { ...process.env, BROWSERSLIST_IGNORE_OLD_DATA: "1" },
1048
1089
  });
1049
1090
  if (!res || res.status !== 0) {
1050
- if (res && res.stderr) {
1051
- try { process.stderr.write(res.stderr); } catch (_) {}
1052
- }
1053
- throw new Error("[tailwind] On-demand Tailwind compile failed.");
1091
+ throw new Error(
1092
+ tailwindFailureMessage(
1093
+ "[tailwind] On-demand Tailwind compile failed.",
1094
+ res,
1095
+ baseArgs
1096
+ )
1097
+ );
1054
1098
  }
1055
1099
  injectThemeTokens(outputCss);
1056
1100
  stripTailwindThemeLayer(outputCss);
@@ -9,6 +9,11 @@ const {
9
9
 
10
10
  function resolveTailwindCli() {
11
11
  const root = process.cwd();
12
+ const binName = process.platform === "win32" ? "tailwindcss.cmd" : "tailwindcss";
13
+ const localBin = path.join(root, "node_modules", ".bin", binName);
14
+ if (fs.existsSync(localBin)) {
15
+ return {cmd: localBin, args: []};
16
+ }
12
17
  let cliEntry = null;
13
18
  try {
14
19
  cliEntry = require.resolve("@tailwindcss/cli/dist/index.mjs", { paths: [root] });
@@ -18,14 +23,7 @@ function resolveTailwindCli() {
18
23
  if (cliEntry) {
19
24
  return {cmd: process.execPath || "node", args: [cliEntry]};
20
25
  }
21
- const localBin = path.join(
22
- root,
23
- "node_modules",
24
- ".bin",
25
- process.platform === "win32" ? "tailwindcss.cmd" : "tailwindcss"
26
- );
27
- if (fs.existsSync(localBin)) return {cmd: localBin, args: []};
28
- return {cmd: "tailwindcss", args: []};
26
+ return null;
29
27
  }
30
28
 
31
29
  function injectThemeTokens(targetPath) {
@@ -10,6 +10,40 @@ let uiWatcherChild = null;
10
10
 
11
11
  const workspacePackageJsonPath = path.resolve(process.cwd(), 'packages/app/package.json');
12
12
  const hasAppWorkspace = fs.existsSync(workspacePackageJsonPath);
13
+ const workspaceUiDistDir = path.resolve(process.cwd(), 'packages/app/ui/dist');
14
+ const requiredUiArtifacts = [
15
+ path.join(workspaceUiDistDir, 'server.mjs'),
16
+ path.join(workspaceUiDistDir, 'index.mjs'),
17
+ ];
18
+
19
+ function prettyPath(p) {
20
+ try {
21
+ const rel = path.relative(process.cwd(), p);
22
+ return rel ? rel.split(path.sep).join('/') : p;
23
+ } catch (_) {
24
+ return p;
25
+ }
26
+ }
27
+
28
+ function ensureUiDistReady(context = 'build') {
29
+ if (!hasAppWorkspace) return;
30
+ const missing = [];
31
+ for (const file of requiredUiArtifacts) {
32
+ try {
33
+ if (!fs.existsSync(file)) missing.push(file);
34
+ } catch (_) {
35
+ missing.push(file);
36
+ }
37
+ }
38
+ if (missing.length) {
39
+ const list = missing.map((file) => prettyPath(file)).join(', ');
40
+ const label = context ? `${context} ` : '';
41
+ throw new Error(
42
+ `@canopy-iiif/app/ui ${label}did not produce required bundle(s): ${list}. ` +
43
+ 'Run "npm -w @canopy-iiif/app run ui:build" and ensure it completes successfully.'
44
+ );
45
+ }
46
+ }
13
47
 
14
48
  function getMode(argv = process.argv.slice(2), env = process.env) {
15
49
  const cli = new Set(argv);
@@ -49,6 +83,20 @@ function start(cmd, args, opts = {}) {
49
83
  return child;
50
84
  }
51
85
 
86
+ async function buildUiOnce(label, env = process.env) {
87
+ if (!hasAppWorkspace) return;
88
+ const prefix = label || 'Building';
89
+ log(`${prefix} UI assets (@canopy-iiif/app/ui)`);
90
+ try {
91
+ await runOnce('npm', ['-w', '@canopy-iiif/app', 'run', 'ui:build'], { env });
92
+ } catch (error) {
93
+ const message = (error && error.message) || String(error);
94
+ throw new Error(`[canopy] Failed to ${prefix.toLowerCase()} UI assets: ${message}`);
95
+ }
96
+ ensureUiDistReady(prefix.toLowerCase());
97
+ log('UI assets ready');
98
+ }
99
+
52
100
  async function prepareUi(mode, env = process.env) {
53
101
  if (!hasAppWorkspace) {
54
102
  log('Using bundled UI assets from @canopy-iiif/app (workspace not detected)');
@@ -56,22 +104,11 @@ async function prepareUi(mode, env = process.env) {
56
104
  }
57
105
 
58
106
  if (mode === 'build') {
59
- log('Building UI assets (@canopy-iiif/app/ui)');
60
- try {
61
- await runOnce('npm', ['-w', '@canopy-iiif/app', 'run', 'ui:build'], { env });
62
- log('UI assets built');
63
- } catch (error) {
64
- warn(`UI build skipped: ${(error && error.message) || String(error)}`);
65
- }
107
+ await buildUiOnce('Building', env);
66
108
  return null;
67
109
  }
68
110
 
69
- try {
70
- log('Prebuilding UI assets (@canopy-iiif/app/ui)');
71
- await runOnce('npm', ['-w', '@canopy-iiif/app', 'run', 'ui:build'], { env });
72
- } catch (error) {
73
- warn(`UI prebuild skipped: ${(error && error.message) || String(error)}`);
74
- }
111
+ await buildUiOnce('Prebuilding', env);
75
112
 
76
113
  log('Starting UI watcher (@canopy-iiif/app/ui)');
77
114
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canopy-iiif/app",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Mat Jordan <mat@northwestern.edu>",