Rollup打包顺序问题咨询:同步脚本代码位置不符预期
Hey there! Let's clear up this confusion for you. First off, this isn't a configuration bug—it's actually Rollup's default behavior tied to how ES modules work. Here's what's going on, plus solutions to fit your use case:
What's Happening Under the Hood
Rollup uses static analysis of ES modules to optimize your code (like tree-shaking). By design, ES modules require all static imports to be resolved and executed before the top-level code of the importing module runs. That's why Rollup moves the code from maths.js to the start of your bundled file—it's following the ES module execution order.
In your example, this causes a problem because maths.sum tries to reference numbers.base, but numbers.base hasn't been defined yet (since Rollup runs maths.js code first).
Solutions to Match Your Expected Behavior
Option 1: Refactor Code to Avoid Top-Level Dependencies
The cleanest fix is to adjust your modules so they don't rely on top-level variables from other modules. Instead, pass dependencies as arguments or use functions to delay evaluation:
Modified maths.js
let maths = {}; // Accept base as a parameter instead of relying on an external variable maths.sum = function(x, y, base) { return base + x + y; } export {maths};
Modified index.js
/** * License ... */ let numbers = {}; numbers.property = "This is a static variable"; numbers.base = 1000; // Module maths import {maths} from "./maths"; numbers.maths = maths; // Testing // Pass numbers.base as an argument console.log(numbers.maths.sum(10, 20, numbers.base))
This way, the order of bundled code doesn't matter—you're explicitly passing the value when you need it.
Option 2: Use Dynamic Imports for Execution Order Control
If you absolutely need the imported module's code to run at the exact spot of your import statement, switch to dynamic imports. Unlike static imports, dynamic imports execute when the code reaches that line:
Updated index.js
/** * License ... */ let numbers = {}; numbers.property = "This is a static variable"; numbers.base = 1000; // Module maths (dynamic import) import("./maths").then(({maths}) => { numbers.maths = maths; // Testing console.log(numbers.maths.sum(10, 20)) });
Note: Dynamic imports are asynchronous, so your code inside the .then() will run after the module loads. If you need synchronous execution, you can wrap this in an async function and use await.
Option 3: Preserve Module Structure (Multiple Output Files)
If you don't mind outputting multiple files instead of a single bundle, use the preserveModules option in your rollup.config.js. This keeps each module as a separate file, so the import statement stays in place and runs in the order you expect:
rollup.config.js
export default { input: 'index.js', output: { dir: 'dist', format: 'es', // Or 'cjs' for CommonJS preserveModules: true } };
When you run Rollup, it will output dist/index.js and dist/maths.js, with the import in index.js remaining at its original position. The browser (or Node.js) will handle executing the modules in the correct order.
Key Takeaway
Rollup's default behavior aligns with ES module standards, which prioritize resolving all imports before executing the parent module. To fix your issue, either refactor your code to avoid cross-module top-level dependencies, use dynamic imports for execution order control, or preserve the module structure with preserveModules.
内容的提问来源于stack exchange,提问作者The Devman

