xpine 0.0.24 → 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.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +291 -111
- package/dist/src/build/esbuild/transformTSXFiles.d.ts.map +1 -1
- package/dist/src/build/typescript-builder.d.ts +7 -0
- package/dist/src/build/typescript-builder.d.ts.map +1 -1
- package/dist/src/context.d.ts +18 -0
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/express.d.ts.map +1 -1
- package/dist/src/scripts/build.d.ts +13 -2
- package/dist/src/scripts/build.d.ts.map +1 -1
- package/dist/src/scripts/xpine-build.js +265 -111
- package/dist/src/scripts/xpine-dev.js +250 -97
- package/dist/src/util/hooks/onInit.d.ts +3 -0
- package/dist/src/util/hooks/onInit.d.ts.map +1 -0
- package/dist/src/util/paths.d.ts +2 -0
- package/dist/src/util/paths.d.ts.map +1 -0
- package/dist/src/util/require.d.ts +0 -1
- package/dist/src/util/require.d.ts.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -1
- package/types.ts +3 -1
- package/tests/e2e/alpine.spec.ts +0 -14
- package/tests/e2e/app-build.spec.ts +0 -73
- package/tests/e2e/spa.spec.ts +0 -23
- package/tests/e2e/tests-examples/demo-todo-app.spec.ts +0 -437
- package/tests/eslint.config.mjs +0 -27
- package/tests/package-lock.json +0 -8941
- package/tests/package.json +0 -89
- package/tests/playwright.config.ts +0 -81
- package/tests/tsconfig.json +0 -46
- package/tests/xpine.config.mjs +0 -1
|
@@ -11,12 +11,146 @@ import chokidar from "chokidar";
|
|
|
11
11
|
import path5 from "path";
|
|
12
12
|
import fs5 from "fs-extra";
|
|
13
13
|
import { build } from "esbuild";
|
|
14
|
-
import ts3 from "typescript";
|
|
15
14
|
|
|
16
15
|
// src/build/typescript-builder.ts
|
|
17
16
|
import ts from "typescript";
|
|
18
17
|
import fs from "fs-extra";
|
|
18
|
+
import path2 from "path";
|
|
19
|
+
|
|
20
|
+
// src/util/get-config.ts
|
|
19
21
|
import path from "path";
|
|
22
|
+
|
|
23
|
+
// src/util/require.ts
|
|
24
|
+
import { createRequire } from "module";
|
|
25
|
+
var require_default = createRequire(import.meta.url);
|
|
26
|
+
|
|
27
|
+
// src/util/get-config.ts
|
|
28
|
+
var rootDir = process.cwd();
|
|
29
|
+
function fromRoot(pathName) {
|
|
30
|
+
if (!pathName) return rootDir;
|
|
31
|
+
return path.join(rootDir, pathName);
|
|
32
|
+
}
|
|
33
|
+
var userConfig = require_default(path.join(process.cwd(), "./xpine.config.mjs")).default;
|
|
34
|
+
var configDefaults = {
|
|
35
|
+
rootDir: fromRoot(),
|
|
36
|
+
srcDir: fromRoot("./src"),
|
|
37
|
+
distDir: fromRoot("./dist"),
|
|
38
|
+
packageJsonPath: fromRoot("package.json"),
|
|
39
|
+
// We need to use getters here in the event someone wants to change folders, such as the dist folder
|
|
40
|
+
get distPublicDir() {
|
|
41
|
+
return path.join(this.distDir, "./public");
|
|
42
|
+
},
|
|
43
|
+
get distPublicScriptsDir() {
|
|
44
|
+
return path.join(this.distPublicDir, "./scripts");
|
|
45
|
+
},
|
|
46
|
+
get distTempFolder() {
|
|
47
|
+
return path.join(this.distDir, "./temp");
|
|
48
|
+
},
|
|
49
|
+
get clientJSBundlePath() {
|
|
50
|
+
return path.join(this.distPublicScriptsDir, "./app.js");
|
|
51
|
+
},
|
|
52
|
+
get alpineDataPath() {
|
|
53
|
+
return path.join(this.distTempFolder, "./alpine-data.ts");
|
|
54
|
+
},
|
|
55
|
+
get serverDistDir() {
|
|
56
|
+
return path.join(this.distDir, "./server");
|
|
57
|
+
},
|
|
58
|
+
get serverDistAppPath() {
|
|
59
|
+
return path.join(this.serverDistDir, "./app.js");
|
|
60
|
+
},
|
|
61
|
+
// Important dirs/paths
|
|
62
|
+
get pagesDir() {
|
|
63
|
+
return path.join(this.srcDir, "./pages");
|
|
64
|
+
},
|
|
65
|
+
get distPagesDir() {
|
|
66
|
+
return path.join(this.distDir, "./pages");
|
|
67
|
+
},
|
|
68
|
+
get publicDir() {
|
|
69
|
+
return path.join(this.srcDir, "./public");
|
|
70
|
+
},
|
|
71
|
+
get serverDir() {
|
|
72
|
+
return path.join(this.srcDir, "./server");
|
|
73
|
+
},
|
|
74
|
+
get runDir() {
|
|
75
|
+
return path.join(this.serverDir, "./run");
|
|
76
|
+
},
|
|
77
|
+
get serverAppPath() {
|
|
78
|
+
return path.join(this.serverDir, "./app.ts");
|
|
79
|
+
},
|
|
80
|
+
get globalCSSFile() {
|
|
81
|
+
return path.join(this.publicDir, "./styles/global.css");
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var config = {
|
|
85
|
+
...configDefaults,
|
|
86
|
+
...userConfig
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/context.ts
|
|
90
|
+
function createContext(value) {
|
|
91
|
+
let stateValue = value;
|
|
92
|
+
let arrayQueue = {};
|
|
93
|
+
return {
|
|
94
|
+
get(id) {
|
|
95
|
+
const val = stateValue[id];
|
|
96
|
+
if (Array.isArray(val)) return val.filter((item) => item !== void 0);
|
|
97
|
+
return val;
|
|
98
|
+
},
|
|
99
|
+
set(id, callback, defaultValue) {
|
|
100
|
+
if (!stateValue[id]) stateValue[id] = defaultValue ?? null;
|
|
101
|
+
stateValue[id] = callback(stateValue[id]);
|
|
102
|
+
},
|
|
103
|
+
clear() {
|
|
104
|
+
stateValue = {};
|
|
105
|
+
},
|
|
106
|
+
getAll() {
|
|
107
|
+
return stateValue;
|
|
108
|
+
},
|
|
109
|
+
getArrayQueue() {
|
|
110
|
+
return arrayQueue;
|
|
111
|
+
},
|
|
112
|
+
addToArray(id, value2, position) {
|
|
113
|
+
const output = {
|
|
114
|
+
id,
|
|
115
|
+
value: addToContextArray(value2, position),
|
|
116
|
+
position
|
|
117
|
+
};
|
|
118
|
+
if (!arrayQueue[id]) {
|
|
119
|
+
arrayQueue[id] = [output];
|
|
120
|
+
} else {
|
|
121
|
+
arrayQueue[id].push(output);
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
runArrayQueue() {
|
|
125
|
+
Object.keys(arrayQueue).forEach((key) => {
|
|
126
|
+
arrayQueue[key].sort((a, b) => {
|
|
127
|
+
return (a?.position ?? Infinity) - (b.position ?? Infinity);
|
|
128
|
+
});
|
|
129
|
+
for (const item of arrayQueue[key]) {
|
|
130
|
+
this.set(key, item.value, []);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
arrayQueue = {};
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
var context = createContext({});
|
|
138
|
+
function addToContextArray(newValue, position) {
|
|
139
|
+
return function(currentValue) {
|
|
140
|
+
if (!currentValue) return [newValue];
|
|
141
|
+
if (typeof position === "number") {
|
|
142
|
+
if (position > currentValue?.length) {
|
|
143
|
+
const output = [...currentValue, ...new Array(position + 1 - currentValue.length)];
|
|
144
|
+
return output.toSpliced(position, 0, newValue);
|
|
145
|
+
}
|
|
146
|
+
if (currentValue?.[position] === void 0) return currentValue.toSpliced(position, 1, newValue);
|
|
147
|
+
return currentValue.toSpliced(position, 0, newValue);
|
|
148
|
+
}
|
|
149
|
+
return [...currentValue, newValue];
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/build/typescript-builder.ts
|
|
20
154
|
function findDataAttributesAndFunctions(node, sourceFile, foundDataAttributes = [], foundFunctions = []) {
|
|
21
155
|
if (node.kind === ts.SyntaxKind.JsxAttribute) {
|
|
22
156
|
const attribute = getAttributeValuePair(node, sourceFile);
|
|
@@ -88,18 +222,7 @@ function removeClientScriptInTSXFile(pathName, source) {
|
|
|
88
222
|
}
|
|
89
223
|
if (child.kind === ts.SyntaxKind.ImportDeclaration && child.pos >= clientDataStart) {
|
|
90
224
|
const text = child.getText(source);
|
|
91
|
-
|
|
92
|
-
if (child2.kind === ts.SyntaxKind.StringLiteral) {
|
|
93
|
-
const text2 = child2.getText(source);
|
|
94
|
-
const importPath = text2.replace(/[\"\']/g, "");
|
|
95
|
-
const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
|
|
96
|
-
if (!isRelativeImport) return;
|
|
97
|
-
clientImportsToReplace.push({
|
|
98
|
-
old: importPath,
|
|
99
|
-
new: path.join(path.dirname(pathName), importPath)
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
});
|
|
225
|
+
clientImportsToReplace.push(...getImportsToAbsolutePaths(child, source, pathName));
|
|
103
226
|
clientImportsToHoist.push(text);
|
|
104
227
|
}
|
|
105
228
|
});
|
|
@@ -115,18 +238,58 @@ function removeClientScriptInTSXFile(pathName, source) {
|
|
|
115
238
|
clientDataStart
|
|
116
239
|
};
|
|
117
240
|
}
|
|
241
|
+
function getImportsToAbsolutePaths(child, source, pathName) {
|
|
242
|
+
const output = [];
|
|
243
|
+
child.forEachChild((child2) => {
|
|
244
|
+
if (child2.kind === ts.SyntaxKind.StringLiteral) {
|
|
245
|
+
const text = child2.getText(source);
|
|
246
|
+
const importPath = text.replace(/[\"\']/g, "");
|
|
247
|
+
const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
|
|
248
|
+
if (!isRelativeImport) return;
|
|
249
|
+
output.push({
|
|
250
|
+
old: importPath,
|
|
251
|
+
new: path2.join(path2.dirname(pathName), importPath)
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
return output;
|
|
256
|
+
}
|
|
257
|
+
function getXpineOnLoadFunction(pathName, source, onLoadFileResult) {
|
|
258
|
+
const value = {
|
|
259
|
+
imports: "",
|
|
260
|
+
fn: ""
|
|
261
|
+
};
|
|
262
|
+
source.forEachChild((child) => {
|
|
263
|
+
if (child.kind == ts.SyntaxKind.ImportDeclaration) {
|
|
264
|
+
let importText = child.getText(source);
|
|
265
|
+
const importOutput = getImportsToAbsolutePaths(child, source, pathName);
|
|
266
|
+
for (const importItem of importOutput) {
|
|
267
|
+
importText = importText.replace(importItem.old, importItem.new);
|
|
268
|
+
}
|
|
269
|
+
value.imports = importText + "\n" + value.imports;
|
|
270
|
+
}
|
|
271
|
+
if ([ts.SyntaxKind.FirstStatement, ts.SyntaxKind.FunctionDeclaration].includes(child.kind)) {
|
|
272
|
+
let text = child.getText(source);
|
|
273
|
+
if (text.includes("xpineOnLoad")) {
|
|
274
|
+
const body = child?.body?.getText(source) || "";
|
|
275
|
+
value.fn = value.fn + "\n" + body ? `(function() ${body})();` : "";
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
return value;
|
|
280
|
+
}
|
|
281
|
+
async function triggerXPineOnLoad(noCache = false) {
|
|
282
|
+
context.clear();
|
|
283
|
+
const xpineOnLoad = (await import(path2.join(config.distDir, `./__xpineOnLoad.js${noCache ? `?cache=${Date.now()}` : ""}`)))?.default;
|
|
284
|
+
if (xpineOnLoad) await xpineOnLoad();
|
|
285
|
+
}
|
|
118
286
|
|
|
119
287
|
// src/scripts/build.ts
|
|
120
288
|
import { globSync } from "glob";
|
|
121
289
|
import postcss from "postcss";
|
|
122
290
|
import tailwindPostcss from "@tailwindcss/postcss";
|
|
123
291
|
|
|
124
|
-
// src/util/
|
|
125
|
-
import path2 from "path";
|
|
126
|
-
|
|
127
|
-
// src/util/require.ts
|
|
128
|
-
import { createRequire } from "module";
|
|
129
|
-
var require_default = createRequire(import.meta.url);
|
|
292
|
+
// src/util/paths.ts
|
|
130
293
|
function getXPineDistDir() {
|
|
131
294
|
const dir = import.meta.dirname;
|
|
132
295
|
const splitDir = dir.split("/xpine/dist");
|
|
@@ -137,68 +300,6 @@ function getXPineDistDir() {
|
|
|
137
300
|
return splitDir[0] + "/xpine/dist";
|
|
138
301
|
}
|
|
139
302
|
|
|
140
|
-
// src/util/get-config.ts
|
|
141
|
-
var rootDir = process.cwd();
|
|
142
|
-
function fromRoot(pathName) {
|
|
143
|
-
if (!pathName) return rootDir;
|
|
144
|
-
return path2.join(rootDir, pathName);
|
|
145
|
-
}
|
|
146
|
-
var userConfig = require_default(path2.join(process.cwd(), "./xpine.config.mjs")).default;
|
|
147
|
-
var configDefaults = {
|
|
148
|
-
rootDir: fromRoot(),
|
|
149
|
-
srcDir: fromRoot("./src"),
|
|
150
|
-
distDir: fromRoot("./dist"),
|
|
151
|
-
packageJsonPath: fromRoot("package.json"),
|
|
152
|
-
// We need to use getters here in the event someone wants to change folders, such as the dist folder
|
|
153
|
-
get distPublicDir() {
|
|
154
|
-
return path2.join(this.distDir, "./public");
|
|
155
|
-
},
|
|
156
|
-
get distPublicScriptsDir() {
|
|
157
|
-
return path2.join(this.distPublicDir, "./scripts");
|
|
158
|
-
},
|
|
159
|
-
get distTempFolder() {
|
|
160
|
-
return path2.join(this.distDir, "./temp");
|
|
161
|
-
},
|
|
162
|
-
get clientJSBundlePath() {
|
|
163
|
-
return path2.join(this.distPublicScriptsDir, "./app.js");
|
|
164
|
-
},
|
|
165
|
-
get alpineDataPath() {
|
|
166
|
-
return path2.join(this.distTempFolder, "./alpine-data.ts");
|
|
167
|
-
},
|
|
168
|
-
get serverDistDir() {
|
|
169
|
-
return path2.join(this.distDir, "./server");
|
|
170
|
-
},
|
|
171
|
-
get serverDistAppPath() {
|
|
172
|
-
return path2.join(this.serverDistDir, "./app.js");
|
|
173
|
-
},
|
|
174
|
-
// Important dirs/paths
|
|
175
|
-
get pagesDir() {
|
|
176
|
-
return path2.join(this.srcDir, "./pages");
|
|
177
|
-
},
|
|
178
|
-
get distPagesDir() {
|
|
179
|
-
return path2.join(this.distDir, "./pages");
|
|
180
|
-
},
|
|
181
|
-
get publicDir() {
|
|
182
|
-
return path2.join(this.srcDir, "./public");
|
|
183
|
-
},
|
|
184
|
-
get serverDir() {
|
|
185
|
-
return path2.join(this.srcDir, "./server");
|
|
186
|
-
},
|
|
187
|
-
get runDir() {
|
|
188
|
-
return path2.join(this.serverDir, "./run");
|
|
189
|
-
},
|
|
190
|
-
get serverAppPath() {
|
|
191
|
-
return path2.join(this.serverDir, "./app.ts");
|
|
192
|
-
},
|
|
193
|
-
get globalCSSFile() {
|
|
194
|
-
return path2.join(this.publicDir, "./styles/global.css");
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
var config = {
|
|
198
|
-
...configDefaults,
|
|
199
|
-
...userConfig
|
|
200
|
-
};
|
|
201
|
-
|
|
202
303
|
// src/util/postcss/remove-layers.ts
|
|
203
304
|
var plugin = (opts = {}) => {
|
|
204
305
|
return {
|
|
@@ -272,13 +373,16 @@ function transformTSXFiles(componentData, pageConfigFiles) {
|
|
|
272
373
|
ts2.ScriptTarget.Latest
|
|
273
374
|
);
|
|
274
375
|
const cleanedContent = removeClientScriptInTSXFile(args.path, source);
|
|
275
|
-
const htmlImportStart =
|
|
276
|
-
|
|
376
|
+
const htmlImportStart = [
|
|
377
|
+
"import { html } from 'xpine';"
|
|
378
|
+
];
|
|
379
|
+
const newContent = `${htmlImportStart.join("\n")}${cleanedContent.content}`;
|
|
277
380
|
componentData.push({
|
|
278
381
|
...args,
|
|
279
382
|
contents: `${htmlImportStart}${cleanedContent.fullContent}`,
|
|
280
383
|
clientContent: cleanedContent.clientContent,
|
|
281
|
-
configFiles: isAConfigFile(args?.path) ? null : getConfigFiles(args.path, pageConfigFiles)
|
|
384
|
+
configFiles: isAConfigFile(args?.path) ? null : getConfigFiles(args.path, pageConfigFiles),
|
|
385
|
+
source
|
|
282
386
|
});
|
|
283
387
|
return {
|
|
284
388
|
contents: newContent,
|
|
@@ -348,7 +452,10 @@ var extensions = [".ts", ".tsx"];
|
|
|
348
452
|
var packageJson = JSON.parse(fs5.readFileSync(config.packageJsonPath, "utf-8"));
|
|
349
453
|
var allPackages = Object.keys(packageJson.devDependencies).concat(Object.keys(packageJson.dependencies));
|
|
350
454
|
var xpineDistDir = getXPineDistDir();
|
|
351
|
-
async function buildApp(
|
|
455
|
+
async function buildApp(args) {
|
|
456
|
+
const isDev = args?.isDev || false;
|
|
457
|
+
const removePreviousBuild = args?.removePreviousBuild || false;
|
|
458
|
+
const disableTailwind = args?.disableTailwind || false;
|
|
352
459
|
try {
|
|
353
460
|
if (removePreviousBuild) fs5.removeSync(config.distDir);
|
|
354
461
|
const srcDirFiles = globSync(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
|
|
@@ -356,9 +463,12 @@ async function buildApp(isDev = false, removePreviousBuild = false) {
|
|
|
356
463
|
const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
|
|
357
464
|
await buildClientSideFiles([alpineDataFile], isDev);
|
|
358
465
|
fs5.removeSync(config.distTempFolder);
|
|
359
|
-
await buildCSS();
|
|
466
|
+
await buildCSS(disableTailwind);
|
|
360
467
|
await buildPublicFolderSymlinks();
|
|
468
|
+
await buildOnLoadFile(componentData, isDev);
|
|
469
|
+
if (!isDev) await triggerXPineOnLoad();
|
|
361
470
|
if (!isDev) await buildFilesWithConfigs(componentData);
|
|
471
|
+
if (!isDev) context.clear();
|
|
362
472
|
} catch (err) {
|
|
363
473
|
console.error("Build failed");
|
|
364
474
|
console.error(err);
|
|
@@ -452,12 +562,7 @@ async function buildAlpineDataFile(componentData, dataFiles) {
|
|
|
452
562
|
};
|
|
453
563
|
const componentsAndDataFiles = componentData.concat(dataFiles);
|
|
454
564
|
for (const component of componentsAndDataFiles) {
|
|
455
|
-
const
|
|
456
|
-
component.path,
|
|
457
|
-
component.contents,
|
|
458
|
-
ts3.ScriptTarget.Latest
|
|
459
|
-
);
|
|
460
|
-
const dataFunctionResult = findDataAttributesAndFunctions(sourceFile, sourceFile);
|
|
565
|
+
const dataFunctionResult = findDataAttributesAndFunctions(component.source, component.source);
|
|
461
566
|
dataFunctionResults.foundDataAttributes.push(...dataFunctionResult.foundDataAttributes);
|
|
462
567
|
const foundFunctionsWithPath = dataFunctionResult.foundFunctions.map((item) => {
|
|
463
568
|
return {
|
|
@@ -481,11 +586,11 @@ async function buildAlpineDataFile(componentData, dataFiles) {
|
|
|
481
586
|
fs5.writeFileSync(config.alpineDataPath, result);
|
|
482
587
|
return config.alpineDataPath;
|
|
483
588
|
}
|
|
484
|
-
async function buildCSS() {
|
|
589
|
+
async function buildCSS(disableTailwind) {
|
|
485
590
|
const cssFiles = globSync(config.srcDir + "/**/*.css");
|
|
486
591
|
for (const file of cssFiles) {
|
|
487
592
|
const fileContents = fs5.readFileSync(file, "utf-8");
|
|
488
|
-
const result = await postcss([tailwindPostcss(), remove_layers_default()]).process(fileContents, { from: file });
|
|
593
|
+
const result = disableTailwind ? fileContents : await postcss([tailwindPostcss(), remove_layers_default()]).process(fileContents, { from: file });
|
|
489
594
|
const newPath = file.replace(config.srcDir, config.distDir);
|
|
490
595
|
fs5.ensureFileSync(newPath);
|
|
491
596
|
fs5.writeFileSync(newPath, result.css);
|
|
@@ -547,6 +652,7 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
547
652
|
}
|
|
548
653
|
const componentDynamicPaths = getComponentDynamicPaths(componentFileName);
|
|
549
654
|
const componentFn = componentImport.default;
|
|
655
|
+
if (componentImport?.onInit) await componentImport.onInit();
|
|
550
656
|
const outputPath = componentDynamicPaths?.length ? componentDynamicPaths.reduce((total, current) => {
|
|
551
657
|
return total.replace(`/[${current}]`, "");
|
|
552
658
|
}, path5.dirname(builtComponentPath)) : path5.dirname(builtComponentPath);
|
|
@@ -596,6 +702,53 @@ function getComponentDynamicPaths(componentPath) {
|
|
|
596
702
|
}
|
|
597
703
|
return output;
|
|
598
704
|
}
|
|
705
|
+
async function buildOnLoadFile(componentData, isDev) {
|
|
706
|
+
const onLoadFiles = [];
|
|
707
|
+
const onLoadFileResult = {
|
|
708
|
+
imports: "",
|
|
709
|
+
fn: ""
|
|
710
|
+
};
|
|
711
|
+
for (const component of componentData) {
|
|
712
|
+
if (component.contents.includes("xpineOnLoad")) {
|
|
713
|
+
onLoadFiles.push({
|
|
714
|
+
path: sourcePathToDistPath(component.path),
|
|
715
|
+
source: component.source
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
onLoadFiles.sort((a, b) => {
|
|
720
|
+
return a.path.localeCompare(b.path);
|
|
721
|
+
});
|
|
722
|
+
for (const file of onLoadFiles) {
|
|
723
|
+
const result = getXpineOnLoadFunction(file.path, file.source, onLoadFileResult);
|
|
724
|
+
onLoadFileResult.fn += result.fn;
|
|
725
|
+
onLoadFileResult.imports += result.imports;
|
|
726
|
+
}
|
|
727
|
+
const output = `
|
|
728
|
+
${onLoadFileResult.imports}
|
|
729
|
+
import { context } from "xpine";
|
|
730
|
+
export default async function triggerOnLoad() {
|
|
731
|
+
${onLoadFileResult.fn}
|
|
732
|
+
context.runArrayQueue();
|
|
733
|
+
}
|
|
734
|
+
`;
|
|
735
|
+
const onLoadFilePath = path5.join(config.distDir, "./__xpineOnLoad.ts");
|
|
736
|
+
fs5.writeFileSync(onLoadFilePath, output);
|
|
737
|
+
await build({
|
|
738
|
+
entryPoints: [onLoadFilePath],
|
|
739
|
+
format: "esm",
|
|
740
|
+
platform: "node",
|
|
741
|
+
outdir: config.distDir,
|
|
742
|
+
bundle: true,
|
|
743
|
+
sourcemap: isDev ? "inline" : false,
|
|
744
|
+
external: allPackages,
|
|
745
|
+
jsx: "transform",
|
|
746
|
+
minify: !isDev,
|
|
747
|
+
plugins: [
|
|
748
|
+
addDotJS(allPackages, extensions, isDev)
|
|
749
|
+
]
|
|
750
|
+
});
|
|
751
|
+
}
|
|
599
752
|
|
|
600
753
|
// src/runDevServer.ts
|
|
601
754
|
import path7 from "path";
|
|
@@ -636,7 +789,7 @@ await setupEnv();
|
|
|
636
789
|
async function runDevServer() {
|
|
637
790
|
process.env.NODE_ENV = "development";
|
|
638
791
|
const rebuildEmitter = createRebuildEmitter();
|
|
639
|
-
await buildApp(true);
|
|
792
|
+
await buildApp({ isDev: true });
|
|
640
793
|
const startServer = (await import(config.serverDistAppPath + `?cache=${Date.now()}`)).default;
|
|
641
794
|
let appServer = await startServer();
|
|
642
795
|
const watcher = chokidar.watch(config.srcDir, {
|
|
@@ -651,14 +804,14 @@ async function runDevServer() {
|
|
|
651
804
|
rebuildEmitter.emit("rebuild-server");
|
|
652
805
|
return;
|
|
653
806
|
}
|
|
654
|
-
await buildApp(true);
|
|
807
|
+
await buildApp({ isDev: true });
|
|
655
808
|
refreshEmitter.emit("refresh");
|
|
656
809
|
});
|
|
657
810
|
rebuildEmitter.on("done", async () => {
|
|
658
811
|
await rebuildServer();
|
|
659
812
|
});
|
|
660
813
|
async function rebuildServer() {
|
|
661
|
-
await buildApp(true);
|
|
814
|
+
await buildApp({ isDev: true });
|
|
662
815
|
const startServer2 = (await import(config.serverDistAppPath + `?cache=${Date.now()}`)).default;
|
|
663
816
|
appServer = await startServer2();
|
|
664
817
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onInit.d.ts","sourceRoot":"","sources":["../../../../src/util/hooks/onInit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI5C,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,uBAOhE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/util/paths.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,WAS9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"require.d.ts","sourceRoot":"","sources":["../../../src/util/require.ts"],"names":[],"mappings":";AAEA,wBAA8C
|
|
1
|
+
{"version":3,"file":"require.d.ts","sourceRoot":"","sources":["../../../src/util/require.ts"],"names":[],"mappings":";AAEA,wBAA8C"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Request, Response } from 'express';
|
|
2
|
+
import ts from 'typescript';
|
|
2
3
|
export type XPineConfig = {
|
|
3
4
|
[key: string]: any;
|
|
4
5
|
};
|
|
@@ -37,5 +38,6 @@ export type ComponentData = {
|
|
|
37
38
|
contents: string;
|
|
38
39
|
clientContent: string;
|
|
39
40
|
configFiles: string[];
|
|
41
|
+
source: ts.SourceFile;
|
|
40
42
|
};
|
|
41
43
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG;IACpC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,GAAG,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,EAAE,CAAC,CAAC,CAAC;IACrE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,aAAa,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;IACd,IAAI,EAAE,GAAG,CAAC;CACX,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC;CACvB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xpine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.27",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-secrets-manager": "^3.758.0",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"test:dev": "cd ./tests && npm run dev",
|
|
34
34
|
"test:start": "cd ./tests && npm run build && npm start",
|
|
35
35
|
"test:build": "cd ./tests && npm run build",
|
|
36
|
+
"test:build:dev": "cd ./tests && npm run build:dev",
|
|
36
37
|
"lint": "npx eslint",
|
|
37
38
|
"fix": "npx eslint --fix",
|
|
38
39
|
"release:patch": "npm run build && npm version patch && npm publish"
|
|
@@ -45,12 +46,14 @@
|
|
|
45
46
|
"type": "module",
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@eslint/js": "^9.24.0",
|
|
49
|
+
"@tailwindcss/oxide-darwin-arm64": "^4.1.3",
|
|
48
50
|
"@types/express": "^5.0.0",
|
|
49
51
|
"@types/node": "^22.13.5",
|
|
50
52
|
"@types/request-ip": "^0.0.41",
|
|
51
53
|
"@types/shelljs": "^0.8.15",
|
|
52
54
|
"@types/yargs": "^17.0.33",
|
|
53
55
|
"axios": "^1.8.4",
|
|
56
|
+
"lightningcss-darwin-arm64": "^1.29.3",
|
|
54
57
|
"typescript-eslint": "^8.29.0"
|
|
55
58
|
}
|
|
56
59
|
}
|
package/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Request, Response } from 'express';
|
|
2
|
+
import ts from 'typescript';
|
|
2
3
|
|
|
3
4
|
export type XPineConfig = {
|
|
4
5
|
[key: string]: any;
|
|
@@ -22,7 +23,7 @@ export type WrapperProps = {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export type ConfigFile = {
|
|
25
|
-
staticPaths?: boolean | (() => Promise<{ [key: string]: string}[]>);
|
|
26
|
+
staticPaths?: boolean | (() => Promise<{ [key: string]: string }[]>);
|
|
26
27
|
wrapper?: (props: WrapperProps) => Promise<any>;
|
|
27
28
|
data?: (req: ServerRequest) => Promise<any>;
|
|
28
29
|
}
|
|
@@ -43,4 +44,5 @@ export type ComponentData = {
|
|
|
43
44
|
contents: string;
|
|
44
45
|
clientContent: string;
|
|
45
46
|
configFiles: string[];
|
|
47
|
+
source: ts.SourceFile;
|
|
46
48
|
}
|
package/tests/e2e/alpine.spec.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { url } from '../playwright.config';
|
|
3
|
-
|
|
4
|
-
test('pathD button changes color on button click', async ({ page }) => {
|
|
5
|
-
await page.goto(url + '/my-path-a2/my-path-b2/my-path-c2/2');
|
|
6
|
-
const button = page.getByTestId('path-d-button');
|
|
7
|
-
const initialStyle = await button.getAttribute('style');
|
|
8
|
-
expect(initialStyle).toEqual('background-color: red');
|
|
9
|
-
await test.step('click button', async () => {
|
|
10
|
-
await button.click();
|
|
11
|
-
const newStyle = await button.getAttribute('style');
|
|
12
|
-
expect(newStyle).toEqual('background-color: blue');
|
|
13
|
-
});
|
|
14
|
-
});
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { config } from 'xpine';
|
|
3
|
-
import fs from 'fs-extra';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { url } from '../playwright.config';
|
|
6
|
-
|
|
7
|
-
test('app builds', async ({ page }) => {
|
|
8
|
-
await page.goto(url);
|
|
9
|
-
await expect(page.getByTestId('hello-world')).toHaveText('Hello world');
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test('home page uses same file wrapper', async ({ page }) => {
|
|
13
|
-
await page.goto(url);
|
|
14
|
-
await expect(page.getByTestId('home-page-wrapper')).toBeAttached();
|
|
15
|
-
expect(await page.getByTestId('base-config').count()).toEqual(0);
|
|
16
|
-
const title = await page.title();
|
|
17
|
-
expect(title).toEqual('Home page');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('same dir +config uses config', async ({ page }) => {
|
|
21
|
-
await page.goto(url + '/with-same-dir-wrapper');
|
|
22
|
-
await expect(page.getByTestId('base-config')).toBeAttached();
|
|
23
|
-
const title = await page.title();
|
|
24
|
-
expect(title).toEqual('Default title');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('dynamic paths with data in +config - path c', async ({ page }) => {
|
|
28
|
-
const result = await page.goto(url + '/my-path-a/my-path-b/1');
|
|
29
|
-
await expect(page.getByTestId('path-c-data')).toHaveText('sunt aut facere repellat provident occaecati excepturi optio reprehenderit');
|
|
30
|
-
await expect(page.getByTestId('path-c-patha')).toHaveText('my-path-a');
|
|
31
|
-
await expect(page.getByTestId('path-c-pathb')).toHaveText('my-path-b');
|
|
32
|
-
await expect(page.getByTestId('base-config')).toBeAttached();
|
|
33
|
-
const body = (await result.body()).toString();
|
|
34
|
-
expect(body).toContain('<!-- static -->');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test('dynamic inner paths with config in the component - path d', async ({ page }) => {
|
|
38
|
-
const result = await page.goto(url + '/my-path-a2/my-path-b2/my-path-c2/2');
|
|
39
|
-
await expect(page.getByTestId('path-d-data')).toHaveText('qui est esse');
|
|
40
|
-
await expect(page.getByTestId('path-d-patha')).toHaveText('my-path-a2');
|
|
41
|
-
await expect(page.getByTestId('path-d-pathb')).toHaveText('my-path-b2');
|
|
42
|
-
await expect(page.getByTestId('path-d-pathc')).toHaveText('my-path-c2');
|
|
43
|
-
await expect(page.getByTestId('base-config')).toBeAttached();
|
|
44
|
-
const body = (await result.body()).toString();
|
|
45
|
-
expect(body).toContain('<!-- static -->');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('static paths exist for dynamic page', async () => {
|
|
49
|
-
expect(fs.existsSync(path.join(config.distDir, './pages/my-path-a2/my-path-b2/my-path-c2/2/index.html'))).toEqual(true);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('boolean static path', async ({ page }) => {
|
|
53
|
-
const result = await page.goto(url + '/boolean-static-path');
|
|
54
|
-
const body = (await result.body()).toString();
|
|
55
|
-
expect(body).toContain('<!-- static -->');
|
|
56
|
-
|
|
57
|
-
expect(fs.existsSync(path.join(config.distDir, './pages/boolean-static-path/index.html'))).toEqual(true);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('inner static path override', async ({ page }) => {
|
|
61
|
-
expect(fs.existsSync(path.join(config.distDir, './pages/base-static-path/index.html'))).toEqual(true);
|
|
62
|
-
expect(fs.existsSync(path.join(config.distDir, './pages/base-static-path/non-static-path/index.html'))).toEqual(false);
|
|
63
|
-
|
|
64
|
-
const staticResult = await page.goto(url + '/base-static-path');
|
|
65
|
-
await expect(page.getByTestId('base-static-path')).toHaveText('My title');
|
|
66
|
-
const staticBody = (await staticResult.body()).toString();
|
|
67
|
-
expect(staticBody).toContain('<!-- static -->');
|
|
68
|
-
|
|
69
|
-
const nonStaticResult = await page.goto(url + '/base-static-path/non-static-path');
|
|
70
|
-
await expect(page.getByTestId('non-static-path')).toHaveText('My title');
|
|
71
|
-
const nonStaticBody = (await nonStaticResult.body()).toString();
|
|
72
|
-
expect(nonStaticBody).not.toContain('<!-- static -->');
|
|
73
|
-
});
|
package/tests/e2e/spa.spec.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { url } from '../playwright.config';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
test('sticky nav creates request for page contents and does not reload page', async ({ page }) => {
|
|
6
|
-
await page.goto(url);
|
|
7
|
-
const link = page.getByTestId('navbar-boolean-static-path');
|
|
8
|
-
const navbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
|
|
9
|
-
await link.click();
|
|
10
|
-
await page.waitForURL('**/boolean-static-path');
|
|
11
|
-
const newNavbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
|
|
12
|
-
expect(navbarNow).toEqual(newNavbarNow);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test('non-spa request for page contents reloads page', async ({ page }) => {
|
|
16
|
-
await page.goto(url);
|
|
17
|
-
const link = page.getByTestId('navbar-non-static-path-non-spa');
|
|
18
|
-
const navbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
|
|
19
|
-
await link.click();
|
|
20
|
-
await page.waitForURL('**/base-static-path/non-static-path');
|
|
21
|
-
const newNavbarNow = await page.getByTestId('navbar-now').getAttribute('data-now');
|
|
22
|
-
expect(navbarNow).not.toEqual(newNavbarNow);
|
|
23
|
-
});
|