crossbind 2.0.0-beta.60 → 2.0.0-beta.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/package.json +6 -1
- package/src/actions/buildDependencies.js +37 -9
- package/src/actions/buildExternal.js +9 -1
- package/src/actions/buildJs.js +1 -1
- package/src/actions/buildLib.js +27 -8
- package/src/actions/buildNativeCommand.js +84 -0
- package/src/actions/buildNode.js +190 -0
- package/src/actions/buildTypes.js +8 -2
- package/src/actions/buildWasiCommand.js +0 -4
- package/src/actions/buildWasm.js +92 -95
- package/src/actions/cloudCommands.js +133 -0
- package/src/actions/createImportedBridges.js +64 -0
- package/src/actions/createInterface.js +318 -65
- package/src/actions/createLib.js +60 -43
- package/src/actions/getAllBridges.js +1 -1
- package/src/actions/getData.js +4 -1
- package/src/actions/getLinkInputs.js +70 -0
- package/src/actions/isSourceNewer.js +2 -0
- package/src/actions/licenses.js +175 -17
- package/src/actions/prepareConanDependencies.js +51 -0
- package/src/actions/publishBinary.js +32 -0
- package/src/actions/run.js +124 -32
- package/src/actions/runnerCommands.js +421 -0
- package/src/actions/writeRuntimeEntry.js +69 -0
- package/src/assets/cmake/CMakeLists.txt +1 -1
- package/src/assets/cmake/command/CMakeLists.txt +21 -0
- package/src/assets/cmake/command/command.cpp +1 -0
- package/src/assets/cmake/dist.cmake +2 -1
- package/src/assets/configure/install.sh +22 -0
- package/src/assets/js-runtime/adapters/path-url.js +6 -3
- package/src/assets/js-runtime/adapters/unboundMessage.js +2 -0
- package/src/assets/js-runtime/adapters/worker-comlink.js +87 -56
- package/src/assets/js-runtime/core.js +11 -0
- package/src/assets/node-import-hooks.mjs +61 -0
- package/src/assets/toolchain-digests.json +27 -13
- package/src/assets/wasi-runtime/stubs.c +29 -0
- package/src/bin.js +290 -37
- package/src/index.js +6 -1
- package/src/integration/bindHeaderImports.js +18 -0
- package/src/integration/getCrossbindScript.js +53 -19
- package/src/integration/getDependFilePath.js +18 -12
- package/src/integration/resolveNativeImport.js +14 -0
- package/src/node/dev.mjs +19 -0
- package/src/runner/blobs.js +135 -0
- package/src/runner/files.js +193 -0
- package/src/runner/server.js +320 -0
- package/src/state/attachConanDependencies.js +56 -0
- package/src/state/index.js +31 -20
- package/src/state/loadConfig.js +36 -24
- package/src/state/refreshBuiltDependencies.js +20 -0
- package/src/state/refreshConanDependencies.js +17 -0
- package/src/utils/androidToolchain.js +4 -0
- package/src/utils/appRustCrates.js +17 -1
- package/src/utils/appSources.js +112 -0
- package/src/utils/archiveFlags.js +12 -0
- package/src/utils/boundHeaders.js +79 -0
- package/src/utils/bridgeExtras.js +486 -0
- package/src/utils/bridgeRuntimeFixes.js +48 -0
- package/src/utils/bundledLicenses.js +26 -0
- package/src/utils/cargoImport.js +44 -0
- package/src/utils/cargoTarget.js +23 -3
- package/src/utils/cloudAccount.js +55 -0
- package/src/utils/conanDependencies.js +66 -0
- package/src/utils/conanImport.js +58 -0
- package/src/utils/conanInstall.js +154 -0
- package/src/utils/conanProfile.js +203 -0
- package/src/utils/conanStage.js +292 -0
- package/src/utils/copyToDistSource.js +13 -0
- package/src/utils/cppDts.js +134 -55
- package/src/utils/darwinToolchain.js +11 -0
- package/src/utils/dirLock.js +137 -28
- package/src/utils/downloadAndExtractFile.js +34 -7
- package/src/utils/embindArgumentGuards.js +84 -0
- package/src/utils/embindCallArguments.js +19 -0
- package/src/utils/embindJspiQueue.js +25 -0
- package/src/utils/embindRsFingerprint.js +26 -0
- package/src/utils/execContainer.js +49 -0
- package/src/utils/headerImports.js +56 -0
- package/src/utils/hostPlatform.js +21 -0
- package/src/utils/inputStamp.js +23 -0
- package/src/utils/iosToolchain.js +6 -0
- package/src/utils/isSourceCmakePackage.js +10 -0
- package/src/utils/licenseReport.js +11 -2
- package/src/utils/linkLayout.js +8 -1
- package/src/utils/linuxToolchain.js +24 -0
- package/src/utils/makeTreeWritable.js +12 -0
- package/src/utils/nativeImports.js +23 -0
- package/src/utils/nativeSourceStamp.js +36 -0
- package/src/utils/nodeDevBuild.js +92 -0
- package/src/utils/packageLicense.js +101 -0
- package/src/utils/pthreadMainScript.js +14 -0
- package/src/utils/pullDockerImage.js +10 -5
- package/src/utils/relocatePrebuilt.js +119 -0
- package/src/utils/remoteClient.js +127 -0
- package/src/utils/remoteOutputs.js +39 -0
- package/src/utils/remoteRunner.js +97 -0
- package/src/utils/remoteUpload.js +134 -0
- package/src/utils/replaceFile.js +8 -0
- package/src/utils/resolveCompanionPackage.js +51 -0
- package/src/utils/resolveEmbindNapi.js +22 -0
- package/src/utils/resolveEmbindRust.js +17 -52
- package/src/utils/runCargo.js +51 -53
- package/src/utils/runConan.js +257 -0
- package/src/utils/runtimeEntries.js +56 -0
- package/src/utils/rustBridgeGen.js +903 -253
- package/src/utils/rustMt.js +4 -0
- package/src/utils/scopedEmbind.js +22 -0
- package/src/utils/selectRunner.js +81 -0
- package/src/utils/sourceFingerprint.js +4 -3
- package/src/utils/swigInterface.js +86 -6
- package/src/utils/systemKeys.js +43 -3
- package/src/utils/targets.js +104 -3
- package/src/utils/toolchainNotices.js +5 -0
- package/src/utils/wasiToolchain.js +14 -1
- package/src/utils/windowsToolchain.js +18 -0
- package/vitest.config.js +11 -0
- package/src/utils/cppFieldBindings.js +0 -23
package/src/bin.js
CHANGED
|
@@ -9,22 +9,43 @@ import createBridgeFile from './actions/createInterface.js';
|
|
|
9
9
|
import createLib from './actions/createLib.js';
|
|
10
10
|
import buildWasm from './actions/buildWasm.js';
|
|
11
11
|
import buildWasiCommand from './actions/buildWasiCommand.js';
|
|
12
|
+
import buildNode, { addonsInPackages, bundleNodeLoader, publishNodeData } from './actions/buildNode.js';
|
|
13
|
+
import buildNativeCommand from './actions/buildNativeCommand.js';
|
|
12
14
|
import buildExternal from './actions/buildExternal.js';
|
|
13
15
|
import buildPackageTypes from './actions/buildTypes.js';
|
|
14
16
|
import buildLib from './actions/buildLib.js';
|
|
15
17
|
import buildDependencies from './actions/buildDependencies.js';
|
|
18
|
+
import writeRuntimeEntry, { removeImportHooks, writeImportHooks } from './actions/writeRuntimeEntry.js';
|
|
19
|
+
import { createImportedBridges, findAppNativeImports } from './actions/createImportedBridges.js';
|
|
20
|
+
import { nativeExtensions } from './utils/nativeImports.js';
|
|
21
|
+
import getDependFilePath from './integration/getDependFilePath.js';
|
|
22
|
+
import { boundHeaderSpecifiers, bridgeTargets, nodeBridgeTarget, resolveBoundHeaders } from './utils/boundHeaders.js';
|
|
23
|
+
import { ENTRY_RUNTIMES } from './utils/runtimeEntries.js';
|
|
24
|
+
import { publishNativeCommand, publishNodeAddon, publishWasiCommand } from './actions/publishBinary.js';
|
|
16
25
|
import runCrossbindApp from './actions/run.js';
|
|
17
|
-
import { getFilteredBuildTargets } from './actions/target.js';
|
|
26
|
+
import { getBuildTargets, getFilteredBuildTargets } from './actions/target.js';
|
|
27
|
+
import { OPT_IN_PLATFORMS, selectRuntimeEnvs } from './utils/targets.js';
|
|
28
|
+
import { resolveHostPlatform } from './utils/hostPlatform.js';
|
|
29
|
+
import resolveEmbindNapiRoot, { resolveEmbindJsiRoot } from './utils/resolveEmbindNapi.js';
|
|
18
30
|
|
|
19
31
|
import writeJson from './utils/writeJson.js';
|
|
20
32
|
import flattenConfigForTable from './utils/flattenConfigForTable.js';
|
|
21
33
|
import systemKeys from './utils/systemKeys.js';
|
|
22
34
|
import logger from './utils/logger.js';
|
|
23
35
|
import { getDockerImage, getDockerContainerName } from './utils/pullDockerImage.js';
|
|
36
|
+
import {
|
|
37
|
+
RUNNER_PLATFORMS, RUNNER_ROLES, connectCommands, deploySteps, initRunner, newRunnerToken, runnerHostPort, startRunner, stopRunner,
|
|
38
|
+
} from './actions/runnerCommands.js';
|
|
39
|
+
import {
|
|
40
|
+
deleteAccount as deleteCloudAccount, fetchUsage, login as loginToCloud, logout as logoutOfCloud, usageLines,
|
|
41
|
+
} from './actions/cloudCommands.js';
|
|
42
|
+
import { cloudUrl } from './utils/cloudAccount.js';
|
|
24
43
|
import { cargoHome } from './utils/runCargo.js';
|
|
44
|
+
import { conanRoot } from './utils/runConan.js';
|
|
25
45
|
import { cleanDepsCache } from './utils/dependencyRebuild.js';
|
|
26
46
|
import collectLicenseRows from './actions/licenses.js';
|
|
27
47
|
import { formatNoticesMarkdown, formatCycloneDxSbom, validateSpdx } from './utils/licenseReport.js';
|
|
48
|
+
import { SBOM_FILE, nodePackageMeta, writeNodePackageLicense } from './utils/packageLicense.js';
|
|
28
49
|
import findFiles from './utils/findFiles.js';
|
|
29
50
|
|
|
30
51
|
const packageJSON = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url)));
|
|
@@ -60,11 +81,11 @@ program
|
|
|
60
81
|
|
|
61
82
|
program.command('build')
|
|
62
83
|
.description('compile the project that was set up using crossbind')
|
|
63
|
-
.addOption(new Option('-p, --platform <platform>', 'target platform').argParser(createListParser(platforms)))
|
|
84
|
+
.addOption(new Option('-p, --platform <platform>', 'target platform (host: the one of this machine)').argParser(createListParser(platforms, resolveHostPlatform)))
|
|
64
85
|
.addOption(new Option('-a, --arch <arch>', 'target architecture').argParser(createListParser(archs)))
|
|
65
86
|
.addOption(new Option('-r, --runtime <runtime>', 'target runtime').argParser(createListParser(runtimes)))
|
|
66
87
|
.addOption(new Option('-b, --build-type <buildType>', 'target build type').argParser(createListParser(buildTypes)))
|
|
67
|
-
.addOption(new Option('-e, --runtime-env <runtimeEnv>', '
|
|
88
|
+
.addOption(new Option('-e, --runtime-env <runtimeEnv>', 'binaries to make, by runtime environment (without it, only the archives are built)').argParser(createListParser(runtimeEnvs)))
|
|
68
89
|
.option('--rebuild-deps [list]', 'rebuild dependencies from source instead of using prebuilt (all, or a comma-separated list of names)')
|
|
69
90
|
.action((options) => {
|
|
70
91
|
const { rebuildDeps, ...rest } = options;
|
|
@@ -77,16 +98,18 @@ program.command('build')
|
|
|
77
98
|
targetParams.buildType = ['release'];
|
|
78
99
|
}
|
|
79
100
|
|
|
80
|
-
targetParams.platform = targetParams.platform || platforms;
|
|
101
|
+
targetParams.platform = targetParams.platform || platforms.filter((item) => !OPT_IN_PLATFORMS.includes(item));
|
|
81
102
|
targetParams.arch = targetParams.arch || archs;
|
|
82
103
|
targetParams.runtime = targetParams.runtime || runtimes;
|
|
83
104
|
targetParams.buildType = targetParams.buildType || buildTypes;
|
|
84
|
-
|
|
105
|
+
const binaryRuntimeEnvs = selectRuntimeEnvs(targetParams.runtimeEnv, state.config.target.runtimeEnv);
|
|
106
|
+
// The archives do not depend on the runtime environment; only the binaries do.
|
|
107
|
+
targetParams.runtimeEnv = runtimeEnvs;
|
|
85
108
|
|
|
86
109
|
if (state.config.build.withBuildConfig) {
|
|
87
110
|
buildExternal(targetParams);
|
|
88
111
|
} else {
|
|
89
|
-
build(targetParams, rebuildDeps);
|
|
112
|
+
build(targetParams, rebuildDeps, binaryRuntimeEnvs);
|
|
90
113
|
}
|
|
91
114
|
});
|
|
92
115
|
|
|
@@ -107,8 +130,14 @@ program.command('licenses')
|
|
|
107
130
|
.option('--sbom [file]', 'write a CycloneDX SBOM json file (default: sbom.cdx.json)')
|
|
108
131
|
.option('--check', 'exit non-zero when a license field is missing or not valid SPDX')
|
|
109
132
|
.option('--platform <platform>', "also list what this platform's artifact statically links beyond the package graph (vendored copies, toolchain runtime)")
|
|
133
|
+
.addOption(new Option('-e, --runtime-env <runtimeEnv>', 'also list the crossbind runtime an addon of --platform compiles in, or without --platform the one its loader bundles').choices(['node']))
|
|
134
|
+
.option('--json [file]', 'write the rows, license texts included, as JSON (default: licenses.json)')
|
|
135
|
+
.option('--package', "write this Node-API package's LICENSE, sbom.cdx.json and package.json license field (with -e node)")
|
|
110
136
|
.action(async (options) => {
|
|
111
|
-
|
|
137
|
+
if (options.package && options.runtimeEnv !== 'node') {
|
|
138
|
+
throw new Error('crossbind licenses --package writes the license files of a Node-API package; pass -e node.');
|
|
139
|
+
}
|
|
140
|
+
const rows = await collectLicenseRows(options.platform || null, { runtimeEnv: options.runtimeEnv || null });
|
|
112
141
|
rows.forEach((row) => {
|
|
113
142
|
console.log(`${row.isCopyleft ? '! ' : ' '}${(row.name || '').padEnd(14)} ${String(row.license || '(missing)').padEnd(48)} native ${String(row.nativeVersion || '-').padEnd(10)} ${row.sourceUrl || ''}`);
|
|
114
143
|
});
|
|
@@ -133,6 +162,15 @@ program.command('licenses')
|
|
|
133
162
|
fs.writeFileSync(file, formatCycloneDxSbom(rows, target));
|
|
134
163
|
logger.info(`crossbind: wrote ${file}`);
|
|
135
164
|
}
|
|
165
|
+
if (options.json) {
|
|
166
|
+
const file = typeof options.json === 'string' ? options.json : `${state.config.paths.project}/licenses.json`;
|
|
167
|
+
fs.writeFileSync(file, `${JSON.stringify(rows, null, 2)}\n`);
|
|
168
|
+
logger.info(`crossbind: wrote ${file}`);
|
|
169
|
+
}
|
|
170
|
+
if (options.package) {
|
|
171
|
+
const expression = writeNodePackageLicense(state.config.paths.project, { ...nodePackageMeta(state.config), rows });
|
|
172
|
+
logger.info(`crossbind: wrote LICENSE and ${SBOM_FILE} (${expression})`);
|
|
173
|
+
}
|
|
136
174
|
if (options.check) {
|
|
137
175
|
const invalid = rows
|
|
138
176
|
.map((row) => ({ row, result: validateSpdx(row.license) }))
|
|
@@ -162,7 +200,7 @@ program.command('clean-deps')
|
|
|
162
200
|
});
|
|
163
201
|
|
|
164
202
|
// A container belongs to one image: the web container carries no NDK, and android runs a forced platform.
|
|
165
|
-
const IMAGE_ROLES = ['web', 'android'];
|
|
203
|
+
const IMAGE_ROLES = ['web', 'android', 'linux', 'windows'];
|
|
166
204
|
const dockerContainerName = (role) => {
|
|
167
205
|
if (!IMAGE_ROLES.includes(role)) {
|
|
168
206
|
console.error(`crossbind: unknown image "${role}" - expected one of ${IMAGE_ROLES.join(', ')}.`);
|
|
@@ -194,13 +232,17 @@ imageArgument(commandDocker.command('create').description('create docker contain
|
|
|
194
232
|
.action((image) => {
|
|
195
233
|
// Google ships the linux NDK for x86_64 only, so an android container is always amd64.
|
|
196
234
|
const platform = image === 'android' ? 'linux/amd64' : undefined;
|
|
235
|
+
// Docker on Linux makes a missing mount source owned by root, which the user's builds cannot write.
|
|
236
|
+
[cargoHome(), conanRoot()].forEach((dir) => fs.mkdirSync(dir, { recursive: true }));
|
|
197
237
|
dockerExec([
|
|
198
238
|
'run', '-dit',
|
|
199
239
|
...(platform ? ['--platform', platform] : []),
|
|
200
240
|
'--name', dockerContainerName(image),
|
|
201
241
|
'-v', `${state.config.paths.base}:/tmp/crossbind/live`,
|
|
202
|
-
// Cargo's registry cache, shared with host builds and with every other project
|
|
242
|
+
// Cargo's registry cache, shared with host builds and with every other project, and the
|
|
243
|
+
// Conan store and work directories every other container build uses.
|
|
203
244
|
'-v', `${cargoHome()}:/var/cache/crossbind/cargo`,
|
|
245
|
+
'-v', `${conanRoot()}:/var/cache/crossbind/conan`,
|
|
204
246
|
getDockerImage(image, platform),
|
|
205
247
|
'bash',
|
|
206
248
|
]);
|
|
@@ -215,6 +257,98 @@ imageArgument(commandDocker.command('stop').description('stop docker container')
|
|
|
215
257
|
imageArgument(commandDocker.command('delete').description('delete docker container'))
|
|
216
258
|
.action((image) => dockerExec(['rm', dockerContainerName(image)]));
|
|
217
259
|
|
|
260
|
+
const runnerAction = (fn) => (...args) => {
|
|
261
|
+
try {
|
|
262
|
+
fn(...args);
|
|
263
|
+
} catch (e) {
|
|
264
|
+
console.error(e.message);
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
const roleOption = () => new Option('--role <role>', 'toolchain image the runner serves').choices(RUNNER_ROLES).default('web');
|
|
269
|
+
|
|
270
|
+
const commandRunner = program.command('runner')
|
|
271
|
+
.description('run the remote build runner that RUNNER=REMOTE sends builds to');
|
|
272
|
+
|
|
273
|
+
commandRunner.command('start')
|
|
274
|
+
.description('start a runner in local docker, from the toolchain image this CLI pins')
|
|
275
|
+
.addOption(roleOption())
|
|
276
|
+
.option('--port <port>', `host port (default: ${RUNNER_ROLES.map((role) => `${runnerHostPort(role)} for ${role}`).join(', ')})`)
|
|
277
|
+
.option('--host <address>', 'host address to listen on', '127.0.0.1')
|
|
278
|
+
.option('--token <token>', 'token builds must send (default: $CROSSBIND_RUNNER_TOKEN, else a new one)')
|
|
279
|
+
.action(runnerAction((options) => {
|
|
280
|
+
const runner = startRunner({
|
|
281
|
+
role: options.role, port: options.port && Number(options.port), host: options.host, token: options.token,
|
|
282
|
+
});
|
|
283
|
+
console.log(`crossbind: ${runner.name} is running. Build against it with:`);
|
|
284
|
+
connectCommands(options.role, runner.url, runner.displayToken).forEach((line) => console.log(` ${line}`));
|
|
285
|
+
}));
|
|
286
|
+
|
|
287
|
+
commandRunner.command('stop')
|
|
288
|
+
.description('stop and remove the local runner')
|
|
289
|
+
.addOption(roleOption())
|
|
290
|
+
.action(runnerAction((options) => stopRunner({ role: options.role })));
|
|
291
|
+
|
|
292
|
+
commandRunner.command('init')
|
|
293
|
+
.description('write a folder that deploys a runner to a hosting platform')
|
|
294
|
+
.argument('<platform>', `hosting platform (${RUNNER_PLATFORMS.join(', ')})`)
|
|
295
|
+
.addOption(roleOption())
|
|
296
|
+
.option('--dir <dir>', 'folder to write (default: crossbind-runner-<platform>-<role>)')
|
|
297
|
+
.option('--vcpu <count>', 'cloudflare: vCPUs of the container (1-4), with the least memory Cloudflare allows them (default: standard-4)')
|
|
298
|
+
.action(runnerAction((platform, options) => {
|
|
299
|
+
const { dir, url } = initRunner({
|
|
300
|
+
platform,
|
|
301
|
+
role: options.role,
|
|
302
|
+
dir: options.dir ?? `crossbind-runner-${platform}-${options.role}`,
|
|
303
|
+
vcpu: options.vcpu === undefined ? undefined : Number(options.vcpu),
|
|
304
|
+
});
|
|
305
|
+
console.log(`crossbind: wrote ${dir}. Deploy it:`);
|
|
306
|
+
deploySteps(platform, dir, newRunnerToken(), options.role, url).forEach((step) => console.log(` ${step}`));
|
|
307
|
+
}));
|
|
308
|
+
|
|
309
|
+
program.command('login')
|
|
310
|
+
.description('sign in to crossbind cloud with your GitHub account')
|
|
311
|
+
.action(async () => {
|
|
312
|
+
const url = cloudUrl(state.config.system);
|
|
313
|
+
const { login } = await loginToCloud({ url });
|
|
314
|
+
console.log(`crossbind: signed in to ${url} as ${login}.`);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
program.command('logout')
|
|
318
|
+
.description('sign out of crossbind cloud on this machine')
|
|
319
|
+
.option('--all', 'sign out every machine signed in to this account')
|
|
320
|
+
.action(async (options) => {
|
|
321
|
+
const url = cloudUrl(state.config.system);
|
|
322
|
+
const result = await logoutOfCloud({ url, all: Boolean(options.all) });
|
|
323
|
+
if (!result) {
|
|
324
|
+
console.log(`crossbind: not signed in to ${url}.`);
|
|
325
|
+
} else if (result.revoked) {
|
|
326
|
+
console.log(`crossbind: signed ${result.login} out${options.all ? ' on every machine' : ''}.`);
|
|
327
|
+
} else {
|
|
328
|
+
console.warn(`crossbind: signed out here, but crossbind cloud did not revoke the token (${result.reason.replace(/^crossbind: /, '')}). Sign in again and run crossbind logout --all to revoke it.`);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
program.command('usage')
|
|
333
|
+
.description('show what you used of crossbind cloud this month and what is left')
|
|
334
|
+
.action(async () => {
|
|
335
|
+
usageLines(await fetchUsage({ url: cloudUrl(state.config.system) })).forEach((line) => console.log(line));
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
program.command('account')
|
|
339
|
+
.description('manage your crossbind cloud account')
|
|
340
|
+
.command('delete')
|
|
341
|
+
.description('delete your crossbind cloud account, with the sign-in of every machine (https://crossbind.dev/privacy/)')
|
|
342
|
+
.option('--yes', 'delete it; without this, nothing is deleted')
|
|
343
|
+
.action(async (options) => {
|
|
344
|
+
const url = cloudUrl(state.config.system);
|
|
345
|
+
if (!options.yes) {
|
|
346
|
+
throw new Error(`crossbind: this deletes your crossbind cloud account at ${url}, with the sign-in of every machine. Run crossbind account delete --yes to go ahead.`);
|
|
347
|
+
}
|
|
348
|
+
const { login } = await deleteCloudAccount({ url });
|
|
349
|
+
console.log(`crossbind: deleted the crossbind cloud account of ${login}.`);
|
|
350
|
+
});
|
|
351
|
+
|
|
218
352
|
const commandConfig = program.command('config')
|
|
219
353
|
.description('manage the crossbind configuration files');
|
|
220
354
|
|
|
@@ -319,14 +453,44 @@ function run(programName, params) {
|
|
|
319
453
|
runCrossbindApp(programName, params, null, null, { console: true });
|
|
320
454
|
}
|
|
321
455
|
|
|
322
|
-
|
|
456
|
+
// A package whose platform packages link its addons, building nothing else, has no archive of its own that
|
|
457
|
+
// anything links.
|
|
458
|
+
function onlyLoadsPackagedAddons(binaryParams) {
|
|
459
|
+
if (binaryParams.runtimeEnv.length === 0) return false;
|
|
460
|
+
const targets = getBuildTargets(binaryParams);
|
|
461
|
+
return targets.every((target) => target.runtimeEnv === 'node' && target.platform !== 'wasm') && addonsInPackages();
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async function build(targetParams, rebuildOption, binaryRuntimeEnvs) {
|
|
323
465
|
await buildDependencies({ targetParams, rebuildOption });
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
466
|
+
const binaryParams = { ...targetParams, runtimeEnv: binaryRuntimeEnvs };
|
|
467
|
+
if (!onlyLoadsPackagedAddons(binaryParams)) {
|
|
468
|
+
buildLib(targetParams);
|
|
469
|
+
}
|
|
470
|
+
if (binaryRuntimeEnvs.length === 0) {
|
|
471
|
+
logger.info(`crossbind: no runtime environment was selected, so only the archives were built - pass -e (${runtimeEnvs.join(', ')}) for a binary.`);
|
|
472
|
+
} else {
|
|
473
|
+
await createWasmJs(binaryParams);
|
|
474
|
+
await createNodeAddons(binaryParams);
|
|
475
|
+
await createNativeCommands(binaryParams);
|
|
476
|
+
await createWasiCommands(binaryParams);
|
|
477
|
+
}
|
|
327
478
|
buildPackageTypes();
|
|
328
479
|
}
|
|
329
480
|
|
|
481
|
+
async function createNativeCommands(targetParams) {
|
|
482
|
+
const targets = getBuildTargets(targetParams).filter((target) => target.runtimeEnv === 'native');
|
|
483
|
+
for (const target of targets) {
|
|
484
|
+
const distCommand = `${state.config.paths.output}/${target.commandName}`;
|
|
485
|
+
const built = await buildNativeCommand(target, { force: !fs.existsSync(distCommand) });
|
|
486
|
+
publishNodeData(target, { refresh: built });
|
|
487
|
+
if (!built) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
publishNativeCommand(target);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
330
494
|
async function createWasiCommands(targetParams) {
|
|
331
495
|
const targets = getFilteredBuildTargets(targetParams, { platform: 'wasi' });
|
|
332
496
|
if (targets.length === 0) {
|
|
@@ -338,44 +502,115 @@ async function createWasiCommands(targetParams) {
|
|
|
338
502
|
if (!built) {
|
|
339
503
|
continue;
|
|
340
504
|
}
|
|
341
|
-
|
|
342
|
-
// Copied (not renamed) so a later fingerprint cache-hit still has the
|
|
343
|
-
// build-dir tree to serve from.
|
|
344
|
-
if (fs.existsSync(`${state.config.paths.build}/data`)) {
|
|
345
|
-
fs.rmSync(`${state.config.paths.output}/data`, { recursive: true, force: true });
|
|
346
|
-
fs.cpSync(`${state.config.paths.build}/data`, `${state.config.paths.output}/data`, { recursive: true });
|
|
347
|
-
}
|
|
505
|
+
publishWasiCommand(target);
|
|
348
506
|
}
|
|
349
507
|
}
|
|
350
508
|
|
|
351
|
-
|
|
352
|
-
if (state.config.export.bundle === false) {
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
const targets = getFilteredBuildTargets(targetParams, { platform: 'wasm' });
|
|
356
|
-
if (targets.length === 0) {
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
509
|
+
function createBridges(target) {
|
|
359
510
|
let headers = [];
|
|
360
511
|
state.config.paths.header.forEach((headerPath) => {
|
|
361
512
|
headers.push(findFiles('**/*.h', { cwd: headerPath }));
|
|
362
513
|
});
|
|
363
514
|
headers = headers.filter((path) => !!path.toString()).flat();
|
|
364
515
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
516
|
+
return headers.map((header) => ({ file: header, bridge: createBridgeFile(header, target) }));
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// The dependency headers the config binds whole, each read where one of the targets' packages ships it.
|
|
520
|
+
function createBoundBridges(targets) {
|
|
521
|
+
const headers = resolveBoundHeaders(boundHeaderSpecifiers(state.config), bridgeTargets(targets, state.targets), getDependFilePath);
|
|
522
|
+
const wholeHeaders = headers.map((header) => header.file);
|
|
523
|
+
return headers.map((header) => ({ ...header, bridge: createBridgeFile(header.file, header.target, { wholeHeaders }) }));
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// A package whose platform packages link its addons ships what loads them: the loader and the data.
|
|
527
|
+
async function publishLoaders(targets) {
|
|
528
|
+
fs.mkdirSync(state.config.paths.output, { recursive: true });
|
|
529
|
+
targets.forEach((target) => publishNodeData(target, { refresh: true }));
|
|
530
|
+
for (const target of new Map(targets.map((t) => [t.jsName, t])).values()) {
|
|
531
|
+
await bundleNodeLoader(target);
|
|
532
|
+
fs.copyFileSync(`${state.config.paths.build}/${target.jsName}`, `${state.config.paths.output}/${target.jsName}`);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
370
535
|
|
|
536
|
+
async function createNodeAddons(targetParams) {
|
|
537
|
+
const targets = getBuildTargets(targetParams)
|
|
538
|
+
.filter((target) => target.runtimeEnv === 'node' && target.platform !== 'wasm');
|
|
539
|
+
if (targets.length === 0) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
// The bridges compile against the embind runtime, which speaks JSI.
|
|
543
|
+
const headerDirs = [
|
|
544
|
+
`${resolveEmbindJsiRoot()}/cpp/src`,
|
|
545
|
+
`${resolveEmbindNapiRoot()}/third_party/node-api-jsi/jsi`,
|
|
546
|
+
];
|
|
547
|
+
const boundHeaders = createBoundBridges(targets);
|
|
548
|
+
const ownHeaders = [...createBridges(nodeBridgeTarget(targets)), ...boundHeaders];
|
|
549
|
+
const imports = findAppNativeImports(bridgeTargets(targets, state.targets));
|
|
550
|
+
const headers = [...ownHeaders, ...createImportedBridges(ownHeaders, imports)];
|
|
371
551
|
const opt = {
|
|
372
552
|
buildSource: false,
|
|
373
553
|
nativeGlob: [
|
|
374
554
|
`${state.config.paths.cli}/assets/cpp-runtime/commonBridges.cpp`,
|
|
375
|
-
...
|
|
555
|
+
...headers.flatMap((header) => header.bridge ?? []),
|
|
376
556
|
],
|
|
557
|
+
headerDirs,
|
|
558
|
+
inputs: headerDirs.flatMap((dir) => findFiles('**/*.h', { cwd: dir })),
|
|
377
559
|
};
|
|
378
560
|
|
|
561
|
+
if (addonsInPackages()) {
|
|
562
|
+
await publishLoaders(targets);
|
|
563
|
+
} else {
|
|
564
|
+
for (const target of targets) {
|
|
565
|
+
const distComplete = fs.existsSync(`${state.config.paths.output}/${target.addonName}`)
|
|
566
|
+
&& fs.existsSync(`${state.config.paths.output}/${target.jsName}`);
|
|
567
|
+
createLib(target, 'Bridge', opt);
|
|
568
|
+
const built = await buildNode(target, { force: !distComplete });
|
|
569
|
+
publishNodeData(target, { refresh: built });
|
|
570
|
+
if (!built) {
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
publishNodeAddon(target);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
const loaderTarget = targets.find((target) => target.buildType === 'release') ?? targets[0];
|
|
577
|
+
if (headers.length && fs.existsSync(`${state.config.paths.output}/${loaderTarget.jsName}`)) {
|
|
578
|
+
const entry = `${state.config.paths.output}/node/napi.mjs`;
|
|
579
|
+
writeRuntimeEntry(entry, headers, ENTRY_RUNTIMES.node(loaderTarget.jsName));
|
|
580
|
+
if (imports.size) writeImportHooks(entry, headers, imports, nativeExtensions(state.config.ext));
|
|
581
|
+
else removeImportHooks(entry);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// The Node and edge wasm builds are CommonJS with a .js extension, which a "type": "module" package loads as
|
|
586
|
+
// ESM. A package.json of the output's own scopes them back, unless the output is a package root.
|
|
587
|
+
const OUTPUT_SCOPE = '{\n "type": "commonjs"\n}\n';
|
|
588
|
+
function scopeOutputToCommonJs() {
|
|
589
|
+
const file = `${state.config.paths.output}/package.json`;
|
|
590
|
+
if (!fs.existsSync(file)) {
|
|
591
|
+
fs.mkdirSync(state.config.paths.output, { recursive: true });
|
|
592
|
+
fs.writeFileSync(file, OUTPUT_SCOPE);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
async function createWasmJs(targetParams) {
|
|
597
|
+
const targets = getFilteredBuildTargets(targetParams, { platform: 'wasm' });
|
|
598
|
+
if (targets.length === 0) {
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const headers = createBridges();
|
|
602
|
+
// A Node app imports what it uses through the module hooks, so a Node binary binds those imports too.
|
|
603
|
+
const isNode = (target) => target.runtimeEnv === 'node';
|
|
604
|
+
const imports = targets.some(isNode) ? findAppNativeImports([state.targets.find((t) => t.platform === 'wasm')]) : new Map();
|
|
605
|
+
const nodeHeaders = [...headers, ...createImportedBridges(headers, imports)];
|
|
606
|
+
const optOf = (bridged) => ({
|
|
607
|
+
buildSource: false,
|
|
608
|
+
nativeGlob: [
|
|
609
|
+
`${state.config.paths.cli}/assets/cpp-runtime/commonBridges.cpp`,
|
|
610
|
+
...bridged.flatMap((header) => header.bridge ?? []),
|
|
611
|
+
],
|
|
612
|
+
});
|
|
613
|
+
|
|
379
614
|
for (const target of targets) {
|
|
380
615
|
// An artifact merely existing in dist used to short-circuit this whole
|
|
381
616
|
// step, which kept serving stale output after flag/runtime changes.
|
|
@@ -384,7 +619,7 @@ async function createWasmJs(targetParams) {
|
|
|
384
619
|
// link and the copy step below moved build/data away on the last run.
|
|
385
620
|
const distComplete = fs.existsSync(`${state.config.paths.output}/${target.jsName}`)
|
|
386
621
|
&& fs.existsSync(`${state.config.paths.output}/${target.wasmName}`);
|
|
387
|
-
createLib(target, 'Bridge',
|
|
622
|
+
createLib(target, 'Bridge', optOf(isNode(target) ? nodeHeaders : headers));
|
|
388
623
|
const built = await buildWasm(target, { force: !distComplete });
|
|
389
624
|
if (!built) {
|
|
390
625
|
continue;
|
|
@@ -401,11 +636,29 @@ async function createWasmJs(targetParams) {
|
|
|
401
636
|
fs.copyFileSync(`${state.config.paths.build}/${target.dataTxtName}`, `${state.config.paths.output}/${target.dataTxtName}`);
|
|
402
637
|
}
|
|
403
638
|
}
|
|
639
|
+
|
|
640
|
+
if (targets.some((target) => ['node', 'edge'].includes(target.runtimeEnv))) {
|
|
641
|
+
scopeOutputToCommonJs();
|
|
642
|
+
}
|
|
643
|
+
// A runtime's entry loads its single-thread wasm32 release build.
|
|
644
|
+
const entryTargetOf = (runtimeEnv) => targets.find((target) => target.runtimeEnv === runtimeEnv && target.arch === 'wasm32'
|
|
645
|
+
&& target.runtime === 'st' && target.buildType === 'release' && fs.existsSync(`${state.config.paths.output}/${target.jsName}`));
|
|
646
|
+
const nodeTarget = entryTargetOf('node');
|
|
647
|
+
const edgeTarget = entryTargetOf('edge');
|
|
648
|
+
if (nodeHeaders.length && nodeTarget) {
|
|
649
|
+
const entry = `${state.config.paths.output}/node/wasm.mjs`;
|
|
650
|
+
writeRuntimeEntry(entry, nodeHeaders, ENTRY_RUNTIMES.node(nodeTarget.jsName));
|
|
651
|
+
if (imports.size) writeImportHooks(entry, nodeHeaders, imports, nativeExtensions(state.config.ext));
|
|
652
|
+
else removeImportHooks(entry);
|
|
653
|
+
}
|
|
654
|
+
if (headers.length && edgeTarget) {
|
|
655
|
+
writeRuntimeEntry(`${state.config.paths.output}/edge/wasm.mjs`, headers, ENTRY_RUNTIMES.edge(edgeTarget.jsName, edgeTarget.wasmName));
|
|
656
|
+
}
|
|
404
657
|
}
|
|
405
658
|
|
|
406
|
-
function createListParser(validList) {
|
|
659
|
+
function createListParser(validList, resolve = (items) => items) {
|
|
407
660
|
return (value, previous) => {
|
|
408
|
-
const items = value.split(',').map(item => item.trim());
|
|
661
|
+
const items = resolve(value.split(',').map(item => item.trim()));
|
|
409
662
|
for (const item of items) {
|
|
410
663
|
if (!validList.includes(item)) {
|
|
411
664
|
throw new Error(`Invalid value: "${item}". Allowed values: ${validList.join(', ')}`);
|
package/src/index.js
CHANGED
|
@@ -13,7 +13,12 @@ export { getTargetParams, getBuildTargets, getFilteredBuildTargets, getFilteredT
|
|
|
13
13
|
export { default as getCrossbindScript, getRustJsScript } from './integration/getCrossbindScript.js';
|
|
14
14
|
export { default as getDependFilePath } from './integration/getDependFilePath.js';
|
|
15
15
|
export { default as buildDependencies, getDependenciesStamp } from './actions/buildDependencies.js';
|
|
16
|
+
export { default as prepareConanDependencies } from './actions/prepareConanDependencies.js';
|
|
16
17
|
export { default as findFiles } from './utils/findFiles.js';
|
|
17
18
|
export { getContentHash, getFileHash } from './utils/hash.js';
|
|
18
|
-
export {
|
|
19
|
+
export {
|
|
20
|
+
collectInputFiles, collectRustBridgeFiles, collectRustSources, computeInputStamp,
|
|
21
|
+
} from './utils/inputStamp.js';
|
|
19
22
|
export { default as buildAppRustCrates } from './utils/appRustCrates.js';
|
|
23
|
+
export { default as appSourceFiles, isAppSource } from './utils/appSources.js';
|
|
24
|
+
export { default as bindHeaderImports } from './integration/bindHeaderImports.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import upath from 'upath';
|
|
3
|
+
import state from '../state/index.js';
|
|
4
|
+
import createBridgeFile from '../actions/createInterface.js';
|
|
5
|
+
import resolveNativeImport from './resolveNativeImport.js';
|
|
6
|
+
import { isAppSource } from '../utils/appSources.js';
|
|
7
|
+
import { findHeaderImports } from '../utils/headerImports.js';
|
|
8
|
+
|
|
9
|
+
// Metro keeps a header's module as it first transformed it, so a source of the app that imports the header binds it
|
|
10
|
+
// again: the functions it names reach the next native build or page load.
|
|
11
|
+
export default function bindHeaderImports(source, file, target) {
|
|
12
|
+
if (!isAppSource(state.config.paths.project, file)) return [];
|
|
13
|
+
const headers = findHeaderImports(source, state.config.ext.header)
|
|
14
|
+
.map(({ specifier }) => resolveNativeImport(specifier, file, target))
|
|
15
|
+
.filter((header) => header && fs.existsSync(header))
|
|
16
|
+
.map((header) => upath.normalize(header));
|
|
17
|
+
return [...new Set(headers)].map((header) => createBridgeFile(header, target));
|
|
18
|
+
}
|
|
@@ -4,18 +4,54 @@ import getData from '../actions/getData.js';
|
|
|
4
4
|
import loadJson from '../utils/loadJson.js';
|
|
5
5
|
import state from '../state/index.js';
|
|
6
6
|
import { parseSurface, createRustBridgeCrate, createCrateImportBridge } from '../utils/rustBridgeGen.js';
|
|
7
|
+
import { parseCargoMarkerName } from '../utils/cargoImport.js';
|
|
8
|
+
import { UNBOUND_MESSAGE } from '../assets/js-runtime/adapters/unboundMessage.js';
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
// `base` is where the bundler serves the app from, as Vite's `base` names it; webpack's public path wins at run time.
|
|
11
|
+
// Metro asks for `liveExports`: it keeps a header's module as it first transformed it while the app's imports change.
|
|
12
|
+
export default function getCrossbindScript(target, bridgePath, { base = '/', liveExports: isLive = false } = {}) {
|
|
9
13
|
if (!bridgePath) {
|
|
10
14
|
throw new Error('getCrossbindScript needs the bridge file of the imported header');
|
|
11
15
|
}
|
|
12
|
-
|
|
16
|
+
const script = buildScript(target, loadJson(`${bridgePath}.exports.json`), base);
|
|
17
|
+
return isLive ? `${script}${liveExportsScript()}` : script;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// A name the module does not export comes off the booted module: undefined before initNative. A name the module the page
|
|
21
|
+
// or app loaded lacks, exported or not, is a function that says why. Serialized into the generated module, so it
|
|
22
|
+
// references nothing outside itself.
|
|
23
|
+
export function liveExports(exportsObject, unbound) {
|
|
24
|
+
return new Proxy(exportsObject, {
|
|
25
|
+
get(target, name, receiver) {
|
|
26
|
+
const value = Reflect.get(target, name, receiver);
|
|
27
|
+
const bound = globalThis.__crossbindModule;
|
|
28
|
+
if (value != null || !bound || typeof name !== 'string' || ['then', 'default', 'toJSON'].includes(name)) return value;
|
|
29
|
+
if (bound[name] !== undefined) return bound[name];
|
|
30
|
+
if (!/^[A-Za-z_]\w*$/.test(name)) return value;
|
|
31
|
+
return function notBound() {
|
|
32
|
+
throw new Error(`crossbind: ${name} ${unbound}`);
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function liveExportsScript() {
|
|
39
|
+
return `
|
|
40
|
+
const __crossbindLiveExports = ${liveExports.toString()};
|
|
41
|
+
if (typeof module === 'object' && module) module.exports = __crossbindLiveExports(module.exports, ${JSON.stringify(UNBOUND_MESSAGE)});
|
|
42
|
+
`;
|
|
13
43
|
}
|
|
14
44
|
|
|
15
45
|
// The Rust analog of a .h import: parse the crate surface and emit the same proxy module
|
|
16
46
|
// (per-symbol lets assigned inside this module's initNative). Vectors come from the owning
|
|
17
47
|
// cargo package's config; classes/enums come from the parsed source.
|
|
18
|
-
export function getRustJsScript(target, rsFile) {
|
|
48
|
+
export function getRustJsScript(target, rsFile, { base = '/' } = {}) {
|
|
49
|
+
return buildScript(target, getRustSymbols(rsFile), base);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// The names a Rust import exports. An app-local file or a cargo: crate gets its bridge crate here, the way a header
|
|
53
|
+
// gets its bridge from createBridgeFile.
|
|
54
|
+
export function getRustSymbols(rsFile) {
|
|
19
55
|
// Compare real paths: dependency paths go through node_modules symlinks (pnpm workspaces)
|
|
20
56
|
// while bundlers hand the transformer the resolved real file.
|
|
21
57
|
const realCrateDir = (d) => {
|
|
@@ -25,25 +61,21 @@ export function getRustJsScript(target, rsFile) {
|
|
|
25
61
|
|
|
26
62
|
// Marker under <cache>/rust-crates/: a direct crate import - the model comes from the
|
|
27
63
|
// upstream crate's own source, and the bridge is synthesized against the cargo dependency.
|
|
28
|
-
const crateName = path.basename(rsReal, '.rs');
|
|
64
|
+
const { crateName, modulePath } = parseCargoMarkerName(path.basename(rsReal, '.rs'));
|
|
29
65
|
const cargoDeps = state.config.cargoDependencies ?? {};
|
|
30
66
|
if (Object.hasOwn(cargoDeps, crateName)
|
|
31
67
|
&& path.dirname(rsReal) === fs.realpathSync(path.join(state.config.paths.cache, 'rust-crates'))) {
|
|
32
|
-
const {
|
|
68
|
+
const { exports } = createCrateImportBridge({
|
|
33
69
|
crateName,
|
|
70
|
+
modulePath,
|
|
34
71
|
spec: cargoDeps[crateName],
|
|
35
72
|
cacheDir: state.config.paths.cache,
|
|
36
73
|
dtsMode: state.config.dts,
|
|
37
74
|
log: () => {},
|
|
38
75
|
});
|
|
39
|
-
// A crate
|
|
40
|
-
// name), so the proxy exports the clean name and reads the
|
|
41
|
-
return
|
|
42
|
-
...model.classes.map((c) => c.name),
|
|
43
|
-
...model.enums.map((e) => e.name),
|
|
44
|
-
...model.freeFns.map((f) => f.jsName),
|
|
45
|
-
...(model.consts ?? []).map((c) => c.name),
|
|
46
|
-
].map((name) => ({ local: name, wire: `${namePrefix}${name}` })));
|
|
76
|
+
// A crate registers its public names under per-crate names (two crates may export the
|
|
77
|
+
// same name), so the proxy exports the clean name and reads the registered one off the module.
|
|
78
|
+
return exports;
|
|
47
79
|
}
|
|
48
80
|
|
|
49
81
|
const pkg = state.config.allDependencies.find((d) => d.export?.type === 'cargo'
|
|
@@ -63,18 +95,18 @@ export function getRustJsScript(target, rsFile) {
|
|
|
63
95
|
log: () => {},
|
|
64
96
|
});
|
|
65
97
|
}
|
|
66
|
-
|
|
98
|
+
return [
|
|
67
99
|
...model.classes.map((c) => c.name),
|
|
100
|
+
...(model.streams ?? []).map((s) => s.name),
|
|
68
101
|
...model.enums.map((e) => e.name),
|
|
69
102
|
...(model.freeFns ?? []).map((f) => f.jsName),
|
|
70
103
|
// `pub const`/`pub static` register as module constants, so the proxy exports them too.
|
|
71
104
|
...(model.consts ?? []).map((c) => c.name),
|
|
72
105
|
...vectors.map((v) => v.name),
|
|
73
106
|
];
|
|
74
|
-
return buildScript(target, symbols);
|
|
75
107
|
}
|
|
76
108
|
|
|
77
|
-
function buildScript(target, symbols) {
|
|
109
|
+
function buildScript(target, symbols, base) {
|
|
78
110
|
if (!target) {
|
|
79
111
|
throw new Error('The target is not available!');
|
|
80
112
|
}
|
|
@@ -92,7 +124,7 @@ function buildScript(target, symbols) {
|
|
|
92
124
|
}
|
|
93
125
|
|
|
94
126
|
return `
|
|
95
|
-
${getPlatformScript(env)}
|
|
127
|
+
${getPlatformScript(env, base)}
|
|
96
128
|
|
|
97
129
|
export let AllSymbols = {};
|
|
98
130
|
${symbolExportDefineString}
|
|
@@ -167,8 +199,9 @@ function getReactNativeScript(env) {
|
|
|
167
199
|
`;
|
|
168
200
|
}
|
|
169
201
|
|
|
170
|
-
function getWebScript(env) {
|
|
202
|
+
function getWebScript(env, base) {
|
|
171
203
|
const params = `{
|
|
204
|
+
path: base,
|
|
172
205
|
...config,
|
|
173
206
|
env: {...${env}, ...config.env},
|
|
174
207
|
paths: {
|
|
@@ -181,7 +214,8 @@ function getWebScript(env) {
|
|
|
181
214
|
|
|
182
215
|
return `
|
|
183
216
|
function __crossbindBoot(config) {
|
|
184
|
-
|
|
217
|
+
const base = new URL((typeof __webpack_public_path__ === 'string' ? __webpack_public_path__ : ${JSON.stringify(base)}) || './', document.baseURI).href;
|
|
218
|
+
return import(/* webpackIgnore: true */ /* @vite-ignore */ base + 'crossbind.js')
|
|
185
219
|
.then(n => window.Crossbind.initNative(${params}));
|
|
186
220
|
}
|
|
187
221
|
`;
|