Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/pack-ecosystem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && contains(github.event.head_commit.message, '(pack)')) ||
(github.event_name == 'pull_request' && contains(github.event.pull_request.title, '(pack)'))
uses: utooland/utoo-ecosystem-ci/.github/workflows/ecosystem-ci.yml@main
uses: utooland/utoo-ecosystem-ci/.github/workflows/ecosystem-ci.yml@e95e8271c1683b0c26329a40ed1ebcd69887b6c5
with:
candidate_mode: source
utoo_repository: >-
Expand All @@ -40,4 +40,4 @@ jobs:
suite: >-
${{ github.event_name == 'workflow_dispatch' && inputs.suite || 'all' }}
harness_repository: utooland/utoo-ecosystem-ci
harness_ref: main
harness_ref: e95e8271c1683b0c26329a40ed1ebcd69887b6c5
2 changes: 1 addition & 1 deletion .github/workflows/utooweb-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ permissions:
jobs:
build:
name: utooweb-ci-build-and-e2e
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Init git submodules
Expand Down
67 changes: 25 additions & 42 deletions crates/pack-core/src/shared/resolve/externals_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,22 +345,27 @@ impl ExternalsPlugin {
let before_condition = match externals_config_ref.is_empty() {
true => BeforeResolvePluginCondition::Never.cell(),
false => {
// Extract all possible module names from external keys
// For "react" -> ["react"]
// For "@ant/bigfish/antd" -> ["@ant/bigfish/antd", "@ant/bigfish"]
let mut modules = Vec::new();
for key in externals_config_ref.keys() {
modules.push(key.clone());
// Extract scoped package name if key contains additional path
if key.starts_with('@')
&& let (Some(pos), Some(first_pos)) = (key.rfind('/'), key.find('/'))
&& pos > first_pos
{
modules.push(key[..pos].into());
}
}

BeforeResolvePluginCondition::from_modules(Vc::cell(modules))
// Match full requests, including URI schemes, before aliases are applied.
// Escape glob syntax so external keys remain literal request names.
let requests = externals_config_ref
.keys()
.map(|key| {
let mut escaped = String::with_capacity(key.len());
for ch in key.chars() {
if matches!(ch, '\\' | '*' | '?' | '[' | ']' | '{' | '}' | ',') {
escaped.push('\\');
}
escaped.push(ch);
}
escaped
})
.collect::<Vec<_>>()
.join(",");

BeforeResolvePluginCondition::from_request_glob(Glob::new(
format!("{{{requests}}}").into(),
GlobOptions::default(),
))
}
};
let before_condition = before_condition.to_resolved().await?;
Expand Down Expand Up @@ -435,34 +440,12 @@ impl BeforeResolvePlugin for ExternalsPlugin {
request: Vc<Request>,
) -> Result<Vc<ResolveResultOption>> {
let externals_config = self.externals_config.await?;
let request_value = request.await?;

let (module_name, subpath_str) = match &*request_value {
Request::Module {
module: Pattern::Constant(name),
path: Pattern::Constant(path),
..
} => (name.as_str(), path.as_str()),
Request::Raw {
path: Pattern::Constant(name),
..
} => (name.as_str(), ""),
_ => return Ok(ResolveResultOption::none()),
};

// Try full path first (e.g., "@ant/bigfish/antd" from module="@ant/bigfish" + path="/antd")
if !subpath_str.is_empty() {
let full_path = format!("{}{}", module_name, subpath_str);
if let Some(external_config) = externals_config.get(full_path.as_str()) {
return Ok(handle_external_config(external_config, &full_path));
}
// If full path not in externals, skip to let after_resolve or normal resolution handle it
let Some(request) = request.await?.request() else {
return Ok(ResolveResultOption::none());
}
};

// Try module name only (e.g., "react")
if let Some(external_config) = externals_config.get(module_name) {
return Ok(handle_external_config(external_config, module_name));
if let Some(external_config) = externals_config.get(request.as_str()) {
return Ok(handle_external_config(external_config, &request));
}

Ok(ResolveResultOption::none())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/output/_turbopack__runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# The Node runtime is unrelated to external request matching.
_turbopack__runtime.js
31 changes: 31 additions & 0 deletions crates/pack-tests/tests/snapshot/externals/virtual-alias/assert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const assert = require("node:assert/strict");
const { spawnSync } = require("node:child_process");
const path = require("node:path");

const result = spawnSync(
process.execPath,
[
"-e",
`
const assert = require("node:assert/strict");
const result = require("./output/main.js");
const { state } = require("./input/fc.js");

assert.equal(result.sameInstance, true);
assert.equal(result.requestInitialized, true);
assert.equal(result.sameUnscopedInstance, true);
assert.equal(result.unscopedInitialized, true);
assert.equal(result.sameLiteralInstance, true);
assert.equal(result.literalInitialized, true);
assert.equal(state.initialized, true);
`,
],
{
cwd: __dirname,
env: { ...process.env, NODE_PATH: path.join(__dirname, "input") },
encoding: "utf8",
},
);

assert.ifError(result.error);
assert.equal(result.status, 0, result.stderr || result.stdout);
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"runtimeType": "Production",
"config": {
"entry": [
{
"import": "input/index.js",
"name": "main"
}
],
"target": "node",
"resolve": {
"alias": {
"@mvp/request/h5": "@mvp/request/fc",
"plain-request/h5": "@mvp/request/fc",
"virtual:request/h5": "@mvp/request/fc",
"virtual:request/[h5]{test}*": "@mvp/request/fc",
"@mvp/request/fc": "./input/fc.js"
}
},
"externals": {
"@mvp/request/h5": "commonjs fc",
"@mvp/request/fc": "commonjs fc",
"plain-request/h5": "commonjs fc",
"virtual:request/h5": "commonjs fc",
"virtual:request/[h5]{test}*": "commonjs fc"
},
"optimization": {
"minify": false,
"moduleIds": "named"
},
"sourceMaps": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.state = { initialized: false };
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { state as initialized } from "@mvp/request/h5";
import { state as unscoped } from "plain-request/h5";
import { state as requested } from "virtual:request/h5";
import { state as literal } from "virtual:request/[h5]{test}*";

initialized.initialized = true;

export const sameInstance = initialized === requested;
export const requestInitialized = requested.initialized;
export const sameUnscopedInstance = initialized === unscoped;
export const unscopedInitialized = unscoped.initialized;
export const sameLiteralInstance = initialized === literal;
export const literalInitialized = literal.initialized;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module.exports = [
"[externals]/fc [external] (fc, cjs)", ((__turbopack_context__, module, exports) => {

var mod = __turbopack_context__.x("fc", () => require("fc"));

module.exports = mod;
}),
"[project]/externals/virtual-alias/input/index.js [server] (ecmascript)", ((__turbopack_context__) => {
"use strict";

var __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__ = __turbopack_context__.i("[externals]/fc [external] (fc, cjs)");
;
;
;
;
__TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"].initialized = true;
const sameInstance = __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"] === __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"];
const requestInitialized = __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"].initialized;
const sameUnscopedInstance = __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"] === __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"];
const unscopedInitialized = __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"].initialized;
const sameLiteralInstance = __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"] === __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"];
const literalInitialized = __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"].initialized;
__turbopack_context__.s([
"literalInitialized",
0,
literalInitialized,
"requestInitialized",
0,
requestInitialized,
"sameInstance",
0,
sameInstance,
"sameLiteralInstance",
0,
sameLiteralInstance,
"sameUnscopedInstance",
0,
sameUnscopedInstance,
"unscopedInitialized",
0,
unscopedInitialized
]);
}),
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
var R=require("./_turbopack__runtime.js")("main.js")
R.c("_root-of-the-server___0z3rgi_jckydl.js")
R.m("[project]/externals/virtual-alias/input/index.js [server] (ecmascript)")
module.exports=R.m("[project]/externals/virtual-alias/input/index.js [server] (ecmascript)").exports
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/output/_turbopack__runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# The Node runtime is unrelated to external request matching.
_turbopack__runtime.js
27 changes: 27 additions & 0 deletions crates/pack-tests/tests/snapshot/externals/virtual-only/assert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const assert = require("node:assert/strict");
const { spawnSync } = require("node:child_process");
const path = require("node:path");

const result = spawnSync(
process.execPath,
[
"-e",
`
const assert = require("node:assert/strict");
const result = require("./output/main.js");
const { state } = require("./input/fc.js");

assert.equal(result.sameInstance, true);
assert.equal(result.requestInitialized, true);
assert.equal(state.initialized, true);
`,
],
{
cwd: __dirname,
env: { ...process.env, NODE_PATH: path.join(__dirname, "input") },
encoding: "utf8",
},
);

assert.ifError(result.error);
assert.equal(result.status, 0, result.stderr || result.stdout);
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"runtimeType": "Production",
"config": {
"entry": [
{
"import": "input/index.js",
"name": "main"
}
],
"target": "node",
"externals": {
"@mvp/request/h5": "commonjs fc",
"virtual:request/h5": "commonjs fc"
},
"optimization": {
"minify": false,
"moduleIds": "named"
},
"sourceMaps": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.state = { initialized: false };
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { state as initialized } from "@mvp/request/h5";
import { state as requested } from "virtual:request/h5";

initialized.initialized = true;

export const sameInstance = initialized === requested;
export const requestInitialized = requested.initialized;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module.exports = [
"[externals]/fc [external] (fc, cjs)", ((__turbopack_context__, module, exports) => {

var mod = __turbopack_context__.x("fc", () => require("fc"));

module.exports = mod;
}),
"[project]/externals/virtual-only/input/index.js [server] (ecmascript)", ((__turbopack_context__) => {
"use strict";

var __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__ = __turbopack_context__.i("[externals]/fc [external] (fc, cjs)");
;
;
__TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"].initialized = true;
const sameInstance = __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"] === __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"];
const requestInitialized = __TURBOPACK__imported__module__$5b$externals$5d2f$fc__$5b$external$5d$__$28$fc$2c$__cjs$29$__["state"].initialized;
__turbopack_context__.s([
"requestInitialized",
0,
requestInitialized,
"sameInstance",
0,
sameInstance
]);
}),
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
var R=require("./_turbopack__runtime.js")("main.js")
R.c("_root-of-the-server___1uve16sck8pk_.js")
R.m("[project]/externals/virtual-only/input/index.js [server] (ecmascript)")
module.exports=R.m("[project]/externals/virtual-only/input/index.js [server] (ecmascript)").exports
Loading