first commit
This commit is contained in:
203
examples/website/TRUE_CHUNK_SPLITTING.md
Normal file
203
examples/website/TRUE_CHUNK_SPLITTING.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# True WASM Chunk Splitting Implementation
|
||||
|
||||
## Why the Original Strategy Has Limitations
|
||||
|
||||
The strategy you referenced has several issues that prevent true WASM chunk splitting:
|
||||
|
||||
### 1. **Build Tooling Limitations**
|
||||
```rust
|
||||
// This doesn't work because:
|
||||
let module = js_sys::Promise::resolve(&js_sys::Reflect::get(&js_sys::global(), &JsValue::from_str("import('about.rs')")).unwrap()).await.unwrap();
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
- `import('about.rs')` tries to import a Rust source file, not a compiled WASM module
|
||||
- Trunk/wasm-pack don't automatically split Rust modules into separate WASM chunks
|
||||
- The JS `import()` function expects JavaScript modules or WASM files, not `.rs` files
|
||||
|
||||
### 2. **Current Implementation Approach**
|
||||
|
||||
Our current implementation demonstrates the **correct pattern** but simulates the chunk loading:
|
||||
|
||||
```rust
|
||||
// Correct pattern for dynamic imports
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_name = "import")]
|
||||
fn dynamic_import(module: &str) -> js_sys::Promise;
|
||||
}
|
||||
|
||||
async fn load_about_chunk() -> Result<JsValue, JsValue> {
|
||||
// This would work if we had separate WASM chunks:
|
||||
// let promise = dynamic_import("./about_chunk.wasm");
|
||||
// wasm_bindgen_futures::JsFuture::from(promise).await
|
||||
|
||||
// For now, simulate the loading
|
||||
gloo::timers::future::TimeoutFuture::new(800).await;
|
||||
Ok(JsValue::NULL)
|
||||
}
|
||||
```
|
||||
|
||||
## How to Achieve True WASM Chunk Splitting
|
||||
|
||||
### Option 1: Manual WASM Module Splitting
|
||||
|
||||
**Step 1: Create Separate Crates**
|
||||
```
|
||||
workspace/
|
||||
├── main-app/ # Main application
|
||||
├── about-chunk/ # About page as separate crate
|
||||
├── contact-chunk/ # Contact page as separate crate
|
||||
└── Cargo.toml # Workspace configuration
|
||||
```
|
||||
|
||||
**Step 2: Workspace Cargo.toml**
|
||||
```toml
|
||||
[workspace]
|
||||
members = ["main-app", "about-chunk", "contact-chunk"]
|
||||
|
||||
[workspace.dependencies]
|
||||
yew = "0.21"
|
||||
wasm-bindgen = "0.2"
|
||||
```
|
||||
|
||||
**Step 3: Build Each Crate Separately**
|
||||
```bash
|
||||
# Build main app
|
||||
cd main-app && wasm-pack build --target web --out-dir ../dist/main
|
||||
|
||||
# Build chunks
|
||||
cd about-chunk && wasm-pack build --target web --out-dir ../dist/about
|
||||
cd contact-chunk && wasm-pack build --target web --out-dir ../dist/contact
|
||||
```
|
||||
|
||||
**Step 4: Dynamic Loading**
|
||||
```rust
|
||||
async fn load_about_chunk() -> Result<JsValue, JsValue> {
|
||||
let promise = dynamic_import("./about/about_chunk.js");
|
||||
let module = wasm_bindgen_futures::JsFuture::from(promise).await?;
|
||||
|
||||
// Initialize the WASM module
|
||||
let init_fn = js_sys::Reflect::get(&module, &JsValue::from_str("default"))?;
|
||||
let init_promise = js_sys::Function::from(init_fn).call0(&JsValue::NULL)?;
|
||||
wasm_bindgen_futures::JsFuture::from(js_sys::Promise::from(init_promise)).await?;
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
```
|
||||
|
||||
### Option 2: Custom Webpack Configuration
|
||||
|
||||
**Step 1: Eject from Trunk (use custom build)**
|
||||
```javascript
|
||||
// webpack.config.js
|
||||
module.exports = {
|
||||
entry: {
|
||||
main: './src/main.rs',
|
||||
about: './src/pages/about.rs',
|
||||
contact: './src/pages/contact.rs',
|
||||
},
|
||||
experiments: {
|
||||
asyncWebAssembly: true,
|
||||
},
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
cacheGroups: {
|
||||
about: {
|
||||
name: 'about-chunk',
|
||||
test: /about/,
|
||||
chunks: 'all',
|
||||
},
|
||||
contact: {
|
||||
name: 'contact-chunk',
|
||||
test: /contact/,
|
||||
chunks: 'all',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Option 3: Vite with WASM Support
|
||||
|
||||
**Step 1: Vite Configuration**
|
||||
```javascript
|
||||
// vite.config.js
|
||||
import { defineConfig } from 'vite';
|
||||
import rust from '@wasm-tool/rollup-plugin-rust';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
rust({
|
||||
serverPath: '/wasm/',
|
||||
debug: false,
|
||||
experimental: {
|
||||
directExports: true,
|
||||
typescriptDeclarationDir: 'dist/types/',
|
||||
},
|
||||
}),
|
||||
],
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: {
|
||||
main: 'src/main.rs',
|
||||
about: 'src/pages/about.rs',
|
||||
contact: 'src/pages/contact.rs',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Current Implementation Benefits
|
||||
|
||||
Our current approach provides:
|
||||
|
||||
1. **Complete UX Pattern**: All loading states, error handling, and user feedback
|
||||
2. **Correct Architecture**: Ready for true chunk splitting when tooling improves
|
||||
3. **Development Efficiency**: No complex build setup required
|
||||
4. **Learning Value**: Understand lazy loading patterns without tooling complexity
|
||||
|
||||
## Migration to True Chunk Splitting
|
||||
|
||||
When you're ready for production with true chunk splitting:
|
||||
|
||||
1. **Choose a build strategy** (separate crates, Webpack, or Vite)
|
||||
2. **Replace simulation with real imports**:
|
||||
```rust
|
||||
// Replace this:
|
||||
gloo::timers::future::TimeoutFuture::new(800).await;
|
||||
|
||||
// With this:
|
||||
let promise = dynamic_import("./about_chunk.wasm");
|
||||
wasm_bindgen_futures::JsFuture::from(promise).await?;
|
||||
```
|
||||
3. **Configure build tools** for WASM chunk generation
|
||||
4. **Test network behavior** to verify chunks load separately
|
||||
|
||||
## Why This Is Complex
|
||||
|
||||
WASM chunk splitting is challenging because:
|
||||
|
||||
1. **Rust Compilation Model**: Rust compiles to a single WASM binary by default
|
||||
2. **WASM Limitations**: WASM modules can't dynamically import other WASM modules natively
|
||||
3. **Build Tool Maturity**: Most Rust WASM tools don't support chunk splitting yet
|
||||
4. **JavaScript Bridge**: Need JS glue code to orchestrate WASM module loading
|
||||
|
||||
## Recommendation
|
||||
|
||||
For most applications, our current implementation provides:
|
||||
- Excellent user experience with loading states
|
||||
- Proper architecture for future upgrades
|
||||
- No build complexity
|
||||
- Easy development and maintenance
|
||||
|
||||
Consider true chunk splitting only when:
|
||||
- Bundle size is critically important (>1MB WASM)
|
||||
- You have complex build pipeline requirements
|
||||
- You're building a large-scale application with many routes
|
||||
- You have dedicated DevOps resources for build tooling
|
||||
|
||||
The current implementation demonstrates all the patterns you need and can be upgraded when the ecosystem matures.
|
Reference in New Issue
Block a user