I am attempting to migrate our single-page application from RequireJS to Webpack. As part of this transition, I am gradually rewriting our hundreds of modules from ASM define()
syntax to modern ESM import
/ export
syntax. Because of the size of the codebase, it's not feasible to refactor every file at once.
In doing so, I've ran into a fundamental difference between ASM / ES modules exporting: the ASM modules always export a single value, while ES modules support either named exports and/or a single export default
value. Our codebase is already set up to use single module exports, so I think the default exports are more appropriate for the modules we have.
However, this means that when importing these ES modules into legacy ASM modules, and also fetching them with require()
or import()
, we always have to extract the default
property from them.
Examples:
// Refactored ESM module
// Both ASM and ESM dependencies can be imported with this syntax
import LegacyDependency from "legacyDependency";
import EsmDependency from "esmDependency";
// Legacy ASM module
// ASM dependencies come in as-is; ESM dependencies come in as modules with default property
define(["legacyDependency", "esmDependency"],
function(LegacyDependency, {default: EsmDependency}) {
});
// Async import
// Both ASM and ESM come in as modules with default property
const {default: LegacyDependency} = import("legacyDependency");
const {default: EsmDependency} = import("esmDependency");
Not only is this a lot of code to refactor, it also requires us to know what kind of module each of our files is (and then go change all references to it after it gets refactored into ESM.
Is there a way to override Webpack's importing behavior so that the import()
method will always return the module's default
export, if one exists? Even if this isn't consistent with how a "pure" ESM app would work (if it were using the browser's native import feature), it would stop a lot of headaches in the short-term during this transitional period.
Ultimately I'd like it if we could adjust Webpack's interpreter so that the above examples could be rewritten as this:
// Legacy ASM module (no destructuring)
define(["legacyDependency", "esmDependency", "namedDependency"],
function(LegacyDependency, EsmDependency, {namedFn, namedProperty}) {
});
// Async import (no destructuring)
const LegacyDependency = import("legacyDependency");
const EsmDependency = import("esmDependency");
const {namedFn, namedProperty} = import("namedDependency");
Is the above possible with Webpack's configuration?
We ultimately decided to bite the bullet and refactor all of our files before merging them all at once. We used this tool to automatically rewrite the define()
headers into import
statements in bulk; after that we just need to rewrite our async imports manually.