rollipop 1.0.0-alpha.26 → 1.0.0-alpha.28

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.
Files changed (40) hide show
  1. package/client.d.ts +5 -1
  2. package/dist/config/index.d.ts +1 -1
  3. package/dist/config/load-config.js +2 -0
  4. package/dist/config/notice.js +7 -0
  5. package/dist/config/types.d.ts +36 -3
  6. package/dist/constants.js +1 -1
  7. package/dist/core/assets.d.ts +4 -3
  8. package/dist/core/assets.js +124 -78
  9. package/dist/core/bundler.js +2 -2
  10. package/dist/core/plugins/alias-plugin.d.ts +13 -0
  11. package/dist/core/plugins/alias-plugin.js +8 -0
  12. package/dist/core/plugins/dev-server-plugin.d.ts +4 -2
  13. package/dist/core/plugins/dev-server-plugin.js +5 -3
  14. package/dist/core/plugins/import-glob-plugin.d.ts +11 -0
  15. package/dist/core/plugins/import-glob-plugin.js +7 -0
  16. package/dist/core/plugins/index.d.ts +4 -2
  17. package/dist/core/plugins/index.js +7 -1
  18. package/dist/core/plugins/react-native-plugin.d.ts +1 -1
  19. package/dist/core/rolldown.js +44 -5
  20. package/dist/core/types.d.ts +1 -1
  21. package/dist/index.d.ts +4 -4
  22. package/dist/index.js +1 -1
  23. package/dist/internal/react-native.js +2 -5
  24. package/dist/node/commands/bundle/action.js +1 -1
  25. package/dist/node/commands/start/action.js +2 -3
  26. package/dist/package.js +1 -1
  27. package/dist/server/create-dev-server.js +0 -7
  28. package/dist/server/mcp/server.js +1 -1
  29. package/dist/server/mcp/tools/index.js +1 -1
  30. package/dist/server/middlewares/dashboard.js +8 -2
  31. package/dist/server/middlewares/serve-assets.js +5 -4
  32. package/dist/server/middlewares/symbolicate.js +20 -16
  33. package/dist/server/rest/domains/actions.js +2 -2
  34. package/dist/server/state/store.js +9 -1
  35. package/dist/server/symbolicate.js +35 -19
  36. package/dist/storage/file-storage.js +1 -1
  37. package/dist/utils/reset-cache.d.ts +2 -3
  38. package/dist/utils/reset-cache.js +4 -19
  39. package/import-glob.d.ts +129 -0
  40. package/package.json +4 -3
package/client.d.ts CHANGED
@@ -4,6 +4,10 @@ interface ImportMetaEnv {
4
4
  }
5
5
 
6
6
  interface ImportMeta {
7
- hot?: import('./dist').HMRContext;
7
+ glob: import('./import-glob').ImportGlobFunction;
8
8
  env: ImportMetaEnv;
9
+ /**
10
+ * Only available in development mode.
11
+ */
12
+ hot?: import('./dist').HMRContext;
9
13
  }
@@ -1,4 +1,4 @@
1
- import { AnalyzerConfig, BabelTransformConfig, CodegenConfig, Config, DevModeConfig, ExperimentalConfig, FlowConfig, HmrConfig, OptimizationConfig, PluginOption, Polyfill, PolyfillOptions, PolyfillType, PolyfillWithCode, PolyfillWithPath, ReactNativeConfig, ResolverConfig, RolldownConfig, RollipopReactNativeFlowConfig, RollipopReactNativeWorkletsConfig, SerializerConfig, SwcTransformConfig, TerminalConfig, TransformRule, TransformerConfig, WatcherConfig } from "./types.js";
1
+ import { AliasConfig, AnalyzerConfig, BabelTransformConfig, CodegenConfig, Config, DevModeConfig, ExperimentalConfig, FlowConfig, HmrConfig, OptimizationConfig, PluginOption, Polyfill, PolyfillOptions, PolyfillType, PolyfillWithCode, PolyfillWithPath, ReactNativeConfig, ResolverConfig, RolldownConfig, RollipopReactNativeFlowConfig, RollipopReactNativeWorkletsConfig, SerializerConfig, SwcTransformConfig, TerminalConfig, TransformRule, TransformerConfig, WatcherConfig } from "./types.js";
2
2
  import { PluginFlattenConfig, mergeConfig } from "./merge-config.js";
3
3
  import { DefaultConfig, InternalConfig, ResolvedConfig, getDefaultConfig } from "./defaults.js";
4
4
  import { DefineConfigContext, DynamicUserConfig, UserConfig, defineConfig } from "./define-config.js";
