xpine 0.0.48 → 0.0.50
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/README.md +28 -1
- package/dist/index.js +164 -29
- package/dist/src/build/css.d.ts.map +1 -1
- package/dist/src/express.d.ts.map +1 -1
- package/dist/src/scripts/build.d.ts +3 -1
- package/dist/src/scripts/build.d.ts.map +1 -1
- package/dist/src/scripts/xpine-build.js +141 -28
- package/dist/src/scripts/xpine-dev.js +141 -28
- package/dist/src/util/get-config.d.ts.map +1 -1
- package/dist/src/util/regex.d.ts +4 -0
- package/dist/src/util/regex.d.ts.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -426,4 +426,31 @@ setupEnv also supports AWS secrets manager. Simply add SECRETS_NAME=your_aws_sec
|
|
|
426
426
|
|
|
427
427
|
1. Add script to src/public/scripts/pages/your_script.ts
|
|
428
428
|
2. Import script into page HTML (e.g. `<script src="/scripts/pages/your_script.ts">`)
|
|
429
|
-
3. To unload event listeners, use `window.addEventListener('spa-update-page-url', () => { remove event listeners here})` in the code
|
|
429
|
+
3. To unload event listeners, use `window.addEventListener('spa-update-page-url', () => { remove event listeners here})` in the code
|
|
430
|
+
|
|
431
|
+
### Separate client side bundles
|
|
432
|
+
|
|
433
|
+
You can create separate client side bundles in xpine.config.mjs like this:
|
|
434
|
+
|
|
435
|
+
```
|
|
436
|
+
export default {
|
|
437
|
+
bundles: [
|
|
438
|
+
{
|
|
439
|
+
id: 'site',
|
|
440
|
+
excludePaths: [
|
|
441
|
+
// Excludes SecretPageData
|
|
442
|
+
'/**/pages/secret/**/*.{js,ts,tsx,jsx}',
|
|
443
|
+
'/**/pages/secret/*.{js,ts,tsx,jsx}',
|
|
444
|
+
],
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
id: 'secret-page',
|
|
448
|
+
includePaths: [
|
|
449
|
+
// Only uses Alpine data coming from paths in this directory
|
|
450
|
+
'/**/pages/secret/**/*.{js,ts,tsx,jsx}',
|
|
451
|
+
],
|
|
452
|
+
requireAuthentication: true, // Only authenticated users can access this .js file
|
|
453
|
+
}
|
|
454
|
+
]
|
|
455
|
+
}
|
|
456
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,8 @@ import chokidar from "chokidar";
|
|
|
9
9
|
import path6 from "path";
|
|
10
10
|
import fs7 from "fs-extra";
|
|
11
11
|
import { build } from "esbuild";
|
|
12
|
+
import micromatch from "micromatch";
|
|
13
|
+
import minifyXML from "minify-xml";
|
|
12
14
|
|
|
13
15
|
// src/build/typescript-builder.ts
|
|
14
16
|
import ts from "typescript";
|
|
@@ -30,6 +32,7 @@ function fromRoot(pathName) {
|
|
|
30
32
|
}
|
|
31
33
|
var userConfig = require_default(path.join(process.cwd(), "./xpine.config.mjs")).default;
|
|
32
34
|
var configDefaults = {
|
|
35
|
+
domain: "",
|
|
33
36
|
rootDir: fromRoot(),
|
|
34
37
|
srcDir: fromRoot("./src"),
|
|
35
38
|
distDir: fromRoot("./dist"),
|
|
@@ -77,6 +80,9 @@ var configDefaults = {
|
|
|
77
80
|
},
|
|
78
81
|
get globalCSSFile() {
|
|
79
82
|
return path.join(this.publicDir, "./styles/global.css");
|
|
83
|
+
},
|
|
84
|
+
get sitemapPath() {
|
|
85
|
+
return path.join(this.distPublicDir, "./sitemap.xml");
|
|
80
86
|
}
|
|
81
87
|
};
|
|
82
88
|
var config = {
|
|
@@ -322,6 +328,10 @@ var regex_default = {
|
|
|
322
328
|
isDynamicRoute: /\[(.*)\]/g,
|
|
323
329
|
endsWithTSX: /\.tsx$/,
|
|
324
330
|
endsWithJSX: /\.jsx$/,
|
|
331
|
+
endsWithJs: /\.js$/,
|
|
332
|
+
endsWithPageFileName: /\.(tsx|jsx)$/,
|
|
333
|
+
endsWithIndexNoExtension: /\/index$/,
|
|
334
|
+
endsWithIndex: /\/index\.(html|tsx|jsx|js|ts)$/,
|
|
325
335
|
endsWithFileName: /\.(html|tsx|jsx|js|ts)$/,
|
|
326
336
|
indexFile: /index\.(html|tsx|jsx|js|ts)$/g,
|
|
327
337
|
catchAllRoute: /\/_all_$/g,
|
|
@@ -643,9 +653,29 @@ async function verifyUserMiddleware(req, _res, next) {
|
|
|
643
653
|
}
|
|
644
654
|
next();
|
|
645
655
|
}
|
|
656
|
+
async function verifyAuthenticatedBundleMiddleware(req, res, next) {
|
|
657
|
+
if (!req?.originalUrl?.startsWith("/scripts/")) {
|
|
658
|
+
next();
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
const bundle = req?.originalUrl?.split("/")?.pop()?.split(".js")?.shift();
|
|
662
|
+
const foundBundle = config?.bundles?.find((bundleItem) => bundleItem?.id === bundle);
|
|
663
|
+
if (!foundBundle) {
|
|
664
|
+
next();
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
if (foundBundle?.requireAuthentication && !req?.user) {
|
|
668
|
+
res.status(403).json({
|
|
669
|
+
message: "Unauthenticated"
|
|
670
|
+
});
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
next();
|
|
674
|
+
}
|
|
646
675
|
async function createXPineRouter(app, beforeErrorRoute) {
|
|
647
|
-
app.use(express.static(config.distPublicDir));
|
|
648
676
|
app.use(verifyUserMiddleware);
|
|
677
|
+
app.use(verifyAuthenticatedBundleMiddleware);
|
|
678
|
+
app.use(express.static(config.distPublicDir));
|
|
649
679
|
app.use(requestIP.mw());
|
|
650
680
|
const { router, routeResults } = await createRouter();
|
|
651
681
|
app.use(function replaceableRouter(req, res, next) {
|
|
@@ -754,15 +784,19 @@ import tailwindPostcss from "@tailwindcss/postcss";
|
|
|
754
784
|
async function buildCSS(disableTailwind) {
|
|
755
785
|
const cssFiles = globSync2(config.srcDir + "/**/*.css");
|
|
756
786
|
for (const file of cssFiles) {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
787
|
+
try {
|
|
788
|
+
const fileContents = fs6.readFileSync(file, "utf-8");
|
|
789
|
+
let result = fileContents;
|
|
790
|
+
if (!disableTailwind) {
|
|
791
|
+
result = await postcss([add_breakpoint_data_default()]).process(fileContents, { from: file });
|
|
792
|
+
result = await postcss([tailwindPostcss(), remove_layers_default()]).process(result.css, { from: file });
|
|
793
|
+
}
|
|
794
|
+
const newPath = file.replace(config.srcDir, config.distDir);
|
|
795
|
+
fs6.ensureFileSync(newPath);
|
|
796
|
+
fs6.writeFileSync(newPath, result.css);
|
|
797
|
+
} catch (err) {
|
|
798
|
+
console.error(err);
|
|
762
799
|
}
|
|
763
|
-
const newPath = file.replace(config.srcDir, config.distDir);
|
|
764
|
-
fs6.ensureFileSync(newPath);
|
|
765
|
-
fs6.writeFileSync(newPath, result.css);
|
|
766
800
|
}
|
|
767
801
|
logSize(config.distPublicDir, "css");
|
|
768
802
|
}
|
|
@@ -780,14 +814,35 @@ async function buildApp(args) {
|
|
|
780
814
|
if (removePreviousBuild) fs7.removeSync(config.distDir);
|
|
781
815
|
const srcDirFiles = globSync3(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
|
|
782
816
|
const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev2);
|
|
783
|
-
const
|
|
784
|
-
|
|
817
|
+
const clientSideBundles = [];
|
|
818
|
+
if (config?.bundles?.length) {
|
|
819
|
+
for (const bundle of config.bundles) {
|
|
820
|
+
const matchingComponentData = componentData?.filter((item) => {
|
|
821
|
+
return !micromatch([item.path], bundle?.excludePaths || [])?.length;
|
|
822
|
+
})?.filter((item) => {
|
|
823
|
+
if (!bundle?.includePaths?.length) return true;
|
|
824
|
+
return micromatch([item.path], bundle?.includePaths || [])?.length;
|
|
825
|
+
});
|
|
826
|
+
const matchingDataFiles = dataFiles?.filter((item) => {
|
|
827
|
+
return !micromatch([item.path], bundle?.excludePaths || [])?.length;
|
|
828
|
+
})?.filter((item) => {
|
|
829
|
+
if (!bundle?.includePaths?.length) return true;
|
|
830
|
+
return micromatch([item.path], bundle?.includePaths || [])?.length;
|
|
831
|
+
});
|
|
832
|
+
const alpineDataFile = await buildAlpineDataFile(matchingComponentData, matchingDataFiles, bundle.id);
|
|
833
|
+
await buildClientSideFiles([alpineDataFile], isDev2, `./${bundle.id}.ts`, bundle.id);
|
|
834
|
+
}
|
|
835
|
+
} else {
|
|
836
|
+
const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
|
|
837
|
+
await buildClientSideFiles([alpineDataFile, ...clientSideBundles], isDev2);
|
|
838
|
+
}
|
|
785
839
|
fs7.removeSync(config.distTempFolder);
|
|
786
840
|
await buildCSS(disableTailwind);
|
|
787
841
|
await buildPublicFolderSymlinks();
|
|
788
842
|
await buildOnLoadFile(componentData, isDev2);
|
|
789
843
|
if (!isDev2) await triggerXPineOnLoad();
|
|
790
844
|
if (!isDev2) await buildFilesWithConfigs(componentData);
|
|
845
|
+
if (!isDev2) buildSitemap();
|
|
791
846
|
if (!isDev2) context.clear();
|
|
792
847
|
} catch (err) {
|
|
793
848
|
console.error("Build failed");
|
|
@@ -825,8 +880,8 @@ async function buildAppFiles(files, isDev2) {
|
|
|
825
880
|
dataFiles
|
|
826
881
|
};
|
|
827
882
|
}
|
|
828
|
-
async function buildClientSideFiles(alpineDataFiles = [], isDev2) {
|
|
829
|
-
const tempFilePath = path6.join(config.distTempFolder, "./app.ts");
|
|
883
|
+
async function buildClientSideFiles(alpineDataFiles = [], isDev2, tempClientSidePath, id) {
|
|
884
|
+
const tempFilePath = path6.join(config.distTempFolder, tempClientSidePath || "./app.ts");
|
|
830
885
|
fs7.ensureFileSync(tempFilePath);
|
|
831
886
|
const pagesScriptsGlob = config.publicDir + "/scripts/pages/**/*.{js,ts}";
|
|
832
887
|
const clientFiles = globSync3(
|
|
@@ -853,7 +908,7 @@ async function buildClientSideFiles(alpineDataFiles = [], isDev2) {
|
|
|
853
908
|
minify: !isDev2,
|
|
854
909
|
sourcemap: isDev2 ? "inline" : false
|
|
855
910
|
});
|
|
856
|
-
await logSize(config.distPublicDir, "client");
|
|
911
|
+
await logSize(config.distPublicDir, id ? `client bundle: ${id}.js` : "client bundle: app.js");
|
|
857
912
|
}
|
|
858
913
|
function writeDevServerClientSideCode(tempFilePath) {
|
|
859
914
|
const devServerPath = path6.join(xpineDistDir, "./src/static/dev-server.js");
|
|
@@ -865,7 +920,7 @@ function writeSpaClientSideCode(tempFilePath) {
|
|
|
865
920
|
const content = fs7.readFileSync(spaPath, "utf-8");
|
|
866
921
|
fs7.appendFileSync(tempFilePath, "\n" + content);
|
|
867
922
|
}
|
|
868
|
-
async function buildAlpineDataFile(componentData, dataFiles) {
|
|
923
|
+
async function buildAlpineDataFile(componentData, dataFiles, bundleID) {
|
|
869
924
|
const output = {
|
|
870
925
|
imports: [
|
|
871
926
|
"import Alpine from 'alpinejs';"
|
|
@@ -909,9 +964,16 @@ async function buildAlpineDataFile(componentData, dataFiles) {
|
|
|
909
964
|
output.code.push(`Alpine.data('${dataFunction.name}', ${dataFunction.name});`);
|
|
910
965
|
}
|
|
911
966
|
const result = output.imports.join("\n") + "\n" + output.code.join("\n") + "\n" + output.end.join("\n");
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
967
|
+
if (bundleID) {
|
|
968
|
+
const bundlePath = path6.join(config.distTempFolder, `./alpine-data-${bundleID}.ts`);
|
|
969
|
+
fs7.ensureFileSync(bundlePath);
|
|
970
|
+
fs7.writeFileSync(bundlePath, result);
|
|
971
|
+
return bundlePath;
|
|
972
|
+
} else {
|
|
973
|
+
fs7.ensureFileSync(config.alpineDataPath);
|
|
974
|
+
fs7.writeFileSync(config.alpineDataPath, result);
|
|
975
|
+
return config.alpineDataPath;
|
|
976
|
+
}
|
|
915
977
|
}
|
|
916
978
|
async function buildPublicFolderSymlinks() {
|
|
917
979
|
const files = globSync3(config.publicDir + "/**/*.*", {
|
|
@@ -975,17 +1037,28 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
975
1037
|
const componentDynamicPaths = getComponentDynamicPaths(componentFileName);
|
|
976
1038
|
const componentFn = componentImport.default;
|
|
977
1039
|
if (componentImport?.onInit) await componentImport.onInit();
|
|
978
|
-
const outputPath =
|
|
979
|
-
|
|
980
|
-
}, path6.dirname(builtComponentPath)) : path6.dirname(builtComponentPath);
|
|
1040
|
+
const outputPath = determineOutputPathForStaticPath(builtComponentPath, componentDynamicPaths);
|
|
1041
|
+
if (!outputPath) return;
|
|
981
1042
|
if (typeof config2?.staticPaths === "boolean") {
|
|
982
1043
|
const urlPath = filePathToURLPath(outputPath);
|
|
983
1044
|
try {
|
|
984
|
-
const req = {
|
|
985
|
-
|
|
986
|
-
|
|
1045
|
+
const req = {
|
|
1046
|
+
params: {},
|
|
1047
|
+
route: {
|
|
1048
|
+
path: urlPath
|
|
1049
|
+
},
|
|
1050
|
+
url: urlPath
|
|
1051
|
+
};
|
|
1052
|
+
let data = config2?.data ? await config2.data(req) : null;
|
|
1053
|
+
data = {
|
|
1054
|
+
...data,
|
|
1055
|
+
routePath: urlPath
|
|
1056
|
+
};
|
|
1057
|
+
const staticComponentOutput = await componentFn({ data, routePath: urlPath, req });
|
|
1058
|
+
const htmlOutputPath = path6.join(outputPath, "./index.html");
|
|
1059
|
+
fs7.ensureFileSync(htmlOutputPath);
|
|
987
1060
|
fs7.writeFileSync(
|
|
988
|
-
|
|
1061
|
+
htmlOutputPath,
|
|
989
1062
|
doctypeHTML + (config2?.wrapper ? await config2.wrapper({ req, children: staticComponentOutput, config: config2, data, routePath: urlPath }) : staticComponentOutput) + staticComment
|
|
990
1063
|
);
|
|
991
1064
|
} catch (err) {
|
|
@@ -996,14 +1069,19 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
996
1069
|
const dynamicPaths = await config2.staticPaths();
|
|
997
1070
|
for (const dynamicPath of dynamicPaths) {
|
|
998
1071
|
try {
|
|
1072
|
+
const updatedOutDir = path6.join(outputPath, `./${componentDynamicPaths.map((key) => dynamicPath[key]).join("/")}`);
|
|
1073
|
+
const urlPath = filePathToURLPath(updatedOutDir);
|
|
999
1074
|
const req = {
|
|
1000
1075
|
params: {
|
|
1001
1076
|
...componentDynamicPaths?.length ? dynamicPath : {}
|
|
1002
|
-
}
|
|
1077
|
+
},
|
|
1078
|
+
route: {
|
|
1079
|
+
path: urlPath
|
|
1080
|
+
},
|
|
1081
|
+
url: urlPath
|
|
1003
1082
|
};
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
const data = config2?.data ? await config2.data(req) : null;
|
|
1083
|
+
let data = config2?.data ? await config2.data(req) : null;
|
|
1084
|
+
data = { ...data, routePath: urlPath };
|
|
1007
1085
|
const staticComponentOutput = await componentFn({ req, data, routePath: urlPath });
|
|
1008
1086
|
fs7.ensureDirSync(updatedOutDir);
|
|
1009
1087
|
fs7.writeFileSync(
|
|
@@ -1017,6 +1095,20 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
1017
1095
|
}
|
|
1018
1096
|
}
|
|
1019
1097
|
}
|
|
1098
|
+
function determineOutputPathForStaticPath(builtComponentPath, componentDynamicPaths) {
|
|
1099
|
+
if (componentDynamicPaths?.length) {
|
|
1100
|
+
return componentDynamicPaths.reduce((total, current) => {
|
|
1101
|
+
return total.replace(`/[${current}]`, "");
|
|
1102
|
+
}, path6.dirname(builtComponentPath));
|
|
1103
|
+
} else {
|
|
1104
|
+
if (builtComponentPath?.match(regex_default.endsWithIndex)) {
|
|
1105
|
+
return path6.dirname(builtComponentPath);
|
|
1106
|
+
} else {
|
|
1107
|
+
if (!builtComponentPath.match(regex_default.endsWithJs)) return null;
|
|
1108
|
+
return builtComponentPath.replace(regex_default.endsWithJs, "");
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1020
1112
|
function getComponentDynamicPaths(componentPath) {
|
|
1021
1113
|
const matches = [...componentPath.matchAll(regex_default.dynamicRoutes)].concat([...componentPath.matchAll(regex_default.catchAllRoute)]);
|
|
1022
1114
|
if (!matches?.length) return null;
|
|
@@ -1073,6 +1165,47 @@ async function buildOnLoadFile(componentData, isDev2) {
|
|
|
1073
1165
|
]
|
|
1074
1166
|
});
|
|
1075
1167
|
}
|
|
1168
|
+
async function buildSitemap() {
|
|
1169
|
+
if (!config?.sitemap) return;
|
|
1170
|
+
const staticPages = globSync3(`${config.distPagesDir}/**/*.html`) || [];
|
|
1171
|
+
const dynamicPages = globSync3(`${config.pagesDir}/**/*.{jsx,tsx}`) || [];
|
|
1172
|
+
const allPages = staticPages.concat(dynamicPages);
|
|
1173
|
+
const filteredPages = allPages.filter((filePath) => {
|
|
1174
|
+
return !micromatch([filePath], config.sitemap?.excludePaths || [])?.length;
|
|
1175
|
+
});
|
|
1176
|
+
const pages = filteredPages.map((filePath) => {
|
|
1177
|
+
const replacedExtensions = filePath.replace(regex_default.endsWithFileName, "");
|
|
1178
|
+
const replacedPagesPath = replacedExtensions.replace(config.pagesDir, "");
|
|
1179
|
+
const replacedDistPath = replacedPagesPath.replace(config.distPagesDir, "");
|
|
1180
|
+
const replacedIndex = replacedDistPath.replace(regex_default.endsWithIndexNoExtension, "");
|
|
1181
|
+
if (replacedIndex === "") return "/";
|
|
1182
|
+
return replacedIndex;
|
|
1183
|
+
}).filter((filePath) => {
|
|
1184
|
+
return !filePath.includes("+config");
|
|
1185
|
+
});
|
|
1186
|
+
const sitemap = `
|
|
1187
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
1188
|
+
<urlset
|
|
1189
|
+
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
1190
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
1191
|
+
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
|
|
1192
|
+
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
|
|
1193
|
+
xmlns:xhtml="http://www.w3.org/1999/xhtml"
|
|
1194
|
+
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
|
|
1195
|
+
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"
|
|
1196
|
+
>
|
|
1197
|
+
${pages.map((page) => {
|
|
1198
|
+
return `
|
|
1199
|
+
<url>
|
|
1200
|
+
<loc>${config?.domain ? `https://${config.domain}${page}` : page}</loc>
|
|
1201
|
+
</url>
|
|
1202
|
+
`;
|
|
1203
|
+
}).join("\n")}
|
|
1204
|
+
</urlset>
|
|
1205
|
+
`;
|
|
1206
|
+
fs7.ensureFileSync(config.sitemapPath);
|
|
1207
|
+
fs7.writeFileSync(config.sitemapPath, minifyXML(sitemap));
|
|
1208
|
+
}
|
|
1076
1209
|
|
|
1077
1210
|
// src/runDevServer.ts
|
|
1078
1211
|
import path8 from "path";
|
|
@@ -1229,12 +1362,14 @@ export {
|
|
|
1229
1362
|
buildFilesWithConfigs,
|
|
1230
1363
|
buildOnLoadFile,
|
|
1231
1364
|
buildPublicFolderSymlinks,
|
|
1365
|
+
buildSitemap,
|
|
1232
1366
|
buildStaticFiles,
|
|
1233
1367
|
config,
|
|
1234
1368
|
context,
|
|
1235
1369
|
createContext,
|
|
1236
1370
|
createRouter,
|
|
1237
1371
|
createXPineRouter,
|
|
1372
|
+
determineOutputPathForStaticPath,
|
|
1238
1373
|
filePathToURLPath,
|
|
1239
1374
|
fromRoot,
|
|
1240
1375
|
getComponentDynamicPaths,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../../../src/build/css.ts"],"names":[],"mappings":"AAUA,wBAAsB,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../../../src/build/css.ts"],"names":[],"mappings":"AAUA,wBAAsB,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,iBAoBvD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAgB,OAAO,EAAqB,MAAM,SAAS,CAAC;AAqJ5E,wBAAsB,YAAY;;;GAkCjC;
|
|
1
|
+
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAgB,OAAO,EAAqB,MAAM,SAAS,CAAC;AAqJ5E,wBAAsB,YAAY;;;GAkCjC;AAsCD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,iBA0B1F;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,KAAK,CAanG;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,OAAc,UAQzE"}
|
|
@@ -6,14 +6,16 @@ type BuildAppArgs = {
|
|
|
6
6
|
};
|
|
7
7
|
export declare function buildApp(args: BuildAppArgs): Promise<void>;
|
|
8
8
|
export declare function buildPublicFolderSymlinks(): Promise<void>;
|
|
9
|
-
export declare function logSize(pathName: string, type:
|
|
9
|
+
export declare function logSize(pathName: string, type: string, validExtensions?: string[]): Promise<void>;
|
|
10
10
|
export declare function buildFilesWithConfigs(componentData: ComponentData[]): Promise<void>;
|
|
11
11
|
export declare function buildStaticFiles(config: ConfigFile, component: ComponentData, componentImport: any, builtComponentPath: string): Promise<void>;
|
|
12
|
+
export declare function determineOutputPathForStaticPath(builtComponentPath: string, componentDynamicPaths?: string[]): string;
|
|
12
13
|
export declare function getComponentDynamicPaths(componentPath: string): string[];
|
|
13
14
|
export type OnLoadFileResult = {
|
|
14
15
|
imports: string;
|
|
15
16
|
fn: string;
|
|
16
17
|
};
|
|
17
18
|
export declare function buildOnLoadFile(componentData: ComponentData[], isDev?: boolean): Promise<void>;
|
|
19
|
+
export declare function buildSitemap(): Promise<void>;
|
|
18
20
|
export {};
|
|
19
21
|
//# sourceMappingURL=build.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/scripts/build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/scripts/build.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,UAAU,EAA2B,aAAa,EAAE,MAAM,aAAa,CAAC;AAajF,KAAK,YAAY,GAAG;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAA;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,YAAY,iBAgDhD;AAwJD,wBAAsB,yBAAyB,kBAgB9C;AAED,wBAAsB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,WAAkB,iBAa9F;AAED,wBAAsB,qBAAqB,CAAC,aAAa,EAAE,aAAa,EAAE,iBAezE;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,GAAG,EAAE,kBAAkB,EAAE,MAAM,iBA2FpI;AAED,wBAAgB,gCAAgC,CAAC,kBAAkB,EAAE,MAAM,EAAE,qBAAqB,CAAC,EAAE,MAAM,EAAE,UAe5G;AAED,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,CAQxE;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAA;AAGD,wBAAsB,eAAe,CAAC,aAAa,EAAE,aAAa,EAAE,EAAE,KAAK,CAAC,EAAE,OAAO,iBAoDpF;AAED,wBAAsB,YAAY,kBA0CjC"}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import path5 from "path";
|
|
5
5
|
import fs7 from "fs-extra";
|
|
6
6
|
import { build } from "esbuild";
|
|
7
|
+
import micromatch from "micromatch";
|
|
8
|
+
import minifyXML from "minify-xml";
|
|
7
9
|
|
|
8
10
|
// src/build/typescript-builder.ts
|
|
9
11
|
import ts from "typescript";
|
|
@@ -25,6 +27,7 @@ function fromRoot(pathName) {
|
|
|
25
27
|
}
|
|
26
28
|
var userConfig = require_default(path.join(process.cwd(), "./xpine.config.mjs")).default;
|
|
27
29
|
var configDefaults = {
|
|
30
|
+
domain: "",
|
|
28
31
|
rootDir: fromRoot(),
|
|
29
32
|
srcDir: fromRoot("./src"),
|
|
30
33
|
distDir: fromRoot("./dist"),
|
|
@@ -72,6 +75,9 @@ var configDefaults = {
|
|
|
72
75
|
},
|
|
73
76
|
get globalCSSFile() {
|
|
74
77
|
return path.join(this.publicDir, "./styles/global.css");
|
|
78
|
+
},
|
|
79
|
+
get sitemapPath() {
|
|
80
|
+
return path.join(this.distPublicDir, "./sitemap.xml");
|
|
75
81
|
}
|
|
76
82
|
};
|
|
77
83
|
var config = {
|
|
@@ -317,6 +323,10 @@ var regex_default = {
|
|
|
317
323
|
isDynamicRoute: /\[(.*)\]/g,
|
|
318
324
|
endsWithTSX: /\.tsx$/,
|
|
319
325
|
endsWithJSX: /\.jsx$/,
|
|
326
|
+
endsWithJs: /\.js$/,
|
|
327
|
+
endsWithPageFileName: /\.(tsx|jsx)$/,
|
|
328
|
+
endsWithIndexNoExtension: /\/index$/,
|
|
329
|
+
endsWithIndex: /\/index\.(html|tsx|jsx|js|ts)$/,
|
|
320
330
|
endsWithFileName: /\.(html|tsx|jsx|js|ts)$/,
|
|
321
331
|
indexFile: /index\.(html|tsx|jsx|js|ts)$/g,
|
|
322
332
|
catchAllRoute: /\/_all_$/g,
|
|
@@ -547,15 +557,19 @@ import tailwindPostcss from "@tailwindcss/postcss";
|
|
|
547
557
|
async function buildCSS(disableTailwind2) {
|
|
548
558
|
const cssFiles = globSync2(config.srcDir + "/**/*.css");
|
|
549
559
|
for (const file of cssFiles) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
560
|
+
try {
|
|
561
|
+
const fileContents = fs6.readFileSync(file, "utf-8");
|
|
562
|
+
let result = fileContents;
|
|
563
|
+
if (!disableTailwind2) {
|
|
564
|
+
result = await postcss([add_breakpoint_data_default()]).process(fileContents, { from: file });
|
|
565
|
+
result = await postcss([tailwindPostcss(), remove_layers_default()]).process(result.css, { from: file });
|
|
566
|
+
}
|
|
567
|
+
const newPath = file.replace(config.srcDir, config.distDir);
|
|
568
|
+
fs6.ensureFileSync(newPath);
|
|
569
|
+
fs6.writeFileSync(newPath, result.css);
|
|
570
|
+
} catch (err) {
|
|
571
|
+
console.error(err);
|
|
555
572
|
}
|
|
556
|
-
const newPath = file.replace(config.srcDir, config.distDir);
|
|
557
|
-
fs6.ensureFileSync(newPath);
|
|
558
|
-
fs6.writeFileSync(newPath, result.css);
|
|
559
573
|
}
|
|
560
574
|
logSize(config.distPublicDir, "css");
|
|
561
575
|
}
|
|
@@ -573,14 +587,35 @@ async function buildApp(args) {
|
|
|
573
587
|
if (removePreviousBuild2) fs7.removeSync(config.distDir);
|
|
574
588
|
const srcDirFiles = globSync3(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
|
|
575
589
|
const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev3);
|
|
576
|
-
const
|
|
577
|
-
|
|
590
|
+
const clientSideBundles = [];
|
|
591
|
+
if (config?.bundles?.length) {
|
|
592
|
+
for (const bundle of config.bundles) {
|
|
593
|
+
const matchingComponentData = componentData?.filter((item) => {
|
|
594
|
+
return !micromatch([item.path], bundle?.excludePaths || [])?.length;
|
|
595
|
+
})?.filter((item) => {
|
|
596
|
+
if (!bundle?.includePaths?.length) return true;
|
|
597
|
+
return micromatch([item.path], bundle?.includePaths || [])?.length;
|
|
598
|
+
});
|
|
599
|
+
const matchingDataFiles = dataFiles?.filter((item) => {
|
|
600
|
+
return !micromatch([item.path], bundle?.excludePaths || [])?.length;
|
|
601
|
+
})?.filter((item) => {
|
|
602
|
+
if (!bundle?.includePaths?.length) return true;
|
|
603
|
+
return micromatch([item.path], bundle?.includePaths || [])?.length;
|
|
604
|
+
});
|
|
605
|
+
const alpineDataFile = await buildAlpineDataFile(matchingComponentData, matchingDataFiles, bundle.id);
|
|
606
|
+
await buildClientSideFiles([alpineDataFile], isDev3, `./${bundle.id}.ts`, bundle.id);
|
|
607
|
+
}
|
|
608
|
+
} else {
|
|
609
|
+
const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
|
|
610
|
+
await buildClientSideFiles([alpineDataFile, ...clientSideBundles], isDev3);
|
|
611
|
+
}
|
|
578
612
|
fs7.removeSync(config.distTempFolder);
|
|
579
613
|
await buildCSS(disableTailwind2);
|
|
580
614
|
await buildPublicFolderSymlinks();
|
|
581
615
|
await buildOnLoadFile(componentData, isDev3);
|
|
582
616
|
if (!isDev3) await triggerXPineOnLoad();
|
|
583
617
|
if (!isDev3) await buildFilesWithConfigs(componentData);
|
|
618
|
+
if (!isDev3) buildSitemap();
|
|
584
619
|
if (!isDev3) context.clear();
|
|
585
620
|
} catch (err) {
|
|
586
621
|
console.error("Build failed");
|
|
@@ -618,8 +653,8 @@ async function buildAppFiles(files, isDev3) {
|
|
|
618
653
|
dataFiles
|
|
619
654
|
};
|
|
620
655
|
}
|
|
621
|
-
async function buildClientSideFiles(alpineDataFiles = [], isDev3) {
|
|
622
|
-
const tempFilePath = path5.join(config.distTempFolder, "./app.ts");
|
|
656
|
+
async function buildClientSideFiles(alpineDataFiles = [], isDev3, tempClientSidePath, id) {
|
|
657
|
+
const tempFilePath = path5.join(config.distTempFolder, tempClientSidePath || "./app.ts");
|
|
623
658
|
fs7.ensureFileSync(tempFilePath);
|
|
624
659
|
const pagesScriptsGlob = config.publicDir + "/scripts/pages/**/*.{js,ts}";
|
|
625
660
|
const clientFiles = globSync3(
|
|
@@ -646,7 +681,7 @@ async function buildClientSideFiles(alpineDataFiles = [], isDev3) {
|
|
|
646
681
|
minify: !isDev3,
|
|
647
682
|
sourcemap: isDev3 ? "inline" : false
|
|
648
683
|
});
|
|
649
|
-
await logSize(config.distPublicDir, "client");
|
|
684
|
+
await logSize(config.distPublicDir, id ? `client bundle: ${id}.js` : "client bundle: app.js");
|
|
650
685
|
}
|
|
651
686
|
function writeDevServerClientSideCode(tempFilePath) {
|
|
652
687
|
const devServerPath = path5.join(xpineDistDir, "./src/static/dev-server.js");
|
|
@@ -658,7 +693,7 @@ function writeSpaClientSideCode(tempFilePath) {
|
|
|
658
693
|
const content = fs7.readFileSync(spaPath, "utf-8");
|
|
659
694
|
fs7.appendFileSync(tempFilePath, "\n" + content);
|
|
660
695
|
}
|
|
661
|
-
async function buildAlpineDataFile(componentData, dataFiles) {
|
|
696
|
+
async function buildAlpineDataFile(componentData, dataFiles, bundleID) {
|
|
662
697
|
const output = {
|
|
663
698
|
imports: [
|
|
664
699
|
"import Alpine from 'alpinejs';"
|
|
@@ -702,9 +737,16 @@ async function buildAlpineDataFile(componentData, dataFiles) {
|
|
|
702
737
|
output.code.push(`Alpine.data('${dataFunction.name}', ${dataFunction.name});`);
|
|
703
738
|
}
|
|
704
739
|
const result = output.imports.join("\n") + "\n" + output.code.join("\n") + "\n" + output.end.join("\n");
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
740
|
+
if (bundleID) {
|
|
741
|
+
const bundlePath = path5.join(config.distTempFolder, `./alpine-data-${bundleID}.ts`);
|
|
742
|
+
fs7.ensureFileSync(bundlePath);
|
|
743
|
+
fs7.writeFileSync(bundlePath, result);
|
|
744
|
+
return bundlePath;
|
|
745
|
+
} else {
|
|
746
|
+
fs7.ensureFileSync(config.alpineDataPath);
|
|
747
|
+
fs7.writeFileSync(config.alpineDataPath, result);
|
|
748
|
+
return config.alpineDataPath;
|
|
749
|
+
}
|
|
708
750
|
}
|
|
709
751
|
async function buildPublicFolderSymlinks() {
|
|
710
752
|
const files = globSync3(config.publicDir + "/**/*.*", {
|
|
@@ -768,17 +810,28 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
768
810
|
const componentDynamicPaths = getComponentDynamicPaths(componentFileName);
|
|
769
811
|
const componentFn = componentImport.default;
|
|
770
812
|
if (componentImport?.onInit) await componentImport.onInit();
|
|
771
|
-
const outputPath =
|
|
772
|
-
|
|
773
|
-
}, path5.dirname(builtComponentPath)) : path5.dirname(builtComponentPath);
|
|
813
|
+
const outputPath = determineOutputPathForStaticPath(builtComponentPath, componentDynamicPaths);
|
|
814
|
+
if (!outputPath) return;
|
|
774
815
|
if (typeof config2?.staticPaths === "boolean") {
|
|
775
816
|
const urlPath = filePathToURLPath(outputPath);
|
|
776
817
|
try {
|
|
777
|
-
const req = {
|
|
778
|
-
|
|
779
|
-
|
|
818
|
+
const req = {
|
|
819
|
+
params: {},
|
|
820
|
+
route: {
|
|
821
|
+
path: urlPath
|
|
822
|
+
},
|
|
823
|
+
url: urlPath
|
|
824
|
+
};
|
|
825
|
+
let data = config2?.data ? await config2.data(req) : null;
|
|
826
|
+
data = {
|
|
827
|
+
...data,
|
|
828
|
+
routePath: urlPath
|
|
829
|
+
};
|
|
830
|
+
const staticComponentOutput = await componentFn({ data, routePath: urlPath, req });
|
|
831
|
+
const htmlOutputPath = path5.join(outputPath, "./index.html");
|
|
832
|
+
fs7.ensureFileSync(htmlOutputPath);
|
|
780
833
|
fs7.writeFileSync(
|
|
781
|
-
|
|
834
|
+
htmlOutputPath,
|
|
782
835
|
doctypeHTML + (config2?.wrapper ? await config2.wrapper({ req, children: staticComponentOutput, config: config2, data, routePath: urlPath }) : staticComponentOutput) + staticComment
|
|
783
836
|
);
|
|
784
837
|
} catch (err) {
|
|
@@ -789,14 +842,19 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
789
842
|
const dynamicPaths = await config2.staticPaths();
|
|
790
843
|
for (const dynamicPath of dynamicPaths) {
|
|
791
844
|
try {
|
|
845
|
+
const updatedOutDir = path5.join(outputPath, `./${componentDynamicPaths.map((key) => dynamicPath[key]).join("/")}`);
|
|
846
|
+
const urlPath = filePathToURLPath(updatedOutDir);
|
|
792
847
|
const req = {
|
|
793
848
|
params: {
|
|
794
849
|
...componentDynamicPaths?.length ? dynamicPath : {}
|
|
795
|
-
}
|
|
850
|
+
},
|
|
851
|
+
route: {
|
|
852
|
+
path: urlPath
|
|
853
|
+
},
|
|
854
|
+
url: urlPath
|
|
796
855
|
};
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
const data = config2?.data ? await config2.data(req) : null;
|
|
856
|
+
let data = config2?.data ? await config2.data(req) : null;
|
|
857
|
+
data = { ...data, routePath: urlPath };
|
|
800
858
|
const staticComponentOutput = await componentFn({ req, data, routePath: urlPath });
|
|
801
859
|
fs7.ensureDirSync(updatedOutDir);
|
|
802
860
|
fs7.writeFileSync(
|
|
@@ -810,6 +868,20 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
810
868
|
}
|
|
811
869
|
}
|
|
812
870
|
}
|
|
871
|
+
function determineOutputPathForStaticPath(builtComponentPath, componentDynamicPaths) {
|
|
872
|
+
if (componentDynamicPaths?.length) {
|
|
873
|
+
return componentDynamicPaths.reduce((total, current) => {
|
|
874
|
+
return total.replace(`/[${current}]`, "");
|
|
875
|
+
}, path5.dirname(builtComponentPath));
|
|
876
|
+
} else {
|
|
877
|
+
if (builtComponentPath?.match(regex_default.endsWithIndex)) {
|
|
878
|
+
return path5.dirname(builtComponentPath);
|
|
879
|
+
} else {
|
|
880
|
+
if (!builtComponentPath.match(regex_default.endsWithJs)) return null;
|
|
881
|
+
return builtComponentPath.replace(regex_default.endsWithJs, "");
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
813
885
|
function getComponentDynamicPaths(componentPath) {
|
|
814
886
|
const matches = [...componentPath.matchAll(regex_default.dynamicRoutes)].concat([...componentPath.matchAll(regex_default.catchAllRoute)]);
|
|
815
887
|
if (!matches?.length) return null;
|
|
@@ -866,6 +938,47 @@ async function buildOnLoadFile(componentData, isDev3) {
|
|
|
866
938
|
]
|
|
867
939
|
});
|
|
868
940
|
}
|
|
941
|
+
async function buildSitemap() {
|
|
942
|
+
if (!config?.sitemap) return;
|
|
943
|
+
const staticPages = globSync3(`${config.distPagesDir}/**/*.html`) || [];
|
|
944
|
+
const dynamicPages = globSync3(`${config.pagesDir}/**/*.{jsx,tsx}`) || [];
|
|
945
|
+
const allPages = staticPages.concat(dynamicPages);
|
|
946
|
+
const filteredPages = allPages.filter((filePath) => {
|
|
947
|
+
return !micromatch([filePath], config.sitemap?.excludePaths || [])?.length;
|
|
948
|
+
});
|
|
949
|
+
const pages = filteredPages.map((filePath) => {
|
|
950
|
+
const replacedExtensions = filePath.replace(regex_default.endsWithFileName, "");
|
|
951
|
+
const replacedPagesPath = replacedExtensions.replace(config.pagesDir, "");
|
|
952
|
+
const replacedDistPath = replacedPagesPath.replace(config.distPagesDir, "");
|
|
953
|
+
const replacedIndex = replacedDistPath.replace(regex_default.endsWithIndexNoExtension, "");
|
|
954
|
+
if (replacedIndex === "") return "/";
|
|
955
|
+
return replacedIndex;
|
|
956
|
+
}).filter((filePath) => {
|
|
957
|
+
return !filePath.includes("+config");
|
|
958
|
+
});
|
|
959
|
+
const sitemap = `
|
|
960
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
961
|
+
<urlset
|
|
962
|
+
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
963
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
964
|
+
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
|
|
965
|
+
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
|
|
966
|
+
xmlns:xhtml="http://www.w3.org/1999/xhtml"
|
|
967
|
+
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
|
|
968
|
+
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"
|
|
969
|
+
>
|
|
970
|
+
${pages.map((page) => {
|
|
971
|
+
return `
|
|
972
|
+
<url>
|
|
973
|
+
<loc>${config?.domain ? `https://${config.domain}${page}` : page}</loc>
|
|
974
|
+
</url>
|
|
975
|
+
`;
|
|
976
|
+
}).join("\n")}
|
|
977
|
+
</urlset>
|
|
978
|
+
`;
|
|
979
|
+
fs7.ensureFileSync(config.sitemapPath);
|
|
980
|
+
fs7.writeFileSync(config.sitemapPath, minifyXML(sitemap));
|
|
981
|
+
}
|
|
869
982
|
|
|
870
983
|
// src/scripts/xpine-build.ts
|
|
871
984
|
import yargs from "yargs";
|
|
@@ -11,6 +11,8 @@ import chokidar from "chokidar";
|
|
|
11
11
|
import path5 from "path";
|
|
12
12
|
import fs7 from "fs-extra";
|
|
13
13
|
import { build } from "esbuild";
|
|
14
|
+
import micromatch from "micromatch";
|
|
15
|
+
import minifyXML from "minify-xml";
|
|
14
16
|
|
|
15
17
|
// src/build/typescript-builder.ts
|
|
16
18
|
import ts from "typescript";
|
|
@@ -32,6 +34,7 @@ function fromRoot(pathName) {
|
|
|
32
34
|
}
|
|
33
35
|
var userConfig = require_default(path.join(process.cwd(), "./xpine.config.mjs")).default;
|
|
34
36
|
var configDefaults = {
|
|
37
|
+
domain: "",
|
|
35
38
|
rootDir: fromRoot(),
|
|
36
39
|
srcDir: fromRoot("./src"),
|
|
37
40
|
distDir: fromRoot("./dist"),
|
|
@@ -79,6 +82,9 @@ var configDefaults = {
|
|
|
79
82
|
},
|
|
80
83
|
get globalCSSFile() {
|
|
81
84
|
return path.join(this.publicDir, "./styles/global.css");
|
|
85
|
+
},
|
|
86
|
+
get sitemapPath() {
|
|
87
|
+
return path.join(this.distPublicDir, "./sitemap.xml");
|
|
82
88
|
}
|
|
83
89
|
};
|
|
84
90
|
var config = {
|
|
@@ -324,6 +330,10 @@ var regex_default = {
|
|
|
324
330
|
isDynamicRoute: /\[(.*)\]/g,
|
|
325
331
|
endsWithTSX: /\.tsx$/,
|
|
326
332
|
endsWithJSX: /\.jsx$/,
|
|
333
|
+
endsWithJs: /\.js$/,
|
|
334
|
+
endsWithPageFileName: /\.(tsx|jsx)$/,
|
|
335
|
+
endsWithIndexNoExtension: /\/index$/,
|
|
336
|
+
endsWithIndex: /\/index\.(html|tsx|jsx|js|ts)$/,
|
|
327
337
|
endsWithFileName: /\.(html|tsx|jsx|js|ts)$/,
|
|
328
338
|
indexFile: /index\.(html|tsx|jsx|js|ts)$/g,
|
|
329
339
|
catchAllRoute: /\/_all_$/g,
|
|
@@ -554,15 +564,19 @@ import tailwindPostcss from "@tailwindcss/postcss";
|
|
|
554
564
|
async function buildCSS(disableTailwind) {
|
|
555
565
|
const cssFiles = globSync2(config.srcDir + "/**/*.css");
|
|
556
566
|
for (const file of cssFiles) {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
567
|
+
try {
|
|
568
|
+
const fileContents = fs6.readFileSync(file, "utf-8");
|
|
569
|
+
let result = fileContents;
|
|
570
|
+
if (!disableTailwind) {
|
|
571
|
+
result = await postcss([add_breakpoint_data_default()]).process(fileContents, { from: file });
|
|
572
|
+
result = await postcss([tailwindPostcss(), remove_layers_default()]).process(result.css, { from: file });
|
|
573
|
+
}
|
|
574
|
+
const newPath = file.replace(config.srcDir, config.distDir);
|
|
575
|
+
fs6.ensureFileSync(newPath);
|
|
576
|
+
fs6.writeFileSync(newPath, result.css);
|
|
577
|
+
} catch (err) {
|
|
578
|
+
console.error(err);
|
|
562
579
|
}
|
|
563
|
-
const newPath = file.replace(config.srcDir, config.distDir);
|
|
564
|
-
fs6.ensureFileSync(newPath);
|
|
565
|
-
fs6.writeFileSync(newPath, result.css);
|
|
566
580
|
}
|
|
567
581
|
logSize(config.distPublicDir, "css");
|
|
568
582
|
}
|
|
@@ -580,14 +594,35 @@ async function buildApp(args) {
|
|
|
580
594
|
if (removePreviousBuild) fs7.removeSync(config.distDir);
|
|
581
595
|
const srcDirFiles = globSync3(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
|
|
582
596
|
const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev2);
|
|
583
|
-
const
|
|
584
|
-
|
|
597
|
+
const clientSideBundles = [];
|
|
598
|
+
if (config?.bundles?.length) {
|
|
599
|
+
for (const bundle of config.bundles) {
|
|
600
|
+
const matchingComponentData = componentData?.filter((item) => {
|
|
601
|
+
return !micromatch([item.path], bundle?.excludePaths || [])?.length;
|
|
602
|
+
})?.filter((item) => {
|
|
603
|
+
if (!bundle?.includePaths?.length) return true;
|
|
604
|
+
return micromatch([item.path], bundle?.includePaths || [])?.length;
|
|
605
|
+
});
|
|
606
|
+
const matchingDataFiles = dataFiles?.filter((item) => {
|
|
607
|
+
return !micromatch([item.path], bundle?.excludePaths || [])?.length;
|
|
608
|
+
})?.filter((item) => {
|
|
609
|
+
if (!bundle?.includePaths?.length) return true;
|
|
610
|
+
return micromatch([item.path], bundle?.includePaths || [])?.length;
|
|
611
|
+
});
|
|
612
|
+
const alpineDataFile = await buildAlpineDataFile(matchingComponentData, matchingDataFiles, bundle.id);
|
|
613
|
+
await buildClientSideFiles([alpineDataFile], isDev2, `./${bundle.id}.ts`, bundle.id);
|
|
614
|
+
}
|
|
615
|
+
} else {
|
|
616
|
+
const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
|
|
617
|
+
await buildClientSideFiles([alpineDataFile, ...clientSideBundles], isDev2);
|
|
618
|
+
}
|
|
585
619
|
fs7.removeSync(config.distTempFolder);
|
|
586
620
|
await buildCSS(disableTailwind);
|
|
587
621
|
await buildPublicFolderSymlinks();
|
|
588
622
|
await buildOnLoadFile(componentData, isDev2);
|
|
589
623
|
if (!isDev2) await triggerXPineOnLoad();
|
|
590
624
|
if (!isDev2) await buildFilesWithConfigs(componentData);
|
|
625
|
+
if (!isDev2) buildSitemap();
|
|
591
626
|
if (!isDev2) context.clear();
|
|
592
627
|
} catch (err) {
|
|
593
628
|
console.error("Build failed");
|
|
@@ -625,8 +660,8 @@ async function buildAppFiles(files, isDev2) {
|
|
|
625
660
|
dataFiles
|
|
626
661
|
};
|
|
627
662
|
}
|
|
628
|
-
async function buildClientSideFiles(alpineDataFiles = [], isDev2) {
|
|
629
|
-
const tempFilePath = path5.join(config.distTempFolder, "./app.ts");
|
|
663
|
+
async function buildClientSideFiles(alpineDataFiles = [], isDev2, tempClientSidePath, id) {
|
|
664
|
+
const tempFilePath = path5.join(config.distTempFolder, tempClientSidePath || "./app.ts");
|
|
630
665
|
fs7.ensureFileSync(tempFilePath);
|
|
631
666
|
const pagesScriptsGlob = config.publicDir + "/scripts/pages/**/*.{js,ts}";
|
|
632
667
|
const clientFiles = globSync3(
|
|
@@ -653,7 +688,7 @@ async function buildClientSideFiles(alpineDataFiles = [], isDev2) {
|
|
|
653
688
|
minify: !isDev2,
|
|
654
689
|
sourcemap: isDev2 ? "inline" : false
|
|
655
690
|
});
|
|
656
|
-
await logSize(config.distPublicDir, "client");
|
|
691
|
+
await logSize(config.distPublicDir, id ? `client bundle: ${id}.js` : "client bundle: app.js");
|
|
657
692
|
}
|
|
658
693
|
function writeDevServerClientSideCode(tempFilePath) {
|
|
659
694
|
const devServerPath = path5.join(xpineDistDir, "./src/static/dev-server.js");
|
|
@@ -665,7 +700,7 @@ function writeSpaClientSideCode(tempFilePath) {
|
|
|
665
700
|
const content = fs7.readFileSync(spaPath, "utf-8");
|
|
666
701
|
fs7.appendFileSync(tempFilePath, "\n" + content);
|
|
667
702
|
}
|
|
668
|
-
async function buildAlpineDataFile(componentData, dataFiles) {
|
|
703
|
+
async function buildAlpineDataFile(componentData, dataFiles, bundleID) {
|
|
669
704
|
const output = {
|
|
670
705
|
imports: [
|
|
671
706
|
"import Alpine from 'alpinejs';"
|
|
@@ -709,9 +744,16 @@ async function buildAlpineDataFile(componentData, dataFiles) {
|
|
|
709
744
|
output.code.push(`Alpine.data('${dataFunction.name}', ${dataFunction.name});`);
|
|
710
745
|
}
|
|
711
746
|
const result = output.imports.join("\n") + "\n" + output.code.join("\n") + "\n" + output.end.join("\n");
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
747
|
+
if (bundleID) {
|
|
748
|
+
const bundlePath = path5.join(config.distTempFolder, `./alpine-data-${bundleID}.ts`);
|
|
749
|
+
fs7.ensureFileSync(bundlePath);
|
|
750
|
+
fs7.writeFileSync(bundlePath, result);
|
|
751
|
+
return bundlePath;
|
|
752
|
+
} else {
|
|
753
|
+
fs7.ensureFileSync(config.alpineDataPath);
|
|
754
|
+
fs7.writeFileSync(config.alpineDataPath, result);
|
|
755
|
+
return config.alpineDataPath;
|
|
756
|
+
}
|
|
715
757
|
}
|
|
716
758
|
async function buildPublicFolderSymlinks() {
|
|
717
759
|
const files = globSync3(config.publicDir + "/**/*.*", {
|
|
@@ -775,17 +817,28 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
775
817
|
const componentDynamicPaths = getComponentDynamicPaths(componentFileName);
|
|
776
818
|
const componentFn = componentImport.default;
|
|
777
819
|
if (componentImport?.onInit) await componentImport.onInit();
|
|
778
|
-
const outputPath =
|
|
779
|
-
|
|
780
|
-
}, path5.dirname(builtComponentPath)) : path5.dirname(builtComponentPath);
|
|
820
|
+
const outputPath = determineOutputPathForStaticPath(builtComponentPath, componentDynamicPaths);
|
|
821
|
+
if (!outputPath) return;
|
|
781
822
|
if (typeof config2?.staticPaths === "boolean") {
|
|
782
823
|
const urlPath = filePathToURLPath(outputPath);
|
|
783
824
|
try {
|
|
784
|
-
const req = {
|
|
785
|
-
|
|
786
|
-
|
|
825
|
+
const req = {
|
|
826
|
+
params: {},
|
|
827
|
+
route: {
|
|
828
|
+
path: urlPath
|
|
829
|
+
},
|
|
830
|
+
url: urlPath
|
|
831
|
+
};
|
|
832
|
+
let data = config2?.data ? await config2.data(req) : null;
|
|
833
|
+
data = {
|
|
834
|
+
...data,
|
|
835
|
+
routePath: urlPath
|
|
836
|
+
};
|
|
837
|
+
const staticComponentOutput = await componentFn({ data, routePath: urlPath, req });
|
|
838
|
+
const htmlOutputPath = path5.join(outputPath, "./index.html");
|
|
839
|
+
fs7.ensureFileSync(htmlOutputPath);
|
|
787
840
|
fs7.writeFileSync(
|
|
788
|
-
|
|
841
|
+
htmlOutputPath,
|
|
789
842
|
doctypeHTML + (config2?.wrapper ? await config2.wrapper({ req, children: staticComponentOutput, config: config2, data, routePath: urlPath }) : staticComponentOutput) + staticComment
|
|
790
843
|
);
|
|
791
844
|
} catch (err) {
|
|
@@ -796,14 +849,19 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
796
849
|
const dynamicPaths = await config2.staticPaths();
|
|
797
850
|
for (const dynamicPath of dynamicPaths) {
|
|
798
851
|
try {
|
|
852
|
+
const updatedOutDir = path5.join(outputPath, `./${componentDynamicPaths.map((key) => dynamicPath[key]).join("/")}`);
|
|
853
|
+
const urlPath = filePathToURLPath(updatedOutDir);
|
|
799
854
|
const req = {
|
|
800
855
|
params: {
|
|
801
856
|
...componentDynamicPaths?.length ? dynamicPath : {}
|
|
802
|
-
}
|
|
857
|
+
},
|
|
858
|
+
route: {
|
|
859
|
+
path: urlPath
|
|
860
|
+
},
|
|
861
|
+
url: urlPath
|
|
803
862
|
};
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
const data = config2?.data ? await config2.data(req) : null;
|
|
863
|
+
let data = config2?.data ? await config2.data(req) : null;
|
|
864
|
+
data = { ...data, routePath: urlPath };
|
|
807
865
|
const staticComponentOutput = await componentFn({ req, data, routePath: urlPath });
|
|
808
866
|
fs7.ensureDirSync(updatedOutDir);
|
|
809
867
|
fs7.writeFileSync(
|
|
@@ -817,6 +875,20 @@ async function buildStaticFiles(config2, component, componentImport, builtCompon
|
|
|
817
875
|
}
|
|
818
876
|
}
|
|
819
877
|
}
|
|
878
|
+
function determineOutputPathForStaticPath(builtComponentPath, componentDynamicPaths) {
|
|
879
|
+
if (componentDynamicPaths?.length) {
|
|
880
|
+
return componentDynamicPaths.reduce((total, current) => {
|
|
881
|
+
return total.replace(`/[${current}]`, "");
|
|
882
|
+
}, path5.dirname(builtComponentPath));
|
|
883
|
+
} else {
|
|
884
|
+
if (builtComponentPath?.match(regex_default.endsWithIndex)) {
|
|
885
|
+
return path5.dirname(builtComponentPath);
|
|
886
|
+
} else {
|
|
887
|
+
if (!builtComponentPath.match(regex_default.endsWithJs)) return null;
|
|
888
|
+
return builtComponentPath.replace(regex_default.endsWithJs, "");
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
820
892
|
function getComponentDynamicPaths(componentPath) {
|
|
821
893
|
const matches = [...componentPath.matchAll(regex_default.dynamicRoutes)].concat([...componentPath.matchAll(regex_default.catchAllRoute)]);
|
|
822
894
|
if (!matches?.length) return null;
|
|
@@ -873,6 +945,47 @@ async function buildOnLoadFile(componentData, isDev2) {
|
|
|
873
945
|
]
|
|
874
946
|
});
|
|
875
947
|
}
|
|
948
|
+
async function buildSitemap() {
|
|
949
|
+
if (!config?.sitemap) return;
|
|
950
|
+
const staticPages = globSync3(`${config.distPagesDir}/**/*.html`) || [];
|
|
951
|
+
const dynamicPages = globSync3(`${config.pagesDir}/**/*.{jsx,tsx}`) || [];
|
|
952
|
+
const allPages = staticPages.concat(dynamicPages);
|
|
953
|
+
const filteredPages = allPages.filter((filePath) => {
|
|
954
|
+
return !micromatch([filePath], config.sitemap?.excludePaths || [])?.length;
|
|
955
|
+
});
|
|
956
|
+
const pages = filteredPages.map((filePath) => {
|
|
957
|
+
const replacedExtensions = filePath.replace(regex_default.endsWithFileName, "");
|
|
958
|
+
const replacedPagesPath = replacedExtensions.replace(config.pagesDir, "");
|
|
959
|
+
const replacedDistPath = replacedPagesPath.replace(config.distPagesDir, "");
|
|
960
|
+
const replacedIndex = replacedDistPath.replace(regex_default.endsWithIndexNoExtension, "");
|
|
961
|
+
if (replacedIndex === "") return "/";
|
|
962
|
+
return replacedIndex;
|
|
963
|
+
}).filter((filePath) => {
|
|
964
|
+
return !filePath.includes("+config");
|
|
965
|
+
});
|
|
966
|
+
const sitemap = `
|
|
967
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
968
|
+
<urlset
|
|
969
|
+
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
970
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
971
|
+
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
|
|
972
|
+
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
|
|
973
|
+
xmlns:xhtml="http://www.w3.org/1999/xhtml"
|
|
974
|
+
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
|
|
975
|
+
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"
|
|
976
|
+
>
|
|
977
|
+
${pages.map((page) => {
|
|
978
|
+
return `
|
|
979
|
+
<url>
|
|
980
|
+
<loc>${config?.domain ? `https://${config.domain}${page}` : page}</loc>
|
|
981
|
+
</url>
|
|
982
|
+
`;
|
|
983
|
+
}).join("\n")}
|
|
984
|
+
</urlset>
|
|
985
|
+
`;
|
|
986
|
+
fs7.ensureFileSync(config.sitemapPath);
|
|
987
|
+
fs7.writeFileSync(config.sitemapPath, minifyXML(sitemap));
|
|
988
|
+
}
|
|
876
989
|
|
|
877
990
|
// src/runDevServer.ts
|
|
878
991
|
import path7 from "path";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-config.d.ts","sourceRoot":"","sources":["../../../src/util/get-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,wBAAgB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,UAGzC;
|
|
1
|
+
{"version":3,"file":"get-config.d.ts","sourceRoot":"","sources":["../../../src/util/get-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,wBAAgB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,UAGzC;AA2DD,eAAO,MAAM,MAAM,EAAE,WAGpB,CAAC"}
|
package/dist/src/util/regex.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ declare const _default: {
|
|
|
6
6
|
isDynamicRoute: RegExp;
|
|
7
7
|
endsWithTSX: RegExp;
|
|
8
8
|
endsWithJSX: RegExp;
|
|
9
|
+
endsWithJs: RegExp;
|
|
10
|
+
endsWithPageFileName: RegExp;
|
|
11
|
+
endsWithIndexNoExtension: RegExp;
|
|
12
|
+
endsWithIndex: RegExp;
|
|
9
13
|
endsWithFileName: RegExp;
|
|
10
14
|
indexFile: RegExp;
|
|
11
15
|
catchAllRoute: RegExp;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"regex.d.ts","sourceRoot":"","sources":["../../../src/util/regex.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"regex.d.ts","sourceRoot":"","sources":["../../../src/util/regex.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,wBAiBE"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xpine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.50",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-secrets-manager": "^3.758.0",
|
|
7
|
-
"@tailwindcss/postcss": "^4.
|
|
7
|
+
"@tailwindcss/postcss": "^4.1.12",
|
|
8
8
|
"builtin-modules": "^4.0.0",
|
|
9
9
|
"chokidar": "^4.0.3",
|
|
10
10
|
"dotenv": "^16.4.7",
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
"fs-extra": "^11.3.0",
|
|
15
15
|
"glob": "^11.0.1",
|
|
16
16
|
"jsonwebtoken": "^9.0.2",
|
|
17
|
+
"micromatch": "^4.0.8",
|
|
18
|
+
"minify-xml": "^4.5.2",
|
|
17
19
|
"postcss": "^8.5.3",
|
|
18
20
|
"request-ip": "^3.3.0",
|
|
19
21
|
"shelljs": "^0.9.2",
|
|
@@ -48,6 +50,7 @@
|
|
|
48
50
|
"@eslint/js": "^9.24.0",
|
|
49
51
|
"@tailwindcss/oxide-darwin-arm64": "^4.1.3",
|
|
50
52
|
"@types/express": "^5.0.0",
|
|
53
|
+
"@types/micromatch": "^4.0.9",
|
|
51
54
|
"@types/node": "^22.13.5",
|
|
52
55
|
"@types/request-ip": "^0.0.41",
|
|
53
56
|
"@types/shelljs": "^0.8.15",
|