xpine 0.0.47 → 0.0.49

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 CHANGED
@@ -426,4 +426,30 @@ 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
+ }
453
+ ]
454
+ }
455
+ ```
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ 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";
12
13
 
13
14
  // src/build/typescript-builder.ts
14
15
  import ts from "typescript";
@@ -238,7 +239,10 @@ function removeClientScriptInTSXFile(pathName, source) {
238
239
  clientDataStart
239
240
  };
240
241
  }
241
- function getImportsToAbsolutePaths(child, source, pathName) {
242
+ function pathExistsAsIndex(pathName) {
243
+ return fs.existsSync(path2.join(pathName, "./index.js")) || fs.existsSync(path2.join(pathName, "./index.ts")) || fs.existsSync(path2.join(pathName, "./index.jsx")) || fs.existsSync(path2.join(pathName, "./index.tsx"));
244
+ }
245
+ function getImportsToAbsolutePaths(child, source, pathName, convertPathsToJS = false) {
242
246
  const output = [];
243
247
  child.forEachChild((child2) => {
244
248
  if (child2.kind === ts.SyntaxKind.StringLiteral) {
@@ -246,15 +250,23 @@ function getImportsToAbsolutePaths(child, source, pathName) {
246
250
  const importPath = text.replace(/[\"\']/g, "");
247
251
  const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
248
252
  if (!isRelativeImport) return;
253
+ let result = path2.join(path2.dirname(pathName), importPath);
254
+ if (convertPathsToJS) {
255
+ if (pathExistsAsIndex(result)) {
256
+ result = path2.join(result, "./index.js");
257
+ } else {
258
+ result += ".js";
259
+ }
260
+ }
249
261
  output.push({
250
262
  old: importPath,
251
- new: path2.join(path2.dirname(pathName), importPath)
263
+ new: result
252
264
  });
253
265
  }
254
266
  });
255
267
  return output;
256
268
  }
257
- function getXpineOnLoadFunction(pathName, source, onLoadFileResult) {
269
+ function getXpineOnLoadFunction(pathName, source, options) {
258
270
  const value = {
259
271
  imports: "",
260
272
  fn: ""
@@ -262,7 +274,7 @@ function getXpineOnLoadFunction(pathName, source, onLoadFileResult) {
262
274
  source.forEachChild((child) => {
263
275
  if (child.kind == ts.SyntaxKind.ImportDeclaration) {
264
276
  let importText = child.getText(source);
265
- const importOutput = getImportsToAbsolutePaths(child, source, pathName);
277
+ const importOutput = getImportsToAbsolutePaths(child, source, pathName, options?.convertPathsToJS);
266
278
  for (const importItem of importOutput) {
267
279
  importText = importText.replace(importItem.old, importItem.new);
268
280
  }
@@ -769,8 +781,27 @@ async function buildApp(args) {
769
781
  if (removePreviousBuild) fs7.removeSync(config.distDir);
770
782
  const srcDirFiles = globSync3(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
771
783
  const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev2);
784
+ const clientSideBundles = [];
785
+ if (config?.bundles?.length) {
786
+ for (const bundle of config.bundles) {
787
+ const matchingComponentData = componentData?.filter((item) => {
788
+ return !micromatch([item.path], bundle?.excludePaths || [])?.length;
789
+ })?.filter((item) => {
790
+ if (!bundle?.includePaths?.length) return true;
791
+ return micromatch([item.path], bundle?.includePaths || [])?.length;
792
+ });
793
+ const matchingDataFiles = dataFiles?.filter((item) => {
794
+ return !micromatch([item.path], bundle?.excludePaths || [])?.length;
795
+ })?.filter((item) => {
796
+ if (!bundle?.includePaths?.length) return true;
797
+ return micromatch([item.path], bundle?.includePaths || [])?.length;
798
+ });
799
+ const alpineDataFile2 = await buildAlpineDataFile(matchingComponentData, matchingDataFiles, bundle.id);
800
+ await buildClientSideFiles([alpineDataFile2], isDev2, `./${bundle.id}.ts`, bundle.id);
801
+ }
802
+ }
772
803
  const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
773
- await buildClientSideFiles([alpineDataFile], isDev2);
804
+ await buildClientSideFiles([alpineDataFile, ...clientSideBundles], isDev2);
774
805
  fs7.removeSync(config.distTempFolder);
775
806
  await buildCSS(disableTailwind);
776
807
  await buildPublicFolderSymlinks();
@@ -814,8 +845,8 @@ async function buildAppFiles(files, isDev2) {
814
845
  dataFiles
815
846
  };
816
847
  }
817
- async function buildClientSideFiles(alpineDataFiles = [], isDev2) {
818
- const tempFilePath = path6.join(config.distTempFolder, "./app.ts");
848
+ async function buildClientSideFiles(alpineDataFiles = [], isDev2, tempClientSidePath, id) {
849
+ const tempFilePath = path6.join(config.distTempFolder, tempClientSidePath || "./app.ts");
819
850
  fs7.ensureFileSync(tempFilePath);
820
851
  const pagesScriptsGlob = config.publicDir + "/scripts/pages/**/*.{js,ts}";
821
852
  const clientFiles = globSync3(
@@ -842,7 +873,7 @@ async function buildClientSideFiles(alpineDataFiles = [], isDev2) {
842
873
  minify: !isDev2,
843
874
  sourcemap: isDev2 ? "inline" : false
844
875
  });
845
- await logSize(config.distPublicDir, "client");
876
+ await logSize(config.distPublicDir, id ? `client bundle: ${id}.js` : "client bundle: app.js");
846
877
  }
847
878
  function writeDevServerClientSideCode(tempFilePath) {
848
879
  const devServerPath = path6.join(xpineDistDir, "./src/static/dev-server.js");
@@ -854,7 +885,7 @@ function writeSpaClientSideCode(tempFilePath) {
854
885
  const content = fs7.readFileSync(spaPath, "utf-8");
855
886
  fs7.appendFileSync(tempFilePath, "\n" + content);
856
887
  }
857
- async function buildAlpineDataFile(componentData, dataFiles) {
888
+ async function buildAlpineDataFile(componentData, dataFiles, bundleID) {
858
889
  const output = {
859
890
  imports: [
860
891
  "import Alpine from 'alpinejs';"
@@ -898,9 +929,16 @@ async function buildAlpineDataFile(componentData, dataFiles) {
898
929
  output.code.push(`Alpine.data('${dataFunction.name}', ${dataFunction.name});`);
899
930
  }
900
931
  const result = output.imports.join("\n") + "\n" + output.code.join("\n") + "\n" + output.end.join("\n");
901
- fs7.ensureFileSync(config.alpineDataPath);
902
- fs7.writeFileSync(config.alpineDataPath, result);
903
- return config.alpineDataPath;
932
+ if (bundleID) {
933
+ const bundlePath = path6.join(config.distTempFolder, `./alpine-data-${bundleID}.ts`);
934
+ fs7.ensureFileSync(bundlePath);
935
+ fs7.writeFileSync(bundlePath, result);
936
+ return bundlePath;
937
+ } else {
938
+ fs7.ensureFileSync(config.alpineDataPath);
939
+ fs7.writeFileSync(config.alpineDataPath, result);
940
+ return config.alpineDataPath;
941
+ }
904
942
  }
905
943
  async function buildPublicFolderSymlinks() {
906
944
  const files = globSync3(config.publicDir + "/**/*.*", {
@@ -1033,7 +1071,7 @@ async function buildOnLoadFile(componentData, isDev2) {
1033
1071
  return a.path.localeCompare(b.path);
1034
1072
  });
1035
1073
  for (const file of onLoadFiles) {
1036
- const result = getXpineOnLoadFunction(file.path, file.source, onLoadFileResult);
1074
+ const result = getXpineOnLoadFunction(file.path, file.source, { convertPathsToJS: true });
1037
1075
  onLoadFileResult.fn += result.fn;
1038
1076
  onLoadFileResult.imports += result.imports;
1039
1077
  }
@@ -1,5 +1,4 @@
1
1
  import ts from 'typescript';
2
- import { OnLoadFileResult } from '../scripts/build';
3
2
  type ImportDeclaration = {
4
3
  node: ts.Node;
5
4
  importPath: string;
@@ -26,9 +25,13 @@ export declare function removeClientScriptInTSXFile(pathName: string, source: ts
26
25
  clientDataStart: number;
27
26
  };
28
27
  export declare function createStaticFile(pathName: string, source: ts.SourceFile): void;
29
- export declare function getImportsToAbsolutePaths(child: ts.Node, source: ts.SourceFile, pathName: string): any[];
28
+ export declare function pathExistsAsIndex(pathName: string): any;
29
+ export declare function getImportsToAbsolutePaths(child: ts.Node, source: ts.SourceFile, pathName: string, convertPathsToJS?: boolean): any[];
30
30
  export declare function printRecursiveFrom(node: ts.Node, indentLevel: number, sourceFile: ts.SourceFile): void;
31
- export declare function getXpineOnLoadFunction(pathName: string, source: ts.SourceFile, onLoadFileResult: OnLoadFileResult): {
31
+ type GetXpineOnLoadFunctionOptions = {
32
+ convertPathsToJS?: boolean;
33
+ };
34
+ export declare function getXpineOnLoadFunction(pathName: string, source: ts.SourceFile, options?: GetXpineOnLoadFunctionOptions): {
32
35
  imports: string;
33
36
  fn: string;
34
37
  };
@@ -1 +1 @@
1
- {"version":3,"file":"typescript-builder.d.ts","sourceRoot":"","sources":["../../../src/build/typescript-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAIpD,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAA;AAGD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,EAAE,kBAAkB,GAAE,iBAAiB,EAAO,uBAiB/H;AAED,wBAAgB,yBAAyB,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,UAO3H;AAED,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAA;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,UAAU,EAAE,EAAE,CAAC,UAAU,EACzB,mBAAmB,GAAE,MAAM,EAAO,EAClC,cAAc,GAAE,mBAAmB,EAAO;;;EA0B3C;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,MAAM,EAAE,CAMxF;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,mBAAmB,CAkBzG;AAGD,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,QAO1F;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU;;;;;;EAmClF;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,QAUvE;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,SAgBhG;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,QAU9D;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,EAAE,gBAAgB,EAAE,gBAAgB;;;EA0BjH;AAED,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,OAAe,iBAMhE"}
1
+ {"version":3,"file":"typescript-builder.d.ts","sourceRoot":"","sources":["../../../src/build/typescript-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAO5B,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAA;AAGD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,EAAE,kBAAkB,GAAE,iBAAiB,EAAO,uBAiB/H;AAED,wBAAgB,yBAAyB,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,UAO3H;AAED,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAA;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,UAAU,EAAE,EAAE,CAAC,UAAU,EACzB,mBAAmB,GAAE,MAAM,EAAO,EAClC,cAAc,GAAE,mBAAmB,EAAO;;;EA0B3C;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,MAAM,EAAE,CAMxF;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,mBAAmB,CAkBzG;AAGD,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,QAO1F;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU;;;;;;EAmClF;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,QAUvE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,OAKjD;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,GAAE,OAAe,SAwBnI;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,QAU9D;AAED,KAAK,6BAA6B,GAAG;IACnC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAA;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,OAAO,CAAC,EAAE,6BAA6B;;;EA2BxC;AAED,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,OAAe,iBAMhE"}
@@ -6,7 +6,7 @@ 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: 'app' | 'client' | 'css', validExtensions?: string[]): Promise<void>;
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
12
  export declare function getComponentDynamicPaths(componentPath: string): string[];
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/scripts/build.ts"],"names":[],"mappings":"AAkBA,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,iBAsBhD;AAiJD,wBAAsB,yBAAyB,kBAgB9C;AAED,wBAAsB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,EAAE,eAAe,WAAkB,iBAahH;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,iBAyEpI;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"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/scripts/build.ts"],"names":[],"mappings":"AAmBA,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,iBA+ChD;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,iBAyEpI;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"}
@@ -4,6 +4,7 @@
4
4
  import path5 from "path";
5
5
  import fs7 from "fs-extra";
6
6
  import { build } from "esbuild";
7
+ import micromatch from "micromatch";
7
8
 
8
9
  // src/build/typescript-builder.ts
9
10
  import ts from "typescript";
@@ -233,7 +234,10 @@ function removeClientScriptInTSXFile(pathName, source) {
233
234
  clientDataStart
234
235
  };
235
236
  }
236
- function getImportsToAbsolutePaths(child, source, pathName) {
237
+ function pathExistsAsIndex(pathName) {
238
+ return fs.existsSync(path2.join(pathName, "./index.js")) || fs.existsSync(path2.join(pathName, "./index.ts")) || fs.existsSync(path2.join(pathName, "./index.jsx")) || fs.existsSync(path2.join(pathName, "./index.tsx"));
239
+ }
240
+ function getImportsToAbsolutePaths(child, source, pathName, convertPathsToJS = false) {
237
241
  const output = [];
238
242
  child.forEachChild((child2) => {
239
243
  if (child2.kind === ts.SyntaxKind.StringLiteral) {
@@ -241,15 +245,23 @@ function getImportsToAbsolutePaths(child, source, pathName) {
241
245
  const importPath = text.replace(/[\"\']/g, "");
242
246
  const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
243
247
  if (!isRelativeImport) return;
248
+ let result = path2.join(path2.dirname(pathName), importPath);
249
+ if (convertPathsToJS) {
250
+ if (pathExistsAsIndex(result)) {
251
+ result = path2.join(result, "./index.js");
252
+ } else {
253
+ result += ".js";
254
+ }
255
+ }
244
256
  output.push({
245
257
  old: importPath,
246
- new: path2.join(path2.dirname(pathName), importPath)
258
+ new: result
247
259
  });
248
260
  }
249
261
  });
250
262
  return output;
251
263
  }
252
- function getXpineOnLoadFunction(pathName, source, onLoadFileResult) {
264
+ function getXpineOnLoadFunction(pathName, source, options) {
253
265
  const value = {
254
266
  imports: "",
255
267
  fn: ""
@@ -257,7 +269,7 @@ function getXpineOnLoadFunction(pathName, source, onLoadFileResult) {
257
269
  source.forEachChild((child) => {
258
270
  if (child.kind == ts.SyntaxKind.ImportDeclaration) {
259
271
  let importText = child.getText(source);
260
- const importOutput = getImportsToAbsolutePaths(child, source, pathName);
272
+ const importOutput = getImportsToAbsolutePaths(child, source, pathName, options?.convertPathsToJS);
261
273
  for (const importItem of importOutput) {
262
274
  importText = importText.replace(importItem.old, importItem.new);
263
275
  }
@@ -562,8 +574,27 @@ async function buildApp(args) {
562
574
  if (removePreviousBuild2) fs7.removeSync(config.distDir);
563
575
  const srcDirFiles = globSync3(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
564
576
  const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev3);
577
+ const clientSideBundles = [];
578
+ if (config?.bundles?.length) {
579
+ for (const bundle of config.bundles) {
580
+ const matchingComponentData = componentData?.filter((item) => {
581
+ return !micromatch([item.path], bundle?.excludePaths || [])?.length;
582
+ })?.filter((item) => {
583
+ if (!bundle?.includePaths?.length) return true;
584
+ return micromatch([item.path], bundle?.includePaths || [])?.length;
585
+ });
586
+ const matchingDataFiles = dataFiles?.filter((item) => {
587
+ return !micromatch([item.path], bundle?.excludePaths || [])?.length;
588
+ })?.filter((item) => {
589
+ if (!bundle?.includePaths?.length) return true;
590
+ return micromatch([item.path], bundle?.includePaths || [])?.length;
591
+ });
592
+ const alpineDataFile2 = await buildAlpineDataFile(matchingComponentData, matchingDataFiles, bundle.id);
593
+ await buildClientSideFiles([alpineDataFile2], isDev3, `./${bundle.id}.ts`, bundle.id);
594
+ }
595
+ }
565
596
  const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
566
- await buildClientSideFiles([alpineDataFile], isDev3);
597
+ await buildClientSideFiles([alpineDataFile, ...clientSideBundles], isDev3);
567
598
  fs7.removeSync(config.distTempFolder);
568
599
  await buildCSS(disableTailwind2);
569
600
  await buildPublicFolderSymlinks();
@@ -607,8 +638,8 @@ async function buildAppFiles(files, isDev3) {
607
638
  dataFiles
608
639
  };
609
640
  }
610
- async function buildClientSideFiles(alpineDataFiles = [], isDev3) {
611
- const tempFilePath = path5.join(config.distTempFolder, "./app.ts");
641
+ async function buildClientSideFiles(alpineDataFiles = [], isDev3, tempClientSidePath, id) {
642
+ const tempFilePath = path5.join(config.distTempFolder, tempClientSidePath || "./app.ts");
612
643
  fs7.ensureFileSync(tempFilePath);
613
644
  const pagesScriptsGlob = config.publicDir + "/scripts/pages/**/*.{js,ts}";
614
645
  const clientFiles = globSync3(
@@ -635,7 +666,7 @@ async function buildClientSideFiles(alpineDataFiles = [], isDev3) {
635
666
  minify: !isDev3,
636
667
  sourcemap: isDev3 ? "inline" : false
637
668
  });
638
- await logSize(config.distPublicDir, "client");
669
+ await logSize(config.distPublicDir, id ? `client bundle: ${id}.js` : "client bundle: app.js");
639
670
  }
640
671
  function writeDevServerClientSideCode(tempFilePath) {
641
672
  const devServerPath = path5.join(xpineDistDir, "./src/static/dev-server.js");
@@ -647,7 +678,7 @@ function writeSpaClientSideCode(tempFilePath) {
647
678
  const content = fs7.readFileSync(spaPath, "utf-8");
648
679
  fs7.appendFileSync(tempFilePath, "\n" + content);
649
680
  }
650
- async function buildAlpineDataFile(componentData, dataFiles) {
681
+ async function buildAlpineDataFile(componentData, dataFiles, bundleID) {
651
682
  const output = {
652
683
  imports: [
653
684
  "import Alpine from 'alpinejs';"
@@ -691,9 +722,16 @@ async function buildAlpineDataFile(componentData, dataFiles) {
691
722
  output.code.push(`Alpine.data('${dataFunction.name}', ${dataFunction.name});`);
692
723
  }
693
724
  const result = output.imports.join("\n") + "\n" + output.code.join("\n") + "\n" + output.end.join("\n");
694
- fs7.ensureFileSync(config.alpineDataPath);
695
- fs7.writeFileSync(config.alpineDataPath, result);
696
- return config.alpineDataPath;
725
+ if (bundleID) {
726
+ const bundlePath = path5.join(config.distTempFolder, `./alpine-data-${bundleID}.ts`);
727
+ fs7.ensureFileSync(bundlePath);
728
+ fs7.writeFileSync(bundlePath, result);
729
+ return bundlePath;
730
+ } else {
731
+ fs7.ensureFileSync(config.alpineDataPath);
732
+ fs7.writeFileSync(config.alpineDataPath, result);
733
+ return config.alpineDataPath;
734
+ }
697
735
  }
698
736
  async function buildPublicFolderSymlinks() {
699
737
  const files = globSync3(config.publicDir + "/**/*.*", {
@@ -826,7 +864,7 @@ async function buildOnLoadFile(componentData, isDev3) {
826
864
  return a.path.localeCompare(b.path);
827
865
  });
828
866
  for (const file of onLoadFiles) {
829
- const result = getXpineOnLoadFunction(file.path, file.source, onLoadFileResult);
867
+ const result = getXpineOnLoadFunction(file.path, file.source, { convertPathsToJS: true });
830
868
  onLoadFileResult.fn += result.fn;
831
869
  onLoadFileResult.imports += result.imports;
832
870
  }
@@ -11,6 +11,7 @@ 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";
14
15
 
15
16
  // src/build/typescript-builder.ts
16
17
  import ts from "typescript";
@@ -240,7 +241,10 @@ function removeClientScriptInTSXFile(pathName, source) {
240
241
  clientDataStart
241
242
  };
242
243
  }
243
- function getImportsToAbsolutePaths(child, source, pathName) {
244
+ function pathExistsAsIndex(pathName) {
245
+ return fs.existsSync(path2.join(pathName, "./index.js")) || fs.existsSync(path2.join(pathName, "./index.ts")) || fs.existsSync(path2.join(pathName, "./index.jsx")) || fs.existsSync(path2.join(pathName, "./index.tsx"));
246
+ }
247
+ function getImportsToAbsolutePaths(child, source, pathName, convertPathsToJS = false) {
244
248
  const output = [];
245
249
  child.forEachChild((child2) => {
246
250
  if (child2.kind === ts.SyntaxKind.StringLiteral) {
@@ -248,15 +252,23 @@ function getImportsToAbsolutePaths(child, source, pathName) {
248
252
  const importPath = text.replace(/[\"\']/g, "");
249
253
  const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
250
254
  if (!isRelativeImport) return;
255
+ let result = path2.join(path2.dirname(pathName), importPath);
256
+ if (convertPathsToJS) {
257
+ if (pathExistsAsIndex(result)) {
258
+ result = path2.join(result, "./index.js");
259
+ } else {
260
+ result += ".js";
261
+ }
262
+ }
251
263
  output.push({
252
264
  old: importPath,
253
- new: path2.join(path2.dirname(pathName), importPath)
265
+ new: result
254
266
  });
255
267
  }
256
268
  });
257
269
  return output;
258
270
  }
259
- function getXpineOnLoadFunction(pathName, source, onLoadFileResult) {
271
+ function getXpineOnLoadFunction(pathName, source, options) {
260
272
  const value = {
261
273
  imports: "",
262
274
  fn: ""
@@ -264,7 +276,7 @@ function getXpineOnLoadFunction(pathName, source, onLoadFileResult) {
264
276
  source.forEachChild((child) => {
265
277
  if (child.kind == ts.SyntaxKind.ImportDeclaration) {
266
278
  let importText = child.getText(source);
267
- const importOutput = getImportsToAbsolutePaths(child, source, pathName);
279
+ const importOutput = getImportsToAbsolutePaths(child, source, pathName, options?.convertPathsToJS);
268
280
  for (const importItem of importOutput) {
269
281
  importText = importText.replace(importItem.old, importItem.new);
270
282
  }
@@ -569,8 +581,27 @@ async function buildApp(args) {
569
581
  if (removePreviousBuild) fs7.removeSync(config.distDir);
570
582
  const srcDirFiles = globSync3(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
571
583
  const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev2);
584
+ const clientSideBundles = [];
585
+ if (config?.bundles?.length) {
586
+ for (const bundle of config.bundles) {
587
+ const matchingComponentData = componentData?.filter((item) => {
588
+ return !micromatch([item.path], bundle?.excludePaths || [])?.length;
589
+ })?.filter((item) => {
590
+ if (!bundle?.includePaths?.length) return true;
591
+ return micromatch([item.path], bundle?.includePaths || [])?.length;
592
+ });
593
+ const matchingDataFiles = dataFiles?.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 alpineDataFile2 = await buildAlpineDataFile(matchingComponentData, matchingDataFiles, bundle.id);
600
+ await buildClientSideFiles([alpineDataFile2], isDev2, `./${bundle.id}.ts`, bundle.id);
601
+ }
602
+ }
572
603
  const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
573
- await buildClientSideFiles([alpineDataFile], isDev2);
604
+ await buildClientSideFiles([alpineDataFile, ...clientSideBundles], isDev2);
574
605
  fs7.removeSync(config.distTempFolder);
575
606
  await buildCSS(disableTailwind);
576
607
  await buildPublicFolderSymlinks();
@@ -614,8 +645,8 @@ async function buildAppFiles(files, isDev2) {
614
645
  dataFiles
615
646
  };
616
647
  }
617
- async function buildClientSideFiles(alpineDataFiles = [], isDev2) {
618
- const tempFilePath = path5.join(config.distTempFolder, "./app.ts");
648
+ async function buildClientSideFiles(alpineDataFiles = [], isDev2, tempClientSidePath, id) {
649
+ const tempFilePath = path5.join(config.distTempFolder, tempClientSidePath || "./app.ts");
619
650
  fs7.ensureFileSync(tempFilePath);
620
651
  const pagesScriptsGlob = config.publicDir + "/scripts/pages/**/*.{js,ts}";
621
652
  const clientFiles = globSync3(
@@ -642,7 +673,7 @@ async function buildClientSideFiles(alpineDataFiles = [], isDev2) {
642
673
  minify: !isDev2,
643
674
  sourcemap: isDev2 ? "inline" : false
644
675
  });
645
- await logSize(config.distPublicDir, "client");
676
+ await logSize(config.distPublicDir, id ? `client bundle: ${id}.js` : "client bundle: app.js");
646
677
  }
647
678
  function writeDevServerClientSideCode(tempFilePath) {
648
679
  const devServerPath = path5.join(xpineDistDir, "./src/static/dev-server.js");
@@ -654,7 +685,7 @@ function writeSpaClientSideCode(tempFilePath) {
654
685
  const content = fs7.readFileSync(spaPath, "utf-8");
655
686
  fs7.appendFileSync(tempFilePath, "\n" + content);
656
687
  }
657
- async function buildAlpineDataFile(componentData, dataFiles) {
688
+ async function buildAlpineDataFile(componentData, dataFiles, bundleID) {
658
689
  const output = {
659
690
  imports: [
660
691
  "import Alpine from 'alpinejs';"
@@ -698,9 +729,16 @@ async function buildAlpineDataFile(componentData, dataFiles) {
698
729
  output.code.push(`Alpine.data('${dataFunction.name}', ${dataFunction.name});`);
699
730
  }
700
731
  const result = output.imports.join("\n") + "\n" + output.code.join("\n") + "\n" + output.end.join("\n");
701
- fs7.ensureFileSync(config.alpineDataPath);
702
- fs7.writeFileSync(config.alpineDataPath, result);
703
- return config.alpineDataPath;
732
+ if (bundleID) {
733
+ const bundlePath = path5.join(config.distTempFolder, `./alpine-data-${bundleID}.ts`);
734
+ fs7.ensureFileSync(bundlePath);
735
+ fs7.writeFileSync(bundlePath, result);
736
+ return bundlePath;
737
+ } else {
738
+ fs7.ensureFileSync(config.alpineDataPath);
739
+ fs7.writeFileSync(config.alpineDataPath, result);
740
+ return config.alpineDataPath;
741
+ }
704
742
  }
705
743
  async function buildPublicFolderSymlinks() {
706
744
  const files = globSync3(config.publicDir + "/**/*.*", {
@@ -833,7 +871,7 @@ async function buildOnLoadFile(componentData, isDev2) {
833
871
  return a.path.localeCompare(b.path);
834
872
  });
835
873
  for (const file of onLoadFiles) {
836
- const result = getXpineOnLoadFunction(file.path, file.source, onLoadFileResult);
874
+ const result = getXpineOnLoadFunction(file.path, file.source, { convertPathsToJS: true });
837
875
  onLoadFileResult.fn += result.fn;
838
876
  onLoadFileResult.imports += result.imports;
839
877
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xpine",
3
- "version": "0.0.47",
3
+ "version": "0.0.49",
4
4
  "main": "dist/index.js",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-secrets-manager": "^3.758.0",
@@ -14,6 +14,7 @@
14
14
  "fs-extra": "^11.3.0",
15
15
  "glob": "^11.0.1",
16
16
  "jsonwebtoken": "^9.0.2",
17
+ "micromatch": "^4.0.8",
17
18
  "postcss": "^8.5.3",
18
19
  "request-ip": "^3.3.0",
19
20
  "shelljs": "^0.9.2",
@@ -48,6 +49,7 @@
48
49
  "@eslint/js": "^9.24.0",
49
50
  "@tailwindcss/oxide-darwin-arm64": "^4.1.3",
50
51
  "@types/express": "^5.0.0",
52
+ "@types/micromatch": "^4.0.9",
51
53
  "@types/node": "^22.13.5",
52
54
  "@types/request-ip": "^0.0.41",
53
55
  "@types/shelljs": "^0.8.15",