@@ -1,6 +1,7 @@
1
1
  import { getDefaultConfig } from "./defaults.js";
2
2
  import { createPluginContext } from "../core/plugins/context.js";
3
3
  import { mergeConfig } from "./merge-config.js";
4
+ import { printConfigNotice } from "./notice.js";
4
5
  import path from "node:path";
5
6
  import { invariant, omit } from "es-toolkit";
6
7
  import * as c12 from "c12";
@@ -38,6 +39,7 @@ async function loadConfig(options = {}) {
38
39
  };
39
40
  if (!path.isAbsolute(resolvedConfig.entry)) resolvedConfig.entry = path.resolve(resolvedConfig.root, resolvedConfig.entry);
40
41
  await invokeConfigResolved(resolvedConfig, plugins);
42
+ printConfigNotice(resolvedConfig);
41
43
  return resolvedConfig;
42
44
  }
43
45
  async function flattenPluginOption(pluginOption) {
@@ -0,0 +1,7 @@
1
+ import { logger } from "../logger.js";
2
+ //#region src/config/notice.ts
3
+ function printConfigNotice(config) {
4
+ if (config.transformer.reactCompiler != null) logger.info("✨ React Compiler is enabled");
5
+ }
6
+ //#endregion
7
+ export { printConfigNotice };
@@ -1,8 +1,9 @@
1
1
  import { MaybePromise, NullValue, Reporter } from "../types.js";
2
2
  import { Plugin } from "../core/plugins/types.js";
3
+ import { AliasEntry } from "../core/plugins/alias-plugin.js";
3
4
  import { InteractiveCommand } from "../node/commands/start/setup-interactive-mode.js";
4
- import * as rolldown from "@rollipop/rolldown";
5
5
  import { DevWatchOptions, RollipopReactNativeFlowConfig, RollipopReactNativeWorkletsConfig } from "@rollipop/rolldown/experimental";
6
+ import * as rolldown from "@rollipop/rolldown";
6
7
  import { TopLevelFilterExpression } from "@rollipop/rolldown/filter";
7
8
  import * as babel from "@babel/core";
8
9
  import * as swc from "@swc/core";
@@ -197,7 +198,38 @@ interface Config {
197
198
  type PluginOption = MaybePromise<NullValue<Plugin> | {
198
199
  name: string;
199
200
  } | false | PluginOption[]>;
200
- type ResolverConfig = Omit<NonNullable<rolldown.InputOptions['resolve']>, 'extensions'> & {
201
+ type ResolverConfig = Omit<NonNullable<rolldown.InputOptions['resolve']>, 'alias' | 'extensions'> & {
202
+ /**
203
+ * Substitute one package or module path for another.
204
+ *
205
+ * Object aliases are forwarded to Rolldown's native `resolve.alias`.
206
+ * Array aliases are installed through Rollipop's alias plugin so plugin
207
+ * [`resolveId`](/reference/Interface.Plugin#resolveid) hooks can participate in resolving the replacement.
208
+ *
209
+ * @example
210
+ * ```js
211
+ * // Object alias
212
+ * resolve: {
213
+ * alias: {
214
+ * '@': '/src',
215
+ * 'utils': './src/utils',
216
+ * }
217
+ * }
218
+ *
219
+ * // Array alias
220
+ * resolve: {
221
+ * alias: [
222
+ * { find: '@', replacement: '/src' },
223
+ * { find: /^utils\//, replacement: './src/utils/' },
224
+ * ]
225
+ * }
226
+ * ```
227
+ *
228
+ * > [!WARNING]
229
+ * > Object aliases use `resolve.alias`, which will not call `resolveId` hooks of other plugins.
230
+ * > Use the array form when plugin-based resolution is required.
231
+ */
232
+ alias?: AliasConfig;
201
233
  /**
202
234
  * Defaults to: `['ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'json']`
203
235
  */
@@ -226,6 +258,7 @@ type ResolverConfig = Omit<NonNullable<rolldown.InputOptions['resolve']>, 'exten
226
258
  */
227
259
  external?: rolldown.InputOptions['external'];
228
260
  };
261
+ type AliasConfig = NonNullable<rolldown.InputOptions['resolve']>['alias'] | AliasEntry[];
229
262
  type TransformerConfig = Omit<TransformOptions, 'cwd' | 'lang' | 'sourceType' | 'plugins'> & {
230
263
  /**
231
264
  * Flow specific configuration.
@@ -477,4 +510,4 @@ interface RolldownConfig {
477
510
  output?: rolldown.OutputOptions;
478
511
  }
479
512
  //#endregion
480
- export { AnalyzerConfig, BabelTransformConfig, CodegenConfig, Config, DevModeConfig, ExperimentalConfig, FlowConfig, HmrConfig, OptimizationConfig, PluginOption, Polyfill, PolyfillOptions, PolyfillType, PolyfillWithCode, PolyfillWithPath, ReactNativeConfig, ResolverConfig, RolldownConfig, type RollipopReactNativeFlowConfig, type RollipopReactNativeWorkletsConfig, SerializerConfig, SwcTransformConfig, TerminalConfig, TransformRule, TransformerConfig, WatcherConfig };
513
+ export { AliasConfig, AnalyzerConfig, BabelTransformConfig, CodegenConfig, Config, DevModeConfig, ExperimentalConfig, FlowConfig, HmrConfig, OptimizationConfig, PluginOption, Polyfill, PolyfillOptions, PolyfillType, PolyfillWithCode, PolyfillWithPath, ReactNativeConfig, ResolverConfig, RolldownConfig, type RollipopReactNativeFlowConfig, type RollipopReactNativeWorkletsConfig, SerializerConfig, SwcTransformConfig, TerminalConfig, TransformRule, TransformerConfig, WatcherConfig };
package/dist/constants.js CHANGED
@@ -19,7 +19,7 @@ var constants_exports = /* @__PURE__ */ __exportAll({
19
19
  ROLLIPOP_VIRTUAL_ENTRY_ID: () => ROLLIPOP_VIRTUAL_ENTRY_ID,
20
20
  ROLLIPOP_VIRTUAL_PREFIX: () => ROLLIPOP_VIRTUAL_PREFIX
21
21
  });
22
- const ROLLIPOP_VERSION = "1.0.0-alpha.26";
22
+ const ROLLIPOP_VERSION = "1.0.0-alpha.28";
23
23
  const ROLLIPOP_VIRTUAL_PREFIX = "\0rollipop/";
24
24
  const ROLLIPOP_VIRTUAL_ENTRY_ID = `${ROLLIPOP_VIRTUAL_PREFIX}entry`;
25
25
  /**
@@ -1,5 +1,5 @@
1
1
  declare namespace assets_d_exports {
2
- export { AssetContext, AssetData, AssetDataFiltered, AssetDataWithoutFiles, AssetInfo, AssetScale, copyAssetsToDestination, generateAssetRegistryCode, getAssetPriority, getSuffixedPath, platformSuffixPattern, resolveAssetPath, resolveScaledAssets, stripSuffix };
2
+ export { AssetContext, AssetData, AssetDataFiltered, AssetDataWithoutFiles, AssetInfo, AssetScale, copyAssetsToDestination, filterPlatformAssetScales, generateAssetRegistryCode, getAssetPriority, getSuffixedPath, platformSuffixPattern, resolveAssetPath, resolveScaledAssets, stripSuffix };
3
3
  }
4
4
  /**
5
5
  * **NOTE**: Type definitions are ported from `metro` implementation.
@@ -42,7 +42,7 @@ interface AssetData extends AssetDataWithoutFiles {
42
42
  id: string;
43
43
  files: string[];
44
44
  }
45
- type AssetScale = 0.75 | 1 | 1.5 | 2 | 3;
45
+ type AssetScale = number;
46
46
  interface ResolveScaledAssetsOptions {
47
47
  projectRoot: string;
48
48
  assetPath: string;
@@ -75,7 +75,7 @@ interface GetSuffixedPathOptions {
75
75
  * ```
76
76
  */
77
77
  declare function getSuffixedPath(assetPath: string, context: AssetContext, options: GetSuffixedPathOptions): string;
78
- declare function resolveAssetPath(assetPath: string, context: AssetContext, scale: AssetScale): string;
78
+ declare function resolveAssetPath(assetPath: string, context: AssetContext, scale?: AssetScale): string;
79
79
  interface CopyAssetsToDestinationOptions {
80
80
  assets: AssetData[];
81
81
  assetsDir: string;
@@ -86,6 +86,7 @@ interface CopyAssetsToDestinationOptions {
86
86
  * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/community-cli-plugin/src/commands/bundle/assetPathUtils.js
87
87
  */
88
88
  declare function copyAssetsToDestination(options: CopyAssetsToDestinationOptions): Promise<undefined>;
89
+ declare function filterPlatformAssetScales(platform: string, scales: readonly AssetScale[]): AssetScale[];
89
90
  declare function generateAssetRegistryCode(assetRegistryPath: string, asset: AssetData): string;
90
91
  //#endregion
91
92
  export { assets_d_exports };
@@ -15,6 +15,7 @@ import { imageSize } from "image-size";
15
15
  */
16
16
  var assets_exports = /* @__PURE__ */ __exportAll({
17
17
  copyAssetsToDestination: () => copyAssetsToDestination,
18
+ filterPlatformAssetScales: () => filterPlatformAssetScales,
18
19
  generateAssetRegistryCode: () => generateAssetRegistryCode,
19
20
  getAssetPriority: () => getAssetPriority,
20
21
  getSuffixedPath: () => getSuffixedPath,
@@ -24,6 +25,8 @@ var assets_exports = /* @__PURE__ */ __exportAll({
24
25
  stripSuffix: () => stripSuffix
25
26
  });
26
27
  const SCALE_PATTERN = "@(\\d+\\.?\\d*)x";
28
+ const ASSET_BASE_NAME_PATTERN = /(.+?)(@([\d.]+)x)?$/;
29
+ const PLATFORM_FILE_PATH_PATTERN = /^(.+?)(\.([^.]+))?\.([^.]+)$/;
27
30
  const IMAGE_ASSET_TYPES = new Set(IMAGE_EXTENSIONS);
28
31
  /**
29
32
  * key: platform,
@@ -53,51 +56,114 @@ async function resolveScaledAssets(options) {
53
56
  platform,
54
57
  preferNativePlatform
55
58
  };
56
- const extension = path.extname(assetPath);
57
- const type = extension.substring(1);
59
+ const { name, type } = parseAssetPath(path.basename(assetPath), context);
58
60
  const relativePath = path.relative(projectRoot, assetPath);
59
- const dirname = path.dirname(assetPath);
60
- const files = fs.readdirSync(dirname);
61
- const stripedBasename = stripSuffix(assetPath, context);
62
- const suffixPattern = platformSuffixPattern(context);
63
- const assetRegExp = new RegExp(`${stripedBasename}(${SCALE_PATTERN})?(?:${suffixPattern})?${extension}$`);
64
- const scaledAssets = {};
65
- for (const file of files.sort((a, b) => getAssetPriority(b, context) - getAssetPriority(a, context))) {
66
- const match = assetRegExp.exec(file);
67
- if (match) {
68
- const [, , scale = "1"] = match;
69
- if (scaledAssets[scale]) continue;
70
- scaledAssets[scale] = file;
71
- }
72
- }
73
- if (!(Object.keys(scaledAssets).length && scaledAssets[1])) throw new Error(`cannot resolve base asset of ${assetPath}`);
74
- const imageData = fs.readFileSync(assetPath);
75
- const dimensions = IMAGE_ASSET_TYPES.has(type) ? imageSize(imageData) : void 0;
76
- const filteredScaledAssets = Object.entries(scaledAssets).map(([scale, file]) => ({
77
- scale: parseFloat(scale),
78
- file
79
- })).filter(({ scale }) => ALLOW_SCALES[platform]?.includes(scale) ?? true).reduce((acc, { scale, file }) => {
80
- acc.files.push(file);
81
- acc.scales.push(scale);
82
- return acc;
83
- }, {
84
- scales: [],
85
- files: []
86
- });
61
+ const { files, scales } = getAbsoluteAssetRecord(assetPath, context);
62
+ const fileData = await Promise.all(files.map((file) => fs.promises.readFile(file)));
63
+ const hash = md5(Buffer.concat(fileData));
64
+ const firstScale = scales[0] ?? 1;
65
+ const dimensions = IMAGE_ASSET_TYPES.has(type) ? imageSize(fileData[0]) : void 0;
87
66
  return {
88
67
  __packager_asset: true,
89
68
  id: assetPath,
90
- name: stripedBasename.replace(extension, ""),
69
+ name,
91
70
  type,
92
- width: dimensions?.width,
93
- height: dimensions?.height,
94
- files: filteredScaledAssets.files,
95
- scales: filteredScaledAssets.scales,
71
+ width: dimensions?.width == null ? void 0 : dimensions.width / firstScale,
72
+ height: dimensions?.height == null ? void 0 : dimensions.height / firstScale,
73
+ files,
74
+ scales,
96
75
  fileSystemLocation: path.dirname(assetPath),
97
- httpServerLocation: path.join(DEV_SERVER_ASSET_PATH, path.dirname(relativePath)),
98
- hash: md5(imageData)
76
+ httpServerLocation: getHttpServerLocation(relativePath),
77
+ hash
78
+ };
79
+ }
80
+ function getHttpServerLocation(relativePath) {
81
+ const dirname = path.dirname(relativePath);
82
+ return normalizePathSeparatorsToPosix(relativePath.startsWith("..") ? `/${DEV_SERVER_ASSET_PATH}/${dirname}` : path.join("/", DEV_SERVER_ASSET_PATH, dirname));
83
+ }
84
+ function normalizePathSeparatorsToPosix(filePath) {
85
+ return filePath.replace(/\\/g, "/");
86
+ }
87
+ function getAssetPlatforms(context) {
88
+ return [context.platform, context.preferNativePlatform ? "native" : null].filter(isNotNil);
89
+ }
90
+ function parseBaseName(baseName) {
91
+ const match = ASSET_BASE_NAME_PATTERN.exec(baseName);
92
+ if (match == null) throw new Error(`invalid asset name: ${baseName}`);
93
+ const [, rootName, , resolution] = match;
94
+ if (resolution != null) {
95
+ const parsedResolution = Number.parseFloat(resolution);
96
+ if (!Number.isNaN(parsedResolution)) return {
97
+ resolution: parsedResolution,
98
+ rootName
99
+ };
100
+ }
101
+ return {
102
+ resolution: 1,
103
+ rootName
104
+ };
105
+ }
106
+ function tryParseAssetPath(filePath, context) {
107
+ const dirname = path.dirname(filePath);
108
+ const fileName = path.basename(filePath);
109
+ const match = PLATFORM_FILE_PATH_PATTERN.exec(fileName);
110
+ if (match == null) return null;
111
+ const [, baseName, , platformCandidate, extension] = match;
112
+ const platforms = new Set(getAssetPlatforms(context));
113
+ const platform = platformCandidate != null && platforms.has(platformCandidate) ? platformCandidate : void 0;
114
+ const { resolution, rootName } = parseBaseName(platform == null && platformCandidate != null ? `${baseName}.${platformCandidate}` : baseName);
115
+ return {
116
+ assetName: path.join(dirname, `${rootName}.${extension}`),
117
+ name: rootName,
118
+ platform,
119
+ resolution,
120
+ type: extension
99
121
  };
100
122
  }
123
+ function parseAssetPath(filePath, context) {
124
+ const assetPath = tryParseAssetPath(filePath, context);
125
+ if (assetPath == null) throw new Error(`invalid asset file path: ${filePath}`);
126
+ return assetPath;
127
+ }
128
+ function getAssetKey(assetName, platform) {
129
+ return platform == null ? assetName : `${assetName} : ${platform}`;
130
+ }
131
+ function buildAssetMap(dirname, files, context) {
132
+ const assetMap = /* @__PURE__ */ new Map();
133
+ for (const file of files) {
134
+ const asset = tryParseAssetPath(file, context);
135
+ if (asset == null) continue;
136
+ const assetKey = getAssetKey(asset.assetName, asset.platform);
137
+ let record = assetMap.get(assetKey);
138
+ if (record == null) {
139
+ record = {
140
+ files: [],
141
+ scales: []
142
+ };
143
+ assetMap.set(assetKey, record);
144
+ }
145
+ let insertIndex = 0;
146
+ while (insertIndex < record.scales.length && asset.resolution >= record.scales[insertIndex]) insertIndex += 1;
147
+ record.scales.splice(insertIndex, 0, asset.resolution);
148
+ record.files.splice(insertIndex, 0, path.join(dirname, file));
149
+ }
150
+ return assetMap;
151
+ }
152
+ function getAbsoluteAssetRecord(assetPath, context) {
153
+ const dirname = path.dirname(assetPath);
154
+ const files = fs.readdirSync(dirname);
155
+ const asset = parseAssetPath(path.basename(assetPath), context);
156
+ const assetMap = buildAssetMap(dirname, files, context);
157
+ const platformRecord = assetMap.get(getAssetKey(asset.assetName, context.platform));
158
+ if (platformRecord != null) return platformRecord;
159
+ if (context.preferNativePlatform) {
160
+ const nativeRecord = assetMap.get(getAssetKey(asset.assetName, "native"));
161
+ if (nativeRecord != null) return nativeRecord;
162
+ }
163
+ const defaultRecord = assetMap.get(asset.assetName);
164
+ if (defaultRecord != null) return defaultRecord;
165
+ throw new Error(`Asset not found: ${assetPath} for platform: ${context.platform}`);
166
+ }
101
167
  function platformSuffixPattern(context) {
102
168
  return [context.platform, context.preferNativePlatform ? "native" : null].filter(isNotNil).map((platform) => `.${platform}`).join("|");
103
169
  }
@@ -144,68 +210,47 @@ function getSuffixedPath(assetPath, context, options) {
144
210
  return path.join(dirname, suffixedBasename);
145
211
  }
146
212
  function resolveAssetPath(assetPath, context, scale) {
147
- const suffixedPaths = [
148
- getSuffixedPath(assetPath, context, {
149
- scale,
150
- platform: context.platform
151
- }),
152
- context.preferNativePlatform ? getSuffixedPath(assetPath, context, {
153
- scale,
154
- platform: "native"
155
- }) : null,
156
- getSuffixedPath(assetPath, context, { scale })
157
- ].filter(isNotNil);
158
- /**
159
- * When scale is 1, filename can be suffixed or non-suffixed(`image.png`).
160
- *
161
- * - Suffixed
162
- * - `filename.<platform>@<scale>x.ext`
163
- * - `filename.<platform>.ext`
164
- * - `filename@<scale>x.ext`
165
- * - Non suffixed
166
- * - `filename.ext`
167
- *
168
- * 1. Resolve non-suffixed asset first.
169
- * 2. If file is not exist, resolve suffixed path.
170
- */
171
- if (scale === 1) try {
172
- fs.statSync(assetPath);
173
- return assetPath;
174
- } catch {}
175
- for (const suffixedPath of suffixedPaths) try {
176
- fs.statSync(suffixedPath);
177
- return suffixedPath;
178
- } catch {}
213
+ const requestedScale = scale ?? parseAssetPath(path.basename(assetPath), context).resolution;
214
+ const record = getAbsoluteAssetRecord(assetPath, context);
215
+ for (let index = 0; index < record.scales.length; index += 1) if (record.scales[index] >= requestedScale) return record.files[index];
216
+ const fallback = record.files.at(-1);
217
+ if (fallback != null) return fallback;
179
218
  throw new Error(`cannot resolve asset path for ${assetPath}`);
180
219
  }
181
220
  /**
182
221
  * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/community-cli-plugin/src/commands/bundle/assetPathUtils.js
183
222
  */
184
223
  async function copyAssetsToDestination(options) {
185
- const { assets, platform, assetsDir, preferNativePlatform } = options;
186
- const context = {
187
- platform,
188
- preferNativePlatform
189
- };
224
+ const { assets, platform, assetsDir } = options;
190
225
  const mkdirWithAssertPath = (targetPath) => {
191
226
  const dirname = path.dirname(targetPath);
192
227
  fs.mkdirSync(dirname, { recursive: true });
193
228
  };
194
229
  return Promise.all(assets.map((asset) => {
195
- return Promise.all(asset.scales.map(async (scale) => {
230
+ const validScales = new Set(filterPlatformAssetScales(platform, asset.scales));
231
+ return Promise.all(asset.scales.map(async (scale, index) => {
232
+ if (!validScales.has(scale)) return;
196
233
  if (platform !== "android") {
197
- const from = resolveAssetPath(asset.id, context, scale);
234
+ const from = asset.files[index];
198
235
  const to = path.join(assetsDir, getIosAssetDestinationPath(asset, scale));
199
236
  mkdirWithAssertPath(to);
200
237
  return fs.copyFileSync(from, to);
201
238
  }
202
- const from = resolveAssetPath(asset.id, context, scale);
239
+ const from = asset.files[index];
203
240
  const to = path.join(assetsDir, getAndroidAssetDestinationPath(asset, scale));
204
241
  mkdirWithAssertPath(to);
205
242
  fs.copyFileSync(from, to);
206
243
  })).then(() => void 0);
207
244
  })).then(() => void 0);
208
245
  }
246
+ function filterPlatformAssetScales(platform, scales) {
247
+ const allowlist = ALLOW_SCALES[platform];
248
+ if (allowlist == null) return [...scales];
249
+ const filteredScales = scales.filter((scale) => allowlist.includes(scale));
250
+ if (filteredScales.length > 0 || scales.length === 0) return filteredScales;
251
+ const maxAllowedScale = allowlist[allowlist.length - 1];
252
+ return [scales.find((scale) => scale > maxAllowedScale) ?? scales[scales.length - 1]];
253
+ }
209
254
  /**
210
255
  * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/community-cli-plugin/src/commands/bundle/getAssetDestPathIOS.js
211
256
  */
@@ -238,7 +283,8 @@ function isDrawable(type) {
238
283
  ].includes(type);
239
284
  }
240
285
  function generateAssetRegistryCode(assetRegistryPath, asset) {
241
- return `module.exports = require('${assetRegistryPath}').registerAsset(${JSON.stringify(asset)});`;
286
+ const { files: _files, fileSystemLocation: _fileSystemLocation, id: _id, ...registryAsset } = asset;
287
+ return `module.exports = require('${assetRegistryPath}').registerAsset(${JSON.stringify(registryAsset)});`;
242
288
  }
243
289
  //#endregion
244
290
  export { assets_exports, copyAssetsToDestination, generateAssetRegistryCode, resolveAssetPath, resolveScaledAssets };
@@ -1,13 +1,13 @@
1
- import { FileStorage } from "../storage/file-storage.js";
2
1
  import { Logo } from "../common/logo.js";
2
+ import { FileStorage } from "../storage/file-storage.js";
3
3
  import { resolveBuildOptions } from "../utils/build-options.js";
4
4
  import { createId } from "../utils/id.js";
5
5
  import { getOverrideOptions, getOverrideOptionsForDevServer, resolveRolldownOptions } from "./rolldown.js";
6
6
  import fs from "node:fs";
7
7
  import path from "node:path";
8
8
  import { invariant, merge } from "es-toolkit";
9
- import * as rolldown from "@rollipop/rolldown";
10
9
  import { dev } from "@rollipop/rolldown/experimental";
10
+ import * as rolldown from "@rollipop/rolldown";
11
11
  //#region src/core/bundler.ts
12
12
  var Bundler = class Bundler {
13
13
  config;
@@ -0,0 +1,13 @@
1
+ import * as rolldown from "@rollipop/rolldown";
2
+
3
+ //#region src/core/plugins/alias-plugin.d.ts
4
+ interface AliasEntry {
5
+ find: string | RegExp;
6
+ replacement: string;
7
+ }
8
+ interface AliasPluginOptions {
9
+ entries: AliasEntry[];
10
+ }
11
+ declare function aliasPlugin(options: AliasPluginOptions): rolldown.Plugin | null;
12
+ //#endregion
13
+ export { AliasEntry, AliasPluginOptions, aliasPlugin };
@@ -0,0 +1,8 @@
1
+ import { viteAliasPlugin } from "@rollipop/rolldown/experimental";
2
+ //#region src/core/plugins/alias-plugin.ts
3
+ function aliasPlugin(options) {
4
+ if (options.entries.length === 0) return null;
5
+ return viteAliasPlugin(options);
6
+ }
7
+ //#endregion
8
+ export { aliasPlugin };
@@ -1,5 +1,5 @@
1
- import { ResolvedConfig } from "../../config/defaults.js";
2
1
  import { ResolvedHmrConfig } from "../../utils/config.js";
2
+ import { ResolvedConfig } from "../../config/defaults.js";
3
3
  import * as rolldown from "@rollipop/rolldown";
4
4
 
5
5
  //#region src/core/plugins/dev-server-plugin.d.ts
@@ -8,6 +8,8 @@ interface DevServerPluginOptions {
8
8
  hmrClientPath: ResolvedConfig['reactNative']['hmrClientPath'];
9
9
  hmrConfig: ResolvedHmrConfig | null;
10
10
  }
11
+ declare const DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS: RegExp[];
12
+ declare const DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS: RegExp[];
11
13
  declare function devServerPlugin(options: DevServerPluginOptions): Promise<rolldown.Plugin[] | null>;
12
14
  //#endregion
13
- export { DevServerPluginOptions, devServerPlugin };
15
+ export { DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS, DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS, DevServerPluginOptions, devServerPlugin };
@@ -2,6 +2,8 @@ import { resolveFrom } from "../../utils/node-resolve.js";
2
2
  import { rollipopReactRefreshWrapperPlugin } from "@rollipop/rolldown/experimental";
3
3
  import { exactRegex, id, include } from "@rollipop/rolldown/filter";
4
4
  //#region src/core/plugins/dev-server-plugin.ts
5
+ const DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS = [/\.[tj]sx?(?:$|\?)/];
6
+ const DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS = [/node_modules/];
5
7
  async function devServerPlugin(options) {
6
8
  const { cwd, hmrClientPath, hmrConfig } = options;
7
9
  if (hmrConfig == null) return null;
@@ -19,9 +21,9 @@ async function devServerPlugin(options) {
19
21
  }
20
22
  }, rollipopReactRefreshWrapperPlugin({
21
23
  cwd,
22
- include: [/\.[tj]sx?(?:$|\?)/],
23
- exclude: [/\/node_modules\//]
24
+ include: DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS,
25
+ exclude: DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS
24
26
  })];
25
27
  }
26
28
  //#endregion
27
- export { devServerPlugin };
29
+ export { DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS, DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS, devServerPlugin };
@@ -0,0 +1,11 @@
1
+ import * as rolldown from "@rollipop/rolldown";
2
+
3
+ //#region src/core/plugins/import-glob-plugin.d.ts
4
+ interface ImportGlobPluginOptions {
5
+ root?: string;
6
+ sourcemap?: boolean;
7
+ restoreQueryExtension?: boolean;
8
+ }
9
+ declare function importGlobPlugin(options: ImportGlobPluginOptions): rolldown.Plugin;
10
+ //#endregion
11
+ export { ImportGlobPluginOptions, importGlobPlugin };
@@ -0,0 +1,7 @@
1
+ import { viteImportGlobPlugin } from "@rollipop/rolldown/experimental";
2
+ //#region src/core/plugins/import-glob-plugin.ts
3
+ function importGlobPlugin(options) {
4
+ return viteImportGlobPlugin(options);
5
+ }
6
+ //#endregion
7
+ export { importGlobPlugin };
@@ -3,12 +3,14 @@ import { EntryPluginOptions, entryPlugin } from "./entry-plugin.js";
3
3
  import { BabelPluginOptions, babelPlugin } from "./babel-plugin.js";
4
4
  import { SwcPluginOptions, swcPlugin } from "./swc-plugin.js";
5
5
  import { ReporterPluginOptions, reporterPlugin } from "./reporter-plugin.js";
6
- import { DevServerPluginOptions, devServerPlugin } from "./dev-server-plugin.js";
6
+ import { DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS, DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS, DevServerPluginOptions, devServerPlugin } from "./dev-server-plugin.js";
7
7
  import { AnalyzePluginOptions, analyzePlugin } from "./analyze-plugin.js";
8
+ import { ImportGlobPluginOptions, importGlobPlugin } from "./import-glob-plugin.js";
9
+ import { AliasEntry, AliasPluginOptions, aliasPlugin } from "./alias-plugin.js";
8
10
 
9
11
  //#region src/core/plugins/index.d.ts
10
12
  declare namespace index_d_exports {
11
- export { AnalyzePluginOptions, BabelPluginOptions, DevServerPluginOptions, EntryPluginOptions, ReactNativePluginOptions, ReporterPluginOptions, SwcPluginOptions, analyzePlugin as analyze, babelPlugin as babel, devServerPlugin as devServer, entryPlugin as entry, reactNativePlugin as reactNative, reporterPlugin as reporter, swcPlugin as swc };
13
+ export { AliasEntry, AliasPluginOptions, AnalyzePluginOptions, BabelPluginOptions, DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS, DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS, DevServerPluginOptions, EntryPluginOptions, ImportGlobPluginOptions, ReactNativePluginOptions, ReporterPluginOptions, SwcPluginOptions, aliasPlugin as alias, analyzePlugin as analyze, babelPlugin as babel, devServerPlugin as devServer, entryPlugin as entry, importGlobPlugin as importGlob, reactNativePlugin as reactNative, reporterPlugin as reporter, swcPlugin as swc };
12
14
  }
13
15
  //#endregion
14
16
  export { index_d_exports };
@@ -4,14 +4,20 @@ import { entryPlugin } from "./entry-plugin.js";
4
4
  import { babelPlugin } from "./babel-plugin.js";
5
5
  import { swcPlugin } from "./swc-plugin.js";
6
6
  import { reporterPlugin } from "./reporter-plugin.js";
7
- import { devServerPlugin } from "./dev-server-plugin.js";
7
+ import { DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS, DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS, devServerPlugin } from "./dev-server-plugin.js";
8
8
  import { analyzePlugin } from "./analyze-plugin.js";
9
+ import { importGlobPlugin } from "./import-glob-plugin.js";
10
+ import { aliasPlugin } from "./alias-plugin.js";
9
11
  //#region src/core/plugins/index.ts
10
12
  var plugins_exports = /* @__PURE__ */ __exportAll({
13
+ DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS: () => DEFAULT_REACT_REFRESH_EXCLUDE_PATTERNS,
14
+ DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS: () => DEFAULT_REACT_REFRESH_INCLUDE_PATTERNS,
15
+ alias: () => aliasPlugin,
11
16
  analyze: () => analyzePlugin,
12
17
  babel: () => babelPlugin,
13
18
  devServer: () => devServerPlugin,
14
19
  entry: () => entryPlugin,
20
+ importGlob: () => importGlobPlugin,
15
21
  reactNative: () => reactNativePlugin,
16
22
  reporter: () => reporterPlugin,
17
23
  swc: () => swcPlugin
@@ -1,6 +1,6 @@
1
1
  import { BuildType, BundlerContext } from "../types.js";
2
- import * as rolldown from "@rollipop/rolldown";
3
2
  import { RollipopReactNativePluginConfig } from "@rollipop/rolldown/experimental";
3
+ import * as rolldown from "@rollipop/rolldown";
4
4
  import { TopLevelFilterExpression } from "@rollipop/rolldown/filter";
5
5
 
6
6
  //#region src/core/plugins/react-native-plugin.d.ts