@granite-js/plugin-core 0.1.9 → 0.1.11

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @granite-js/plugin-core
2
2
 
3
+ ## 0.1.11
4
+
5
+ ### Patch Changes
6
+
7
+ - d3a2b58: improve resolver plugin
8
+ - @granite-js/utils@0.1.11
9
+
10
+ ## 0.1.10
11
+
12
+ ### Patch Changes
13
+
14
+ - 9438be5: add dynamic config support
15
+ - @granite-js/utils@0.1.10
16
+
3
17
  ## 0.1.9
4
18
 
5
19
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -22,7 +22,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
 
23
23
  //#endregion
24
24
  const es_toolkit = __toESM(require("es-toolkit"));
25
+ const path = __toESM(require("path"));
26
+ const __granite_js_utils = __toESM(require("@granite-js/utils"));
27
+ const fs = __toESM(require("fs"));
25
28
  const zod = __toESM(require("zod"));
29
+ const cosmiconfig = __toESM(require("cosmiconfig"));
30
+ const cosmiconfig_typescript_loader = __toESM(require("cosmiconfig-typescript-loader"));
26
31
 
27
32
  //#region src/createContext.ts
28
33
  function createContext() {
@@ -319,6 +324,35 @@ function createPluginContext() {
319
324
  return context;
320
325
  }
321
326
 
327
+ //#endregion
328
+ //#region src/utils/buildResult.ts
329
+ function isBuildSuccess(result) {
330
+ return "bundle" in result;
331
+ }
332
+ function isBuildFailure(result) {
333
+ return !("bundle" in result);
334
+ }
335
+
336
+ //#endregion
337
+ //#region src/config/graniteGlobals.ts
338
+ function prepareGraniteGlobalsScript(config) {
339
+ const filePath = writeGraniteGlobalsScript(config);
340
+ return {
341
+ esbuild: { prelude: [filePath] },
342
+ metro: { serializer: { getPolyfills: () => [filePath] } }
343
+ };
344
+ }
345
+ function writeGraniteGlobalsScript(config) {
346
+ const script = getGraniteGlobalScript(config);
347
+ const filePath = path.default.join((0, __granite_js_utils.getLocalTempDirectoryPath)(config.rootDir), "granite-globals.js");
348
+ (0, __granite_js_utils.prepareLocalDirectory)(config.rootDir);
349
+ fs.default.writeFileSync(filePath, script, "utf-8");
350
+ return filePath;
351
+ }
352
+ function getGraniteGlobalScript({ appName, scheme }) {
353
+ return ["global.__granite = global.__granite || {};", `global.__granite.app = { name: ${JSON.stringify(appName)}, scheme: ${JSON.stringify(scheme)} };`].join("\n");
354
+ }
355
+
322
356
  //#endregion
323
357
  //#region src/schema/pluginConfig.ts
324
358
  const pluginConfigSchema = zod.object({
@@ -333,11 +367,130 @@ const pluginConfigSchema = zod.object({
333
367
  plugins: zod.custom()
334
368
  });
335
369
 
370
+ //#endregion
371
+ //#region src/config/defineConfig.ts
372
+ /**
373
+ * @public
374
+ * @category Configuration
375
+ * @name defineConfig
376
+ * @description
377
+ * Configures your Granite application by defining key settings in `granite.config.ts`.
378
+ *
379
+ * The configuration lets you specify:
380
+ * - How users will access your app through a URL scheme (e.g. `granite://`)
381
+ * - Your app's unique name that appears in the URL (e.g. `granite://my-service`)
382
+ * - Build settings for bundlers like ESBuild and Metro
383
+ * - Code transformation settings through Babel
384
+ * - Additional functionality through Granite plugins
385
+ *
386
+ * @param config - Configuration options
387
+ * @param config.cwd - Working directory for build process (defaults to process.cwd())
388
+ * @param config.appName - Your app's unique identifier
389
+ * @param config.scheme - URL scheme for launching your app (e.g. 'granite')
390
+ * @param config.outdir - Where to output build files (defaults to 'dist')
391
+ * @param config.entryFile - Your app's entry point (defaults to './src/_app.tsx')
392
+ * @param config.build - Customize build settings
393
+ * @param config.metro - Configure Metro bundler settings
394
+ * @param config.devServer - Configure Mpack dev server settings
395
+ * @param config.plugins - Granite plugins to enhance functionality
396
+ * @returns The processed configuration
397
+ *
398
+ * @example
399
+ * Here's a basic configuration that:
400
+ * - Makes your app accessible via the `granite://` scheme
401
+ * - Names your service "my-app" so it's reachable at `granite://my-app`
402
+ * - Uses the Hermes plugin to optimize JavaScript bundles into bytecode
403
+ *
404
+ * ```ts
405
+ * import { defineConfig } from '@granite-js/react-native/config';
406
+ * import { hermes } from '@granite-js/plugin-hermes';
407
+ *
408
+ * export default defineConfig({
409
+ * // The name of your microservice
410
+ * appName: 'my-app',
411
+ * // The URL scheme for deep linking
412
+ * scheme: 'granite',
413
+ * // Entry file path
414
+ * entryFile: 'index.ts',
415
+ * // Array of plugins to use
416
+ * plugins: [hermes()],
417
+ * });
418
+ * ```
419
+ */
420
+ const defineConfig = async (config) => {
421
+ const parsed = pluginConfigSchema.parse(config);
422
+ const cwd = parsed.cwd ?? (0, __granite_js_utils.getPackageRoot)();
423
+ const appName = parsed.appName;
424
+ const scheme = parsed.scheme;
425
+ const entryFile = path.default.resolve(cwd, parsed.entryFile);
426
+ const outdir = path.default.join(cwd, parsed.outdir);
427
+ const parsedBuildConfig = parsed.build;
428
+ const parsedDevServerConfig = parsed.devServer;
429
+ const parsedMetroConfig = parsed.metro;
430
+ const parsedConfig = {
431
+ ...parsedBuildConfig,
432
+ devServer: parsedDevServerConfig,
433
+ metro: parsedMetroConfig
434
+ };
435
+ const { configs, pluginHooks } = await resolvePlugins(parsed.plugins);
436
+ const globalsScriptConfig = prepareGraniteGlobalsScript({
437
+ rootDir: cwd,
438
+ appName,
439
+ scheme
440
+ });
441
+ const mergedConfig = mergeConfig(parsedConfig, ...[globalsScriptConfig, ...configs].filter(es_toolkit.isNotNil));
442
+ const { metro, devServer,...build } = mergedConfig ?? {};
443
+ return {
444
+ cwd,
445
+ appName,
446
+ entryFile,
447
+ outdir,
448
+ build,
449
+ devServer,
450
+ pluginHooks,
451
+ metro: {
452
+ ...metro,
453
+ babelConfig: mergedConfig?.babel,
454
+ transformSync: mergedConfig?.transformer?.transformSync
455
+ }
456
+ };
457
+ };
458
+
459
+ //#endregion
460
+ //#region src/config/loadConfig.ts
461
+ const MODULE_NAME = "granite";
462
+ const loadConfig = async (options = {}) => {
463
+ let result;
464
+ if (options.configFile) result = await getConfigExplorer().load(path.default.resolve(options.root ?? (0, __granite_js_utils.getPackageRoot)(), options.configFile));
465
+ else result = await getConfigExplorer({ searchPlaces: [
466
+ `${MODULE_NAME}.config.ts`,
467
+ `${MODULE_NAME}.config.mts`,
468
+ `${MODULE_NAME}.config.js`,
469
+ `${MODULE_NAME}.config.cjs`
470
+ ] }).search(options.root);
471
+ (0, es_toolkit.assert)(result, "Config file not found");
472
+ const config = await result.config;
473
+ return config;
474
+ };
475
+ function getConfigExplorer(options) {
476
+ return (0, cosmiconfig.cosmiconfig)(MODULE_NAME, {
477
+ loaders: {
478
+ ".ts": (0, cosmiconfig_typescript_loader.TypeScriptLoader)(),
479
+ ".mts": (0, cosmiconfig_typescript_loader.TypeScriptLoader)()
480
+ },
481
+ ...options
482
+ });
483
+ }
484
+
336
485
  //#endregion
337
486
  exports.createContext = createContext;
338
487
  exports.createPluginContext = createPluginContext;
339
488
  exports.createPluginHooksDriver = createPluginHooksDriver;
489
+ exports.defineConfig = defineConfig;
340
490
  exports.flattenPlugins = flattenPlugins;
491
+ exports.isBuildFailure = isBuildFailure;
492
+ exports.isBuildSuccess = isBuildSuccess;
493
+ exports.loadConfig = loadConfig;
341
494
  exports.mergeBuildConfigs = mergeBuildConfigs;
342
495
  exports.mergeConfig = mergeConfig;
343
496
  exports.pluginConfigSchema = pluginConfigSchema;
package/dist/index.d.cts CHANGED
@@ -5,6 +5,7 @@ import { HandleFunction } from "connect";
5
5
  import { FastifyPluginAsync, FastifyPluginCallback } from "fastify";
6
6
  import * as babel from "@babel/core";
7
7
  import * as z from "zod";
8
+ import { BuildFailureResult as BuildFailureResult$1, BuildResult as BuildResult$1, BuildSuccessResult as BuildSuccessResult$1 } from "@granite-js/plugin-core";
8
9
 
9
10
  //#region src/types/BuildConfig.d.ts
10
11
  interface BuildConfig {
@@ -84,7 +85,7 @@ interface ResolverConfig {
84
85
  */
85
86
  protocols?: ProtocolConfig;
86
87
  }
87
- interface AliasConfig {
88
+ interface AliasConfig extends Pick<esbuild$1.ResolveOptions, 'importer' | 'kind' | 'resolveDir' | 'with'> {
88
89
  /**
89
90
  * Replacement target module path
90
91
  */
@@ -92,10 +93,7 @@ interface AliasConfig {
92
93
  /**
93
94
  * Replacement module path or function that returns module path
94
95
  */
95
- to: string | ((context: {
96
- args: esbuild$1.OnResolveArgs;
97
- resolve: esbuild$1.PluginBuild['resolve'];
98
- }) => string | Promise<string>);
96
+ to: ResolveResult | AliasResolver;
99
97
  /**
100
98
  * - `false`: (default) replace even if subpath exists (`^name(?:$|/)`)
101
99
  * - `true`: replace only if the target is exactly matched (`^name$`)
@@ -123,6 +121,14 @@ interface AliasConfig {
123
121
  */
124
122
  exact?: boolean;
125
123
  }
124
+ type ResolveResult = string | ResolveResultWithOptions;
125
+ interface ResolveResultWithOptions extends Omit<esbuild$1.ResolveOptions, 'pluginName' | 'pluginData'> {
126
+ path: string;
127
+ }
128
+ type AliasResolver = (context: {
129
+ args: esbuild$1.OnResolveArgs;
130
+ resolve: esbuild$1.PluginBuild['resolve'];
131
+ }) => ResolveResult | Promise<ResolveResult>;
126
132
  /**
127
133
  * Custom protocol resolve configuration
128
134
  *
@@ -201,7 +207,8 @@ interface BabelConfig {
201
207
  plugins?: (string | [string, any])[];
202
208
  } //#endregion
203
209
  //#region src/types/BuildResult.d.ts
204
- interface BuildResult extends esbuild.BuildResult {
210
+ type BuildResult = BuildSuccessResult | BuildFailureResult;
211
+ interface BuildSuccessResult extends esbuild.BuildResult {
205
212
  bundle: BundleData;
206
213
  outfile: BuildConfig['outfile'];
207
214
  sourcemapOutfile: NonNullable<BuildConfig['sourcemapOutfile']>;
@@ -211,6 +218,11 @@ interface BuildResult extends esbuild.BuildResult {
211
218
  duration: number;
212
219
  size: number;
213
220
  }
221
+ interface BuildFailureResult extends esbuild.BuildResult {
222
+ platform: BuildConfig['platform'];
223
+ extra: BuildConfig['extra'];
224
+ duration: number;
225
+ }
214
226
  interface BundleData {
215
227
  source: esbuild.OutputFile;
216
228
  sourcemap: esbuild.OutputFile;
@@ -592,4 +604,80 @@ declare function createPluginHooksDriver(config: CompleteGraniteConfig): {
592
604
  declare function createPluginContext(): PluginContext;
593
605
 
594
606
  //#endregion
595
- export { AdditionalMetroConfig, AliasConfig, BabelConfig, BuildConfig, BuildResult, BundleData, CompleteGraniteConfig, DevServerConfig, EsbuildConfig, GraniteConfig, GranitePlugin, GranitePluginBuildPostHandler, GranitePluginBuildPreHandler, GranitePluginConfig, GranitePluginCore, GranitePluginDevHandlerArgs, GranitePluginDevPostHandler, GranitePluginDevPreHandler, GranitePluginHooks, GranitePluginPostHandlerArgs, GranitePluginPreHandlerArgs, MetroDevServerConfig, MetroMiddleware, Middleware, ParsedGraniteConfig, PluginBuildConfig, PluginConfig, PluginContext, PluginInput, PluginMetroConfig, PluginResolvable, ProtocolConfig, ResolverConfig, SwcConfig, TransformAsync, TransformSync, TransformerConfig, createContext, createPluginContext, createPluginHooksDriver, flattenPlugins, mergeBuildConfigs, mergeConfig, pluginConfigSchema, resolvePlugins };
607
+ //#region src/utils/buildResult.d.ts
608
+ declare function isBuildSuccess(result: BuildResult$1): result is BuildSuccessResult$1;
609
+ declare function isBuildFailure(result: BuildResult$1): result is BuildFailureResult$1;
610
+
611
+ //#endregion
612
+ //#region src/config/defineConfig.d.ts
613
+ /**
614
+ * @public
615
+ * @category Configuration
616
+ * @name defineConfig
617
+ * @description
618
+ * Configures your Granite application by defining key settings in `granite.config.ts`.
619
+ *
620
+ * The configuration lets you specify:
621
+ * - How users will access your app through a URL scheme (e.g. `granite://`)
622
+ * - Your app's unique name that appears in the URL (e.g. `granite://my-service`)
623
+ * - Build settings for bundlers like ESBuild and Metro
624
+ * - Code transformation settings through Babel
625
+ * - Additional functionality through Granite plugins
626
+ *
627
+ * @param config - Configuration options
628
+ * @param config.cwd - Working directory for build process (defaults to process.cwd())
629
+ * @param config.appName - Your app's unique identifier
630
+ * @param config.scheme - URL scheme for launching your app (e.g. 'granite')
631
+ * @param config.outdir - Where to output build files (defaults to 'dist')
632
+ * @param config.entryFile - Your app's entry point (defaults to './src/_app.tsx')
633
+ * @param config.build - Customize build settings
634
+ * @param config.metro - Configure Metro bundler settings
635
+ * @param config.devServer - Configure Mpack dev server settings
636
+ * @param config.plugins - Granite plugins to enhance functionality
637
+ * @returns The processed configuration
638
+ *
639
+ * @example
640
+ * Here's a basic configuration that:
641
+ * - Makes your app accessible via the `granite://` scheme
642
+ * - Names your service "my-app" so it's reachable at `granite://my-app`
643
+ * - Uses the Hermes plugin to optimize JavaScript bundles into bytecode
644
+ *
645
+ * ```ts
646
+ * import { defineConfig } from '@granite-js/react-native/config';
647
+ * import { hermes } from '@granite-js/plugin-hermes';
648
+ *
649
+ * export default defineConfig({
650
+ * // The name of your microservice
651
+ * appName: 'my-app',
652
+ * // The URL scheme for deep linking
653
+ * scheme: 'granite',
654
+ * // Entry file path
655
+ * entryFile: 'index.ts',
656
+ * // Array of plugins to use
657
+ * plugins: [hermes()],
658
+ * });
659
+ * ```
660
+ */
661
+ declare const defineConfig: (config: GraniteConfig) => Promise<CompleteGraniteConfig>;
662
+
663
+ //#endregion
664
+ //#region src/config/loadConfig.d.ts
665
+ interface LoadConfigOptions {
666
+ /**
667
+ * Root directory to search for the config file.
668
+ *
669
+ * Defaults to project root
670
+ */
671
+ root?: string;
672
+ /**
673
+ * Exact path to the config file.
674
+ *
675
+ * If provided, the config file will be loaded from the given path.
676
+ * Otherwise, the config file will be searched for in the root directory.
677
+ */
678
+ configFile?: string;
679
+ }
680
+ declare const loadConfig: (options?: LoadConfigOptions) => Promise<CompleteGraniteConfig>;
681
+
682
+ //#endregion
683
+ export { AdditionalMetroConfig, AliasConfig, AliasResolver, BabelConfig, BuildConfig, BuildFailureResult, BuildResult, BuildSuccessResult, BundleData, CompleteGraniteConfig, DevServerConfig, EsbuildConfig, GraniteConfig, GranitePlugin, GranitePluginBuildPostHandler, GranitePluginBuildPreHandler, GranitePluginConfig, GranitePluginCore, GranitePluginDevHandlerArgs, GranitePluginDevPostHandler, GranitePluginDevPreHandler, GranitePluginHooks, GranitePluginPostHandlerArgs, GranitePluginPreHandlerArgs, MetroDevServerConfig, MetroMiddleware, Middleware, ParsedGraniteConfig, PluginBuildConfig, PluginConfig, PluginContext, PluginInput, PluginMetroConfig, PluginResolvable, ProtocolConfig, ResolveResult, ResolveResultWithOptions, ResolverConfig, SwcConfig, TransformAsync, TransformSync, TransformerConfig, createContext, createPluginContext, createPluginHooksDriver, defineConfig, flattenPlugins, isBuildFailure, isBuildSuccess, loadConfig, mergeBuildConfigs, mergeConfig, pluginConfigSchema, resolvePlugins };
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ import * as esbuild from "esbuild";
5
5
  import { HandleFunction } from "connect";
6
6
  import { FastifyPluginAsync, FastifyPluginCallback } from "fastify";
7
7
  import * as babel from "@babel/core";
8
+ import { BuildFailureResult as BuildFailureResult$1, BuildResult as BuildResult$1, BuildSuccessResult as BuildSuccessResult$1 } from "@granite-js/plugin-core";
8
9
 
9
10
  //#region src/types/BuildConfig.d.ts
10
11
  interface BuildConfig {
@@ -84,7 +85,7 @@ interface ResolverConfig {
84
85
  */
85
86
  protocols?: ProtocolConfig;
86
87
  }
87
- interface AliasConfig {
88
+ interface AliasConfig extends Pick<esbuild$1.ResolveOptions, 'importer' | 'kind' | 'resolveDir' | 'with'> {
88
89
  /**
89
90
  * Replacement target module path
90
91
  */
@@ -92,10 +93,7 @@ interface AliasConfig {
92
93
  /**
93
94
  * Replacement module path or function that returns module path
94
95
  */
95
- to: string | ((context: {
96
- args: esbuild$1.OnResolveArgs;
97
- resolve: esbuild$1.PluginBuild['resolve'];
98
- }) => string | Promise<string>);
96
+ to: ResolveResult | AliasResolver;
99
97
  /**
100
98
  * - `false`: (default) replace even if subpath exists (`^name(?:$|/)`)
101
99
  * - `true`: replace only if the target is exactly matched (`^name$`)
@@ -123,6 +121,14 @@ interface AliasConfig {
123
121
  */
124
122
  exact?: boolean;
125
123
  }
124
+ type ResolveResult = string | ResolveResultWithOptions;
125
+ interface ResolveResultWithOptions extends Omit<esbuild$1.ResolveOptions, 'pluginName' | 'pluginData'> {
126
+ path: string;
127
+ }
128
+ type AliasResolver = (context: {
129
+ args: esbuild$1.OnResolveArgs;
130
+ resolve: esbuild$1.PluginBuild['resolve'];
131
+ }) => ResolveResult | Promise<ResolveResult>;
126
132
  /**
127
133
  * Custom protocol resolve configuration
128
134
  *
@@ -201,7 +207,8 @@ interface BabelConfig {
201
207
  plugins?: (string | [string, any])[];
202
208
  } //#endregion
203
209
  //#region src/types/BuildResult.d.ts
204
- interface BuildResult extends esbuild.BuildResult {
210
+ type BuildResult = BuildSuccessResult | BuildFailureResult;
211
+ interface BuildSuccessResult extends esbuild.BuildResult {
205
212
  bundle: BundleData;
206
213
  outfile: BuildConfig['outfile'];
207
214
  sourcemapOutfile: NonNullable<BuildConfig['sourcemapOutfile']>;
@@ -211,6 +218,11 @@ interface BuildResult extends esbuild.BuildResult {
211
218
  duration: number;
212
219
  size: number;
213
220
  }
221
+ interface BuildFailureResult extends esbuild.BuildResult {
222
+ platform: BuildConfig['platform'];
223
+ extra: BuildConfig['extra'];
224
+ duration: number;
225
+ }
214
226
  interface BundleData {
215
227
  source: esbuild.OutputFile;
216
228
  sourcemap: esbuild.OutputFile;
@@ -592,4 +604,80 @@ declare function createPluginHooksDriver(config: CompleteGraniteConfig): {
592
604
  declare function createPluginContext(): PluginContext;
593
605
 
594
606
  //#endregion
595
- export { AdditionalMetroConfig, AliasConfig, BabelConfig, BuildConfig, BuildResult, BundleData, CompleteGraniteConfig, DevServerConfig, EsbuildConfig, GraniteConfig, GranitePlugin, GranitePluginBuildPostHandler, GranitePluginBuildPreHandler, GranitePluginConfig, GranitePluginCore, GranitePluginDevHandlerArgs, GranitePluginDevPostHandler, GranitePluginDevPreHandler, GranitePluginHooks, GranitePluginPostHandlerArgs, GranitePluginPreHandlerArgs, MetroDevServerConfig, MetroMiddleware, Middleware, ParsedGraniteConfig, PluginBuildConfig, PluginConfig, PluginContext, PluginInput, PluginMetroConfig, PluginResolvable, ProtocolConfig, ResolverConfig, SwcConfig, TransformAsync, TransformSync, TransformerConfig, createContext, createPluginContext, createPluginHooksDriver, flattenPlugins, mergeBuildConfigs, mergeConfig, pluginConfigSchema, resolvePlugins };
607
+ //#region src/utils/buildResult.d.ts
608
+ declare function isBuildSuccess(result: BuildResult$1): result is BuildSuccessResult$1;
609
+ declare function isBuildFailure(result: BuildResult$1): result is BuildFailureResult$1;
610
+
611
+ //#endregion
612
+ //#region src/config/defineConfig.d.ts
613
+ /**
614
+ * @public
615
+ * @category Configuration
616
+ * @name defineConfig
617
+ * @description
618
+ * Configures your Granite application by defining key settings in `granite.config.ts`.
619
+ *
620
+ * The configuration lets you specify:
621
+ * - How users will access your app through a URL scheme (e.g. `granite://`)
622
+ * - Your app's unique name that appears in the URL (e.g. `granite://my-service`)
623
+ * - Build settings for bundlers like ESBuild and Metro
624
+ * - Code transformation settings through Babel
625
+ * - Additional functionality through Granite plugins
626
+ *
627
+ * @param config - Configuration options
628
+ * @param config.cwd - Working directory for build process (defaults to process.cwd())
629
+ * @param config.appName - Your app's unique identifier
630
+ * @param config.scheme - URL scheme for launching your app (e.g. 'granite')
631
+ * @param config.outdir - Where to output build files (defaults to 'dist')
632
+ * @param config.entryFile - Your app's entry point (defaults to './src/_app.tsx')
633
+ * @param config.build - Customize build settings
634
+ * @param config.metro - Configure Metro bundler settings
635
+ * @param config.devServer - Configure Mpack dev server settings
636
+ * @param config.plugins - Granite plugins to enhance functionality
637
+ * @returns The processed configuration
638
+ *
639
+ * @example
640
+ * Here's a basic configuration that:
641
+ * - Makes your app accessible via the `granite://` scheme
642
+ * - Names your service "my-app" so it's reachable at `granite://my-app`
643
+ * - Uses the Hermes plugin to optimize JavaScript bundles into bytecode
644
+ *
645
+ * ```ts
646
+ * import { defineConfig } from '@granite-js/react-native/config';
647
+ * import { hermes } from '@granite-js/plugin-hermes';
648
+ *
649
+ * export default defineConfig({
650
+ * // The name of your microservice
651
+ * appName: 'my-app',
652
+ * // The URL scheme for deep linking
653
+ * scheme: 'granite',
654
+ * // Entry file path
655
+ * entryFile: 'index.ts',
656
+ * // Array of plugins to use
657
+ * plugins: [hermes()],
658
+ * });
659
+ * ```
660
+ */
661
+ declare const defineConfig: (config: GraniteConfig) => Promise<CompleteGraniteConfig>;
662
+
663
+ //#endregion
664
+ //#region src/config/loadConfig.d.ts
665
+ interface LoadConfigOptions {
666
+ /**
667
+ * Root directory to search for the config file.
668
+ *
669
+ * Defaults to project root
670
+ */
671
+ root?: string;
672
+ /**
673
+ * Exact path to the config file.
674
+ *
675
+ * If provided, the config file will be loaded from the given path.
676
+ * Otherwise, the config file will be searched for in the root directory.
677
+ */
678
+ configFile?: string;
679
+ }
680
+ declare const loadConfig: (options?: LoadConfigOptions) => Promise<CompleteGraniteConfig>;
681
+
682
+ //#endregion
683
+ export { AdditionalMetroConfig, AliasConfig, AliasResolver, BabelConfig, BuildConfig, BuildFailureResult, BuildResult, BuildSuccessResult, BundleData, CompleteGraniteConfig, DevServerConfig, EsbuildConfig, GraniteConfig, GranitePlugin, GranitePluginBuildPostHandler, GranitePluginBuildPreHandler, GranitePluginConfig, GranitePluginCore, GranitePluginDevHandlerArgs, GranitePluginDevPostHandler, GranitePluginDevPreHandler, GranitePluginHooks, GranitePluginPostHandlerArgs, GranitePluginPreHandlerArgs, MetroDevServerConfig, MetroMiddleware, Middleware, ParsedGraniteConfig, PluginBuildConfig, PluginConfig, PluginContext, PluginInput, PluginMetroConfig, PluginResolvable, ProtocolConfig, ResolveResult, ResolveResultWithOptions, ResolverConfig, SwcConfig, TransformAsync, TransformSync, TransformerConfig, createContext, createPluginContext, createPluginHooksDriver, defineConfig, flattenPlugins, isBuildFailure, isBuildSuccess, loadConfig, mergeBuildConfigs, mergeConfig, pluginConfigSchema, resolvePlugins };
package/dist/index.js CHANGED
@@ -1,5 +1,10 @@
1
- import { isNotNil } from "es-toolkit";
1
+ import { assert, isNotNil } from "es-toolkit";
2
+ import path from "path";
3
+ import { getLocalTempDirectoryPath, getPackageRoot, prepareLocalDirectory } from "@granite-js/utils";
4
+ import fs from "fs";
2
5
  import * as z from "zod";
6
+ import { cosmiconfig } from "cosmiconfig";
7
+ import { TypeScriptLoader } from "cosmiconfig-typescript-loader";
3
8
 
4
9
  //#region src/createContext.ts
5
10
  function createContext() {
@@ -296,6 +301,35 @@ function createPluginContext() {
296
301
  return context;
297
302
  }
298
303
 
304
+ //#endregion
305
+ //#region src/utils/buildResult.ts
306
+ function isBuildSuccess(result) {
307
+ return "bundle" in result;
308
+ }
309
+ function isBuildFailure(result) {
310
+ return !("bundle" in result);
311
+ }
312
+
313
+ //#endregion
314
+ //#region src/config/graniteGlobals.ts
315
+ function prepareGraniteGlobalsScript(config) {
316
+ const filePath = writeGraniteGlobalsScript(config);
317
+ return {
318
+ esbuild: { prelude: [filePath] },
319
+ metro: { serializer: { getPolyfills: () => [filePath] } }
320
+ };
321
+ }
322
+ function writeGraniteGlobalsScript(config) {
323
+ const script = getGraniteGlobalScript(config);
324
+ const filePath = path.join(getLocalTempDirectoryPath(config.rootDir), "granite-globals.js");
325
+ prepareLocalDirectory(config.rootDir);
326
+ fs.writeFileSync(filePath, script, "utf-8");
327
+ return filePath;
328
+ }
329
+ function getGraniteGlobalScript({ appName, scheme }) {
330
+ return ["global.__granite = global.__granite || {};", `global.__granite.app = { name: ${JSON.stringify(appName)}, scheme: ${JSON.stringify(scheme)} };`].join("\n");
331
+ }
332
+
299
333
  //#endregion
300
334
  //#region src/schema/pluginConfig.ts
301
335
  const pluginConfigSchema = z.object({
@@ -311,4 +345,119 @@ const pluginConfigSchema = z.object({
311
345
  });
312
346
 
313
347
  //#endregion
314
- export { createContext, createPluginContext, createPluginHooksDriver, flattenPlugins, mergeBuildConfigs, mergeConfig, pluginConfigSchema, resolvePlugins };
348
+ //#region src/config/defineConfig.ts
349
+ /**
350
+ * @public
351
+ * @category Configuration
352
+ * @name defineConfig
353
+ * @description
354
+ * Configures your Granite application by defining key settings in `granite.config.ts`.
355
+ *
356
+ * The configuration lets you specify:
357
+ * - How users will access your app through a URL scheme (e.g. `granite://`)
358
+ * - Your app's unique name that appears in the URL (e.g. `granite://my-service`)
359
+ * - Build settings for bundlers like ESBuild and Metro
360
+ * - Code transformation settings through Babel
361
+ * - Additional functionality through Granite plugins
362
+ *
363
+ * @param config - Configuration options
364
+ * @param config.cwd - Working directory for build process (defaults to process.cwd())
365
+ * @param config.appName - Your app's unique identifier
366
+ * @param config.scheme - URL scheme for launching your app (e.g. 'granite')
367
+ * @param config.outdir - Where to output build files (defaults to 'dist')
368
+ * @param config.entryFile - Your app's entry point (defaults to './src/_app.tsx')
369
+ * @param config.build - Customize build settings
370
+ * @param config.metro - Configure Metro bundler settings
371
+ * @param config.devServer - Configure Mpack dev server settings
372
+ * @param config.plugins - Granite plugins to enhance functionality
373
+ * @returns The processed configuration
374
+ *
375
+ * @example
376
+ * Here's a basic configuration that:
377
+ * - Makes your app accessible via the `granite://` scheme
378
+ * - Names your service "my-app" so it's reachable at `granite://my-app`
379
+ * - Uses the Hermes plugin to optimize JavaScript bundles into bytecode
380
+ *
381
+ * ```ts
382
+ * import { defineConfig } from '@granite-js/react-native/config';
383
+ * import { hermes } from '@granite-js/plugin-hermes';
384
+ *
385
+ * export default defineConfig({
386
+ * // The name of your microservice
387
+ * appName: 'my-app',
388
+ * // The URL scheme for deep linking
389
+ * scheme: 'granite',
390
+ * // Entry file path
391
+ * entryFile: 'index.ts',
392
+ * // Array of plugins to use
393
+ * plugins: [hermes()],
394
+ * });
395
+ * ```
396
+ */
397
+ const defineConfig = async (config) => {
398
+ const parsed = pluginConfigSchema.parse(config);
399
+ const cwd = parsed.cwd ?? getPackageRoot();
400
+ const appName = parsed.appName;
401
+ const scheme = parsed.scheme;
402
+ const entryFile = path.resolve(cwd, parsed.entryFile);
403
+ const outdir = path.join(cwd, parsed.outdir);
404
+ const parsedBuildConfig = parsed.build;
405
+ const parsedDevServerConfig = parsed.devServer;
406
+ const parsedMetroConfig = parsed.metro;
407
+ const parsedConfig = {
408
+ ...parsedBuildConfig,
409
+ devServer: parsedDevServerConfig,
410
+ metro: parsedMetroConfig
411
+ };
412
+ const { configs, pluginHooks } = await resolvePlugins(parsed.plugins);
413
+ const globalsScriptConfig = prepareGraniteGlobalsScript({
414
+ rootDir: cwd,
415
+ appName,
416
+ scheme
417
+ });
418
+ const mergedConfig = mergeConfig(parsedConfig, ...[globalsScriptConfig, ...configs].filter(isNotNil));
419
+ const { metro, devServer,...build } = mergedConfig ?? {};
420
+ return {
421
+ cwd,
422
+ appName,
423
+ entryFile,
424
+ outdir,
425
+ build,
426
+ devServer,
427
+ pluginHooks,
428
+ metro: {
429
+ ...metro,
430
+ babelConfig: mergedConfig?.babel,
431
+ transformSync: mergedConfig?.transformer?.transformSync
432
+ }
433
+ };
434
+ };
435
+
436
+ //#endregion
437
+ //#region src/config/loadConfig.ts
438
+ const MODULE_NAME = "granite";
439
+ const loadConfig = async (options = {}) => {
440
+ let result;
441
+ if (options.configFile) result = await getConfigExplorer().load(path.resolve(options.root ?? getPackageRoot(), options.configFile));
442
+ else result = await getConfigExplorer({ searchPlaces: [
443
+ `${MODULE_NAME}.config.ts`,
444
+ `${MODULE_NAME}.config.mts`,
445
+ `${MODULE_NAME}.config.js`,
446
+ `${MODULE_NAME}.config.cjs`
447
+ ] }).search(options.root);
448
+ assert(result, "Config file not found");
449
+ const config = await result.config;
450
+ return config;
451
+ };
452
+ function getConfigExplorer(options) {
453
+ return cosmiconfig(MODULE_NAME, {
454
+ loaders: {
455
+ ".ts": TypeScriptLoader(),
456
+ ".mts": TypeScriptLoader()
457
+ },
458
+ ...options
459
+ });
460
+ }
461
+
462
+ //#endregion
463
+ export { createContext, createPluginContext, createPluginHooksDriver, defineConfig, flattenPlugins, isBuildFailure, isBuildSuccess, loadConfig, mergeBuildConfigs, mergeConfig, pluginConfigSchema, resolvePlugins };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@granite-js/plugin-core",
3
3
  "type": "module",
4
- "version": "0.1.9",
4
+ "version": "0.1.11",
5
5
  "description": "The core plugin module for Granite",
6
6
  "scripts": {
7
7
  "prepack": "yarn build",
@@ -31,9 +31,12 @@
31
31
  "vitest": "^3.0.9"
32
32
  },
33
33
  "dependencies": {
34
+ "@granite-js/utils": "0.1.11",
34
35
  "@swc/core": "1.5.24",
35
36
  "@types/babel__core": "^7",
36
37
  "@types/connect": "^3",
38
+ "cosmiconfig": "^9.0.0",
39
+ "cosmiconfig-typescript-loader": "^5.1.0",
37
40
  "es-toolkit": "^1.39.8",
38
41
  "esbuild": "^0.25.8",
39
42
  "fastify": "4.14.0",