xpine 0.0.26 → 0.0.27

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.
@@ -4,12 +4,146 @@
4
4
  import path5 from "path";
5
5
  import fs5 from "fs-extra";
6
6
  import { build } from "esbuild";
7
- import ts3 from "typescript";
8
7
 
9
8
  // src/build/typescript-builder.ts
10
9
  import ts from "typescript";
11
10
  import fs from "fs-extra";
11
+ import path2 from "path";
12
+
13
+ // src/util/get-config.ts
12
14
  import path from "path";
15
+
16
+ // src/util/require.ts
17
+ import { createRequire } from "module";
18
+ var require_default = createRequire(import.meta.url);
19
+
20
+ // src/util/get-config.ts
21
+ var rootDir = process.cwd();
22
+ function fromRoot(pathName) {
23
+ if (!pathName) return rootDir;
24
+ return path.join(rootDir, pathName);
25
+ }
26
+ var userConfig = require_default(path.join(process.cwd(), "./xpine.config.mjs")).default;
27
+ var configDefaults = {
28
+ rootDir: fromRoot(),
29
+ srcDir: fromRoot("./src"),
30
+ distDir: fromRoot("./dist"),
31
+ packageJsonPath: fromRoot("package.json"),
32
+ // We need to use getters here in the event someone wants to change folders, such as the dist folder
33
+ get distPublicDir() {
34
+ return path.join(this.distDir, "./public");
35
+ },
36
+ get distPublicScriptsDir() {
37
+ return path.join(this.distPublicDir, "./scripts");
38
+ },
39
+ get distTempFolder() {
40
+ return path.join(this.distDir, "./temp");
41
+ },
42
+ get clientJSBundlePath() {
43
+ return path.join(this.distPublicScriptsDir, "./app.js");
44
+ },
45
+ get alpineDataPath() {
46
+ return path.join(this.distTempFolder, "./alpine-data.ts");
47
+ },
48
+ get serverDistDir() {
49
+ return path.join(this.distDir, "./server");
50
+ },
51
+ get serverDistAppPath() {
52
+ return path.join(this.serverDistDir, "./app.js");
53
+ },
54
+ // Important dirs/paths
55
+ get pagesDir() {
56
+ return path.join(this.srcDir, "./pages");
57
+ },
58
+ get distPagesDir() {
59
+ return path.join(this.distDir, "./pages");
60
+ },
61
+ get publicDir() {
62
+ return path.join(this.srcDir, "./public");
63
+ },
64
+ get serverDir() {
65
+ return path.join(this.srcDir, "./server");
66
+ },
67
+ get runDir() {
68
+ return path.join(this.serverDir, "./run");
69
+ },
70
+ get serverAppPath() {
71
+ return path.join(this.serverDir, "./app.ts");
72
+ },
73
+ get globalCSSFile() {
74
+ return path.join(this.publicDir, "./styles/global.css");
75
+ }
76
+ };
77
+ var config = {
78
+ ...configDefaults,
79
+ ...userConfig
80
+ };
81
+
82
+ // src/context.ts
83
+ function createContext(value) {
84
+ let stateValue = value;
85
+ let arrayQueue = {};
86
+ return {
87
+ get(id) {
88
+ const val = stateValue[id];
89
+ if (Array.isArray(val)) return val.filter((item) => item !== void 0);
90
+ return val;
91
+ },
92
+ set(id, callback, defaultValue) {
93
+ if (!stateValue[id]) stateValue[id] = defaultValue ?? null;
94
+ stateValue[id] = callback(stateValue[id]);
95
+ },
96
+ clear() {
97
+ stateValue = {};
98
+ },
99
+ getAll() {
100
+ return stateValue;
101
+ },
102
+ getArrayQueue() {
103
+ return arrayQueue;
104
+ },
105
+ addToArray(id, value2, position) {
106
+ const output = {
107
+ id,
108
+ value: addToContextArray(value2, position),
109
+ position
110
+ };
111
+ if (!arrayQueue[id]) {
112
+ arrayQueue[id] = [output];
113
+ } else {
114
+ arrayQueue[id].push(output);
115
+ }
116
+ },
117
+ runArrayQueue() {
118
+ Object.keys(arrayQueue).forEach((key) => {
119
+ arrayQueue[key].sort((a, b) => {
120
+ return (a?.position ?? Infinity) - (b.position ?? Infinity);
121
+ });
122
+ for (const item of arrayQueue[key]) {
123
+ this.set(key, item.value, []);
124
+ }
125
+ });
126
+ arrayQueue = {};
127
+ }
128
+ };
129
+ }
130
+ var context = createContext({});
131
+ function addToContextArray(newValue, position) {
132
+ return function(currentValue) {
133
+ if (!currentValue) return [newValue];
134
+ if (typeof position === "number") {
135
+ if (position > currentValue?.length) {
136
+ const output = [...currentValue, ...new Array(position + 1 - currentValue.length)];
137
+ return output.toSpliced(position, 0, newValue);
138
+ }
139
+ if (currentValue?.[position] === void 0) return currentValue.toSpliced(position, 1, newValue);
140
+ return currentValue.toSpliced(position, 0, newValue);
141
+ }
142
+ return [...currentValue, newValue];
143
+ };
144
+ }
145
+
146
+ // src/build/typescript-builder.ts
13
147
  function findDataAttributesAndFunctions(node, sourceFile, foundDataAttributes = [], foundFunctions = []) {
14
148
  if (node.kind === ts.SyntaxKind.JsxAttribute) {
15
149
  const attribute = getAttributeValuePair(node, sourceFile);
@@ -81,18 +215,7 @@ function removeClientScriptInTSXFile(pathName, source) {
81
215
  }
82
216
  if (child.kind === ts.SyntaxKind.ImportDeclaration && child.pos >= clientDataStart) {
83
217
  const text = child.getText(source);
84
- child.forEachChild((child2) => {
85
- if (child2.kind === ts.SyntaxKind.StringLiteral) {
86
- const text2 = child2.getText(source);
87
- const importPath = text2.replace(/[\"\']/g, "");
88
- const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
89
- if (!isRelativeImport) return;
90
- clientImportsToReplace.push({
91
- old: importPath,
92
- new: path.join(path.dirname(pathName), importPath)
93
- });
94
- }
95
- });
218
+ clientImportsToReplace.push(...getImportsToAbsolutePaths(child, source, pathName));
96
219
  clientImportsToHoist.push(text);
97
220
  }
98
221
  });
@@ -108,18 +231,58 @@ function removeClientScriptInTSXFile(pathName, source) {
108
231
  clientDataStart
109
232
  };
110
233
  }
234
+ function getImportsToAbsolutePaths(child, source, pathName) {
235
+ const output = [];
236
+ child.forEachChild((child2) => {
237
+ if (child2.kind === ts.SyntaxKind.StringLiteral) {
238
+ const text = child2.getText(source);
239
+ const importPath = text.replace(/[\"\']/g, "");
240
+ const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
241
+ if (!isRelativeImport) return;
242
+ output.push({
243
+ old: importPath,
244
+ new: path2.join(path2.dirname(pathName), importPath)
245
+ });
246
+ }
247
+ });
248
+ return output;
249
+ }
250
+ function getXpineOnLoadFunction(pathName, source, onLoadFileResult) {
251
+ const value = {
252
+ imports: "",
253
+ fn: ""
254
+ };
255
+ source.forEachChild((child) => {
256
+ if (child.kind == ts.SyntaxKind.ImportDeclaration) {
257
+ let importText = child.getText(source);
258
+ const importOutput = getImportsToAbsolutePaths(child, source, pathName);
259
+ for (const importItem of importOutput) {
260
+ importText = importText.replace(importItem.old, importItem.new);
261
+ }
262
+ value.imports = importText + "\n" + value.imports;
263
+ }
264
+ if ([ts.SyntaxKind.FirstStatement, ts.SyntaxKind.FunctionDeclaration].includes(child.kind)) {
265
+ let text = child.getText(source);
266
+ if (text.includes("xpineOnLoad")) {
267
+ const body = child?.body?.getText(source) || "";
268
+ value.fn = value.fn + "\n" + body ? `(function() ${body})();` : "";
269
+ }
270
+ }
271
+ });
272
+ return value;
273
+ }
274
+ async function triggerXPineOnLoad(noCache = false) {
275
+ context.clear();
276
+ const xpineOnLoad = (await import(path2.join(config.distDir, `./__xpineOnLoad.js${noCache ? `?cache=${Date.now()}` : ""}`)))?.default;
277
+ if (xpineOnLoad) await xpineOnLoad();
278
+ }
111
279
 
112
280
  // src/scripts/build.ts
113
281
  import { globSync } from "glob";
114
282
  import postcss from "postcss";
115
283
  import tailwindPostcss from "@tailwindcss/postcss";
116
284
 
117
- // src/util/get-config.ts
118
- import path2 from "path";
119
-
120
- // src/util/require.ts
121
- import { createRequire } from "module";
122
- var require_default = createRequire(import.meta.url);
285
+ // src/util/paths.ts
123
286
  function getXPineDistDir() {
124
287
  const dir = import.meta.dirname;
125
288
  const splitDir = dir.split("/xpine/dist");
@@ -130,68 +293,6 @@ function getXPineDistDir() {
130
293
  return splitDir[0] + "/xpine/dist";
131
294
  }
132
295
 
133
- // src/util/get-config.ts
134
- var rootDir = process.cwd();
135
- function fromRoot(pathName) {
136
- if (!pathName) return rootDir;
137
- return path2.join(rootDir, pathName);
138
- }
139
- var userConfig = require_default(path2.join(process.cwd(), "./xpine.config.mjs")).default;
140
- var configDefaults = {
141
- rootDir: fromRoot(),
142
- srcDir: fromRoot("./src"),
143
- distDir: fromRoot("./dist"),
144
- packageJsonPath: fromRoot("package.json"),
145
- // We need to use getters here in the event someone wants to change folders, such as the dist folder
146
- get distPublicDir() {
147
- return path2.join(this.distDir, "./public");
148
- },
149
- get distPublicScriptsDir() {
150
- return path2.join(this.distPublicDir, "./scripts");
151
- },
152
- get distTempFolder() {
153
- return path2.join(this.distDir, "./temp");
154
- },
155
- get clientJSBundlePath() {
156
- return path2.join(this.distPublicScriptsDir, "./app.js");
157
- },
158
- get alpineDataPath() {
159
- return path2.join(this.distTempFolder, "./alpine-data.ts");
160
- },
161
- get serverDistDir() {
162
- return path2.join(this.distDir, "./server");
163
- },
164
- get serverDistAppPath() {
165
- return path2.join(this.serverDistDir, "./app.js");
166
- },
167
- // Important dirs/paths
168
- get pagesDir() {
169
- return path2.join(this.srcDir, "./pages");
170
- },
171
- get distPagesDir() {
172
- return path2.join(this.distDir, "./pages");
173
- },
174
- get publicDir() {
175
- return path2.join(this.srcDir, "./public");
176
- },
177
- get serverDir() {
178
- return path2.join(this.srcDir, "./server");
179
- },
180
- get runDir() {
181
- return path2.join(this.serverDir, "./run");
182
- },
183
- get serverAppPath() {
184
- return path2.join(this.serverDir, "./app.ts");
185
- },
186
- get globalCSSFile() {
187
- return path2.join(this.publicDir, "./styles/global.css");
188
- }
189
- };
190
- var config = {
191
- ...configDefaults,
192
- ...userConfig
193
- };
194
-
195
296
  // src/util/postcss/remove-layers.ts
196
297
  var plugin = (opts = {}) => {
197
298
  return {
@@ -265,13 +366,16 @@ function transformTSXFiles(componentData, pageConfigFiles) {
265
366
  ts2.ScriptTarget.Latest
266
367
  );
267
368
  const cleanedContent = removeClientScriptInTSXFile(args.path, source);
268
- const htmlImportStart = "import { html } from 'xpine';\n";
269
- const newContent = `${htmlImportStart}${cleanedContent.content}`;
369
+ const htmlImportStart = [
370
+ "import { html } from 'xpine';"
371
+ ];
372
+ const newContent = `${htmlImportStart.join("\n")}${cleanedContent.content}`;
270
373
  componentData.push({
271
374
  ...args,
272
375
  contents: `${htmlImportStart}${cleanedContent.fullContent}`,
273
376
  clientContent: cleanedContent.clientContent,
274
- configFiles: isAConfigFile(args?.path) ? null : getConfigFiles(args.path, pageConfigFiles)
377
+ configFiles: isAConfigFile(args?.path) ? null : getConfigFiles(args.path, pageConfigFiles),
378
+ source
275
379
  });
276
380
  return {
277
381
  contents: newContent,
@@ -286,7 +390,7 @@ function transformTSXFiles(componentData, pageConfigFiles) {
286
390
  import fs3 from "fs-extra";
287
391
  import path4 from "path";
288
392
  import builtinModules from "builtin-modules";
289
- function addDotJS(allPackages2, extensions2, isDev) {
393
+ function addDotJS(allPackages2, extensions2, isDev2) {
290
394
  const allPackagesIncludingNode = allPackages2.concat(builtinModules);
291
395
  return {
292
396
  name: "add-dot-js",
@@ -304,7 +408,7 @@ function addDotJS(allPackages2, extensions2, isDev) {
304
408
  }
305
409
  let outputPath = args.path + (existsAsFile ? "" : "/index") + ".js";
306
410
  outputPath = args.path.endsWith(".js") || args.path.endsWith(".mjs") ? args.path : outputPath;
307
- return { path: outputPath + (isDev ? `?cache=${Date.now()}` : ""), external: true };
411
+ return { path: outputPath + (isDev2 ? `?cache=${Date.now()}` : ""), external: true };
308
412
  }
309
413
  });
310
414
  }
@@ -341,23 +445,29 @@ var extensions = [".ts", ".tsx"];
341
445
  var packageJson = JSON.parse(fs5.readFileSync(config.packageJsonPath, "utf-8"));
342
446
  var allPackages = Object.keys(packageJson.devDependencies).concat(Object.keys(packageJson.dependencies));
343
447
  var xpineDistDir = getXPineDistDir();
344
- async function buildApp(isDev = false, removePreviousBuild = false) {
448
+ async function buildApp(args) {
449
+ const isDev2 = args?.isDev || false;
450
+ const removePreviousBuild2 = args?.removePreviousBuild || false;
451
+ const disableTailwind2 = args?.disableTailwind || false;
345
452
  try {
346
- if (removePreviousBuild) fs5.removeSync(config.distDir);
453
+ if (removePreviousBuild2) fs5.removeSync(config.distDir);
347
454
  const srcDirFiles = globSync(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
348
- const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev);
455
+ const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev2);
349
456
  const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
350
- await buildClientSideFiles([alpineDataFile], isDev);
457
+ await buildClientSideFiles([alpineDataFile], isDev2);
351
458
  fs5.removeSync(config.distTempFolder);
352
- await buildCSS();
459
+ await buildCSS(disableTailwind2);
353
460
  await buildPublicFolderSymlinks();
354
- if (!isDev) await buildFilesWithConfigs(componentData);
461
+ await buildOnLoadFile(componentData, isDev2);
462
+ if (!isDev2) await triggerXPineOnLoad();
463
+ if (!isDev2) await buildFilesWithConfigs(componentData);
464
+ if (!isDev2) context.clear();
355
465
  } catch (err) {
356
466
  console.error("Build failed");
357
467
  console.error(err);
358
468
  }
359
469
  }
360
- async function buildAppFiles(files, isDev) {
470
+ async function buildAppFiles(files, isDev2) {
361
471
  const componentData = [];
362
472
  const dataFiles = [];
363
473
  const pageConfigFiles = files.filter((file) => {
@@ -372,12 +482,12 @@ async function buildAppFiles(files, isDev) {
372
482
  platform: "node",
373
483
  outdir: config.distDir,
374
484
  bundle: true,
375
- sourcemap: isDev ? "inline" : false,
485
+ sourcemap: isDev2 ? "inline" : false,
376
486
  external: allPackages,
377
487
  jsx: "transform",
378
- minify: !isDev,
488
+ minify: !isDev2,
379
489
  plugins: [
380
- addDotJS(allPackages, extensions, isDev),
490
+ addDotJS(allPackages, extensions, isDev2),
381
491
  transformTSXFiles(componentData, pageConfigFiles),
382
492
  getDataFiles(dataFiles)
383
493
  ]
@@ -388,7 +498,7 @@ async function buildAppFiles(files, isDev) {
388
498
  dataFiles
389
499
  };
390
500
  }
391
- async function buildClientSideFiles(alpineDataFiles = [], isDev) {
501
+ async function buildClientSideFiles(alpineDataFiles = [], isDev2) {
392
502
  const tempFilePath = path5.join(config.distTempFolder, "./app.ts");
393
503
  fs5.ensureFileSync(tempFilePath);
394
504
  const pagesScriptsGlob = config.publicDir + "/scripts/pages/**/*.{js,ts}";
@@ -399,22 +509,22 @@ async function buildClientSideFiles(alpineDataFiles = [], isDev) {
399
509
  }
400
510
  );
401
511
  convertEntryPointsToSingleFile(alpineDataFiles.concat(clientFiles), tempFilePath);
402
- if (isDev) writeDevServerClientSideCode(tempFilePath);
512
+ if (isDev2) writeDevServerClientSideCode(tempFilePath);
403
513
  writeSpaClientSideCode(tempFilePath);
404
514
  await build({
405
515
  entryPoints: [tempFilePath],
406
516
  bundle: true,
407
517
  outdir: config.distPublicScriptsDir,
408
- minify: !isDev,
409
- sourcemap: isDev ? "inline" : false
518
+ minify: !isDev2,
519
+ sourcemap: isDev2 ? "inline" : false
410
520
  });
411
521
  const pagesFiles = globSync(pagesScriptsGlob);
412
522
  await build({
413
523
  entryPoints: pagesFiles || [],
414
524
  bundle: true,
415
525
  outdir: config.distPublicScriptsDir + "/pages",
416
- minify: !isDev,
417
- sourcemap: isDev ? "inline" : false
526
+ minify: !isDev2,
527
+ sourcemap: isDev2 ? "inline" : false
418
528
  });
419
529
  await logSize(config.distPublicDir, "client");
420
530
  }
@@ -445,12 +555,7 @@ async function buildAlpineDataFile(componentData, dataFiles) {
445
555
  };
446
556
  const componentsAndDataFiles = componentData.concat(dataFiles);
447
557
  for (const component of componentsAndDataFiles) {
448
- const sourceFile = ts3.createSourceFile(
449
- component.path,
450
- component.contents,
451
- ts3.ScriptTarget.Latest
452
- );
453
- const dataFunctionResult = findDataAttributesAndFunctions(sourceFile, sourceFile);
558
+ const dataFunctionResult = findDataAttributesAndFunctions(component.source, component.source);
454
559
  dataFunctionResults.foundDataAttributes.push(...dataFunctionResult.foundDataAttributes);
455
560
  const foundFunctionsWithPath = dataFunctionResult.foundFunctions.map((item) => {
456
561
  return {
@@ -474,11 +579,11 @@ async function buildAlpineDataFile(componentData, dataFiles) {
474
579
  fs5.writeFileSync(config.alpineDataPath, result);
475
580
  return config.alpineDataPath;
476
581
  }
477
- async function buildCSS() {
582
+ async function buildCSS(disableTailwind2) {
478
583
  const cssFiles = globSync(config.srcDir + "/**/*.css");
479
584
  for (const file of cssFiles) {
480
585
  const fileContents = fs5.readFileSync(file, "utf-8");
481
- const result = await postcss([tailwindPostcss(), remove_layers_default()]).process(fileContents, { from: file });
586
+ const result = disableTailwind2 ? fileContents : await postcss([tailwindPostcss(), remove_layers_default()]).process(fileContents, { from: file });
482
587
  const newPath = file.replace(config.srcDir, config.distDir);
483
588
  fs5.ensureFileSync(newPath);
484
589
  fs5.writeFileSync(newPath, result.css);
@@ -540,6 +645,7 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
540
645
  }
541
646
  const componentDynamicPaths = getComponentDynamicPaths(componentFileName);
542
647
  const componentFn = componentImport.default;
648
+ if (componentImport?.onInit) await componentImport.onInit();
543
649
  const outputPath = componentDynamicPaths?.length ? componentDynamicPaths.reduce((total, current) => {
544
650
  return total.replace(`/[${current}]`, "");
545
651
  }, path5.dirname(builtComponentPath)) : path5.dirname(builtComponentPath);
@@ -589,9 +695,57 @@ function getComponentDynamicPaths(componentPath) {
589
695
  }
590
696
  return output;
591
697
  }
698
+ async function buildOnLoadFile(componentData, isDev2) {
699
+ const onLoadFiles = [];
700
+ const onLoadFileResult = {
701
+ imports: "",
702
+ fn: ""
703
+ };
704
+ for (const component of componentData) {
705
+ if (component.contents.includes("xpineOnLoad")) {
706
+ onLoadFiles.push({
707
+ path: sourcePathToDistPath(component.path),
708
+ source: component.source
709
+ });
710
+ }
711
+ }
712
+ onLoadFiles.sort((a, b) => {
713
+ return a.path.localeCompare(b.path);
714
+ });
715
+ for (const file of onLoadFiles) {
716
+ const result = getXpineOnLoadFunction(file.path, file.source, onLoadFileResult);
717
+ onLoadFileResult.fn += result.fn;
718
+ onLoadFileResult.imports += result.imports;
719
+ }
720
+ const output = `
721
+ ${onLoadFileResult.imports}
722
+ import { context } from "xpine";
723
+ export default async function triggerOnLoad() {
724
+ ${onLoadFileResult.fn}
725
+ context.runArrayQueue();
726
+ }
727
+ `;
728
+ const onLoadFilePath = path5.join(config.distDir, "./__xpineOnLoad.ts");
729
+ fs5.writeFileSync(onLoadFilePath, output);
730
+ await build({
731
+ entryPoints: [onLoadFilePath],
732
+ format: "esm",
733
+ platform: "node",
734
+ outdir: config.distDir,
735
+ bundle: true,
736
+ sourcemap: isDev2 ? "inline" : false,
737
+ external: allPackages,
738
+ jsx: "transform",
739
+ minify: !isDev2,
740
+ plugins: [
741
+ addDotJS(allPackages, extensions, isDev2)
742
+ ]
743
+ });
744
+ }
592
745
 
593
746
  // src/scripts/xpine-build.ts
594
747
  import yargs from "yargs";
595
748
  import { hideBin } from "yargs/helpers";
596
749
  var argv = yargs(hideBin(process.argv)).argv;
597
- buildApp(argv?.isDev || false, argv?.removePreviousBuild || false);
750
+ var { isDev, removePreviousBuild, disableTailwind } = argv;
751
+ buildApp({ isDev, removePreviousBuild, disableTailwind });