Skip to content

Commit

Permalink
chore(runtime-diff): alignment of startup chunk dependencies runtime …
Browse files Browse the repository at this point in the history
…module (web-infra-dev#4508)

* feat(runtime-diff): Align startup chunks dependencies

Align startup chunk dependencies runtime module

* fix: clippy error
  • Loading branch information
LingyuCoder committed Dec 11, 2023
1 parent 05d366c commit 77f57e5
Show file tree
Hide file tree
Showing 39 changed files with 423 additions and 29 deletions.
49 changes: 40 additions & 9 deletions crates/rspack_core/src/chunk.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::cmp::Ordering;
use std::{fmt::Debug, hash::Hash, sync::Arc};

use rspack_database::DatabaseItem;
use itertools::Itertools;
use rspack_database::{DatabaseItem, Ukey};
use rspack_hash::{RspackHash, RspackHashDigest};
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};

use crate::ChunkGraph;
use crate::{ChunkGraph, ChunkGroup};
use crate::{ChunkGroupByUkey, ChunkGroupUkey, ChunkUkey, SourceType};
use crate::{Compilation, EntryOptions, Filename, ModuleGraph, RuntimeSpec};

Expand Down Expand Up @@ -69,6 +71,33 @@ impl Chunk {
}
}

pub fn get_sorted_groups_iter(
&self,
chunk_group_by_ukey: &ChunkGroupByUkey,
) -> impl Iterator<Item = &Ukey<ChunkGroup>> {
self.groups.iter().sorted_by(|ukey_a, ukey_b| {
let index_a = chunk_group_by_ukey
.get(ukey_a)
.expect("Group should exists")
.index;
let index_b = chunk_group_by_ukey
.get(ukey_b)
.expect("Group should exists")
.index;
// None should be greater than Some<_> to align with JavaScript
match index_a {
None => match index_b {
None => Ordering::Equal,
Some(_) => Ordering::Greater,
},
Some(index_a) => match index_b {
None => Ordering::Less,
Some(index_b) => index_a.cmp(&index_b),
},
}
})
}

pub fn get_entry_options<'a>(
&self,
chunk_group_by_ukey: &'a ChunkGroupByUkey,
Expand All @@ -88,13 +117,15 @@ impl Chunk {
}

pub fn split(&mut self, new_chunk: &mut Chunk, chunk_group_by_ukey: &mut ChunkGroupByUkey) {
self.groups.iter().for_each(|group| {
let group = chunk_group_by_ukey
.get_mut(group)
.expect("Group should exist");
group.insert_chunk(new_chunk.ukey, self.ukey);
new_chunk.add_group(group.ukey);
});
self
.get_sorted_groups_iter(chunk_group_by_ukey)
.for_each(|group| {
let group = chunk_group_by_ukey
.get_mut(group)
.expect("Group should exist");
group.insert_chunk(new_chunk.ukey, self.ukey);
new_chunk.add_group(group.ukey);
});
new_chunk.id_name_hints.extend(self.id_name_hints.clone());
new_chunk.runtime.extend(self.runtime.clone());
}
Expand Down
7 changes: 4 additions & 3 deletions crates/rspack_core/src/chunk_graph/chunk_graph_chunk.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! There are methods whose verb is `ChunkGraphChunk`

use indexmap::IndexSet;
use rspack_database::Database;
use rspack_identifier::{IdentifierLinkedMap, IdentifierSet};
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
use rustc_hash::FxHashMap as HashMap;

use crate::{
find_graph_roots, merge_runtime, BoxModule, Chunk, ChunkByUkey, ChunkGroup, ChunkGroupByUkey,
Expand Down Expand Up @@ -402,8 +403,8 @@ impl ChunkGraph {
chunk_group_by_ukey: &ChunkGroupByUkey,
) -> impl Iterator<Item = ChunkUkey> {
let chunk = chunk_by_ukey.get(chunk_ukey).expect("should have chunk");
let mut set = HashSet::default();
for chunk_group_ukey in chunk.groups.iter() {
let mut set = IndexSet::new();
for chunk_group_ukey in chunk.get_sorted_groups_iter(chunk_group_by_ukey) {
let chunk_group = chunk_group_by_ukey
.get(chunk_group_ukey)
.expect("should have chunk group");
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::iter;

use itertools::Itertools;
use rspack_core::{
impl_runtime_module,
rspack_sources::{BoxSource, RawSource, SourceExt},
ChunkUkey, Compilation, RuntimeModule,
ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule,
};
use rspack_identifier::Identifier;
use rspack_plugin_javascript::runtime::stringify_chunks_to_array;
use rustc_hash::FxHashSet as HashSet;

#[derive(Debug, Eq)]
pub struct StartupChunkDependenciesRuntimeModule {
Expand Down Expand Up @@ -45,13 +46,47 @@ impl RuntimeModule for StartupChunkDependenciesRuntimeModule {
.expect("Chunk not found");
chunk.expect_id().to_string()
})
.collect::<HashSet<_>>();
let source = if self.async_chunk_loading {
include_str!("runtime/startup_chunk_dependencies_with_async.js")
.collect::<Vec<_>>();

let body = if self.async_chunk_loading {
match chunk_ids.len() {
1 => format!(
r#"return {}("{}").then(next);"#,
RuntimeGlobals::ENSURE_CHUNK,
chunk_ids.first().expect("Should has at least one chunk")
),
2 => format!(
r#"return Promise.all([{}]).then(next);"#,
chunk_ids
.iter()
.map(|cid| format!(r#"{}("{}")"#, RuntimeGlobals::ENSURE_CHUNK, cid))
.join(",\n")
),
_ => format!(
r#"return Promise.all({}.map({}, {})).then(next);"#,
serde_json::to_string(&chunk_ids).expect("Invalid json to string"),
RuntimeGlobals::ENSURE_CHUNK,
RuntimeGlobals::REQUIRE
),
}
} else {
include_str!("runtime/startup_chunk_dependencies.js")
chunk_ids
.iter()
.map(|cid| format!(r#"{}("{}");"#, RuntimeGlobals::ENSURE_CHUNK, cid))
.chain(iter::once("return next();".to_string()))
.join("\n")
};
RawSource::from(source.replace("$ChunkIds$", &stringify_chunks_to_array(&chunk_ids))).boxed()

RawSource::from(format!(
r#"var next = {};
{} = function() {{
{}
}};"#,
RuntimeGlobals::STARTUP,
RuntimeGlobals::STARTUP,
body
))
.boxed()
} else {
unreachable!("should have chunk for StartupChunkDependenciesRuntimeModule")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { value } from "./shared";
export const result = value;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const fs = require("fs");
const vm = require("vm");
const path = require("path");

const requireAsync = file => {
return new Promise((resolve, reject) => {
fs.readFile(file, { encoding: "utf8" }, function (err, data) {
const sandbox = {
module: {
exports: {}
},
require: require,
__dirname: __dirname,
__filename: __filename
};
vm.runInNewContext(data, sandbox);
sandbox.module.exports.MyLib.then(resolve).catch(reject);
});
});
};

it("should work with chunkLoading=async-node and only one entrypoint chunk", async () => {
const chunk = await requireAsync(path.join(__dirname, "async.js"));
expect(chunk.result).toBe("1");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default "1";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import xxx from "./shared";
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import lib1 from "./lib-1";
export const value = lib1;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module.exports = {
entry: {
main: "./index.js",
async: "./async.js",
other: "./other.js"
},
output: {
filename: "[name].js",
chunkLoading: "async-node",
library: {
name: "MyLib",
type: "commonjs-module"
}
},
optimization: {
splitChunks: {
minSize: 0,
cacheGroups: {
lib1: {
test: /lib-1/,
name: "lib1",
chunks: "all",
priority: 3
}
}
}
},
target: "node"
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { value } from "./shared";
export const result = value;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const fs = require("fs");
const vm = require("vm");
const path = require("path");

const requireAsync = file => {
return new Promise((resolve, reject) => {
fs.readFile(file, { encoding: "utf8" }, function (err, data) {
const sandbox = {
module: {
exports: {}
},
require: require,
__dirname: __dirname,
__filename: __filename
};
vm.runInNewContext(data, sandbox);
sandbox.module.exports.MyLib.then(resolve).catch(reject);
});
});
};

it("should work with chunkLoading=async-node and only two entrypoint chunks", async () => {
const chunk = await requireAsync(path.join(__dirname, "async.js"));
expect(chunk.result).toBe("12");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default "1";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default "2";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import xxx from "./shared";
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import lib1 from "./lib-1";
import lib2 from "./lib-2";
export const value = lib1 + lib2;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module.exports = {
entry: {
main: "./index.js",
async: "./async.js",
other: "./other.js"
},
output: {
filename: "[name].js",
chunkLoading: "async-node",
library: {
name: "MyLib",
type: "commonjs-module"
}
},
optimization: {
splitChunks: {
minSize: 0,
cacheGroups: {
lib1: {
test: /lib-1/,
name: "lib1",
chunks: "all",
priority: 3
},
lib2: {
test: /lib-2/,
name: "lib2",
chunks: "all",
priority: 2
}
}
}
},
target: "node"
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { value } from "./shared";
export const result = value;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const fs = require("fs");
const vm = require("vm");
const path = require("path");

const requireAsync = file => {
return new Promise((resolve, reject) => {
fs.readFile(file, { encoding: "utf8" }, function (err, data) {
const sandbox = {
module: {
exports: {}
},
require: require,
__dirname: __dirname,
__filename: __filename
};
vm.runInNewContext(data, sandbox);
sandbox.module.exports.MyLib.then(resolve).catch(reject);
});
});
};

it("should work with chunkLoading=async-node and only three or more entrypoint chunks", async () => {
const chunk = await requireAsync(path.join(__dirname, "async.js"));
expect(chunk.result).toBe("123");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default "1";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default "2";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default "3";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import xxx from "./shared";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import lib2 from "./lib-2";
import lib1 from "./lib-1";
import lib3 from "./lib-3";
export const value = lib1 + lib2 + lib3;
Loading

0 comments on commit 77f57e5

Please sign in to comment.