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.
- package/client.d.ts +5 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/load-config.js +2 -0
- package/dist/config/notice.js +7 -0
- package/dist/config/types.d.ts +36 -3
- package/dist/constants.js +1 -1
- package/dist/core/assets.d.ts +4 -3
- package/dist/core/assets.js +124 -78
- package/dist/core/bundler.js +2 -2
- package/dist/core/plugins/alias-plugin.d.ts +13 -0
- package/dist/core/plugins/alias-plugin.js +8 -0
- package/dist/core/plugins/dev-server-plugin.d.ts +4 -2
- package/dist/core/plugins/dev-server-plugin.js +5 -3
- package/dist/core/plugins/import-glob-plugin.d.ts +11 -0
- package/dist/core/plugins/import-glob-plugin.js +7 -0
- package/dist/core/plugins/index.d.ts +4 -2
- package/dist/core/plugins/index.js +7 -1
- package/dist/core/plugins/react-native-plugin.d.ts +1 -1
- package/dist/core/rolldown.js +44 -5
- package/dist/core/types.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/internal/react-native.js +2 -5
- package/dist/node/commands/bundle/action.js +1 -1
- package/dist/node/commands/start/action.js +2 -3
- package/dist/package.js +1 -1
- package/dist/server/create-dev-server.js +0 -7
- package/dist/server/mcp/server.js +1 -1
- package/dist/server/mcp/tools/index.js +1 -1
- package/dist/server/middlewares/dashboard.js +8 -2
- package/dist/server/middlewares/serve-assets.js +5 -4
- package/dist/server/middlewares/symbolicate.js +20 -16
- package/dist/server/rest/domains/actions.js +2 -2
- package/dist/server/state/store.js +9 -1
- package/dist/server/symbolicate.js +35 -19
- package/dist/storage/file-storage.js +1 -1
- package/dist/utils/reset-cache.d.ts +2 -3
- package/dist/utils/reset-cache.js +4 -19
- package/import-glob.d.ts +129 -0
- 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
|
-
|
|
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
|
}
|
package/dist/config/index.d.ts
CHANGED
|
@@ -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) {
|
package/dist/config/types.d.ts
CHANGED
|
@@ -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.
|
|
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
|
/**
|
package/dist/core/assets.d.ts
CHANGED
|
@@ -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 =
|
|
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
|
|
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 };
|
package/dist/core/assets.js
CHANGED
|
@@ -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
|
|
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
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const
|
|
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
|
|
69
|
+
name,
|
|
91
70
|
type,
|
|
92
|
-
width: dimensions?.width,
|
|
93
|
-
height: dimensions?.height,
|
|
94
|
-
files
|
|
95
|
-
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:
|
|
98
|
-
hash
|
|
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
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 };
|
package/dist/core/bundler.js
CHANGED
|
@@ -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:
|
|
23
|
-
exclude:
|
|
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 };
|
|
@@ -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
|