Skip to content

Commit

Permalink
Merge pull request #37 from dumberjs/node-import
Browse files Browse the repository at this point in the history
feat: support node: import like require('node:fs/promises')
  • Loading branch information
3cp authored Dec 24, 2024
2 parents fc8f0fe + 8d0544c commit 812ad38
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 18 deletions.
7 changes: 6 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,9 @@ module.exports = class Bundler {
const bareId = parsedId.bareId;
const packageName = parsedId.parts[0];
const resource = bareId.slice(packageName.length + 1);
const isNodeCore = packageName.startsWith('node:');

const stub = stubModule(bareId, this._resolve);
const stub = stubModule(isNodeCore ? packageName.slice(5) : packageName, this._resolve);

if (typeof stub === 'string') {
return this.capture({
Expand All @@ -339,6 +340,10 @@ module.exports = class Bundler {
});
}

if (isNodeCore && !stub) {
throw new Error(`Core Node.js module "${packageName}" is not stubbed`);
}

return this.packageReaderFor(stub || {name: packageName})
.then(reader => resource ? reader.readResource(resource, isRelative) : reader.readMain())
.then(unit => this.capture(unit))
Expand Down
10 changes: 5 additions & 5 deletions lib/modules-todo.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ module.exports = class ModulesTodo {
let pluginSpace = space;
if (space !== PACKAGE) pluginSpace = USER_OR_PACKAGE;
const isRelativePlugin = pluginName.startsWith('.') ? 1 : 0;
const key = pluginSpace + ':' + pluginName + ':' + isRelativePlugin;
const key = pluginSpace + ' ' + pluginName + ' ' + isRelativePlugin;
if (!this.todos[key]) this.todos[key] = [];
this.todos[key].push(moduleId);
}

const key = space + ':' + parsedId.cleanId + ':' + isRelative;
const key = space + ' ' + parsedId.cleanId + ' ' + isRelative;
if (!this.todos[key]) this.todos[key] = [];
this.todos[key].push(moduleId);
});
Expand All @@ -87,15 +87,15 @@ module.exports = class ModulesTodo {
groups[SERIAL_GROUP] = [];

keys.forEach(key => {
const [space, id] = key.split(':');
const [space, id] = key.split(' ');

// Don't need the parallel optimization when running
// in nodejs.
if (!process.browser || space === USER) {
groups[SERIAL_GROUP].push(key);
} else {
const packageName = parse(id).parts[0];
const group = space + ':' + packageName;
const group = space + ' ' + packageName;
if (!groups[group]) groups[group] = [];
groups[group].push(key);
}
Expand All @@ -108,7 +108,7 @@ module.exports = class ModulesTodo {
let p = Promise.resolve();

keys.forEach(key => {
const [space, id, isRelative] = key.split(':');
const [space, id, isRelative] = key.split(' ');
const requiredBy = todos[key];

p = p.then(() => cb(id, {
Expand Down
5 changes: 5 additions & 0 deletions lib/transformers/replace.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ module.exports = function replace(unit) {
dep = dep.slice(0, -1);
}

if (dep.startsWith('node:')) {
// remove node: prefix for node built-in modules
dep = dep.slice(5);
}

// browser replacement;
if (replacement && replacement[dep]) {
dep = replacement[dep];
Expand Down
69 changes: 69 additions & 0 deletions test/bundler.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1958,3 +1958,72 @@ test("Bundler ignores runtime modules", async (t) => {
(err) => t.fail(err.stack)
);
});

test("Bundler traces node:fs/promises", async (t) => {
const fakeFs = {
"node_modules/dumber-module-loader/dist/index.debug.js":
"dumber-module-loader",

"node_modules/fs-browser-stub/package.json": JSON.stringify({
name: "fs-browser-stub",
main: "index.js",
exports: {
".": "./index.js",
"./promises": "./promises.js"
}
}),
"node_modules/fs-browser-stub/index.js": "module.exports = { promises: {}}",
"node_modules/fs-browser-stub/promises.js": "module.exports = {}",
};
const bundler = mockBundler(fakeFs);

return Promise.resolve()
.then(() =>
bundler.capture({
path: "src/app.js",
contents: "require('node:fs/promises');",
moduleId: "app.js",
})
)
.then(() => bundler.resolve())
.then(() => bundler.bundle())
.then(
(bundleMap) => {
t.deepEqual(bundleMap, {
"entry-bundle": {
files: [
{
path: "node_modules/dumber-module-loader/dist/index.debug.js",
contents: "dumber-module-loader;",
},
{
contents: "define.switchToUserSpace();",
},
{
path: "src/app.js",
contents:
"define('app.js',['require','exports','module','fs/promises'],function (require, exports, module) {\nrequire('fs/promises');\n});\n",
},
{
contents: "define.switchToPackageSpace();",
},
{
path: "node_modules/fs-browser-stub/promises.js",
contents:
"define('fs/promises.js',['require','exports','module'],function (require, exports, module) {\nmodule.exports = {}\n});\n",
},
{
contents: "define.switchToUserSpace();",
},
],
config: {
baseUrl: "/dist",
paths: {},
bundles: {},
},
},
});
},
(err) => t.fail(err.stack)
);
});
24 changes: 12 additions & 12 deletions test/modules-todo.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ test('ModulesTodo process traced unit', t => {
});

t.deepEqual(Object.assign({}, md.todos), {
'0:text!foo.html:1': ['foo'],
'2:some-plugin:0': ['foo'],
'0:some-plugin!readme.md:1': ['foo'],
'2:bar:0': ['foo'],
'1:bar/lo:1': ['bar/index']
'0 text!foo.html 1': ['foo'],
'2 some-plugin 0': ['foo'],
'0 some-plugin!readme.md 1': ['foo'],
'2 bar 0': ['foo'],
'1 bar/lo 1': ['bar/index']
});
t.notOk(md.needCssInjection);
t.ok(md.hasTodo());
Expand Down Expand Up @@ -109,7 +109,7 @@ test('ModulesTodo handles additional todos, set needCssInjection', async t => {
]);
t.notOk(md.needCssInjection);
t.deepEqual(Object.assign({}, md.todos), {
'1:bar/lor:1': ['bar/lo'],
'1 bar/lor 1': ['bar/lo'],
});
t.ok(md.hasTodo());

Expand All @@ -123,8 +123,8 @@ test('ModulesTodo handles additional todos, set needCssInjection', async t => {
]);
t.ok(md.needCssInjection);
t.deepEqual(Object.assign({}, md.todos), {
'1:bar/lor/tool.css:1': ['bar/lor/index'],
'1:bar/lor/tool2:1': ['bar/lor/index']
'1 bar/lor/tool.css 1': ['bar/lor/index'],
'1 bar/lor/tool2 1': ['bar/lor/index']
});
t.ok(md.hasTodo());

Expand Down Expand Up @@ -154,7 +154,7 @@ test('ModulesTodo sets needCssInjection for less module', t => {
});

t.deepEqual(Object.assign({}, md.todos), {
'0:foo.less:1': ['foo']
'0 foo.less 1': ['foo']
});
t.ok(md.needCssInjection);
t.ok(md.hasTodo());
Expand All @@ -168,7 +168,7 @@ test('ModulesTodo sets needCssInjection for scss module', t => {
});

t.deepEqual(Object.assign({}, md.todos), {
'0:foo.scss:1': ['foo']
'0 foo.scss 1': ['foo']
});
t.ok(md.needCssInjection);
t.ok(md.hasTodo());
Expand All @@ -182,7 +182,7 @@ test('ModulesTodo sets needCssInjection for sass module', t => {
});

t.deepEqual(Object.assign({}, md.todos), {
'0:foo.sass:1': ['foo']
'0 foo.sass 1': ['foo']
});
t.ok(md.needCssInjection);
t.ok(md.hasTodo());
Expand All @@ -196,7 +196,7 @@ test('ModulesTodo sets needCssInjection for styl module', t => {
});

t.deepEqual(Object.assign({}, md.todos), {
'0:foo.styl:1': ['foo']
'0 foo.styl 1': ['foo']
});
t.ok(md.needCssInjection);
t.ok(md.hasTodo());
Expand Down
4 changes: 4 additions & 0 deletions test/transformers/replace.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@ test('replace transform ignores empty replacement', t => {
test('replace transform cleanup dep, even with empty replacement', t => {
const source = `define('foo', ['require', 'module-a.js', './bar/', 'o/a.js'], function (require) {
require('module-a.js');
const {rm} = require('node:fs');
const {rmdir} = require('node:fs/promises');
require('./bar/');
require('o/a.js');
})`;

const result = `define('foo', ['require', 'module-a.js', './bar', 'o/a.js'], function (require) {
require('module-a.js');
const {rm} = require('fs');
const {rmdir} = require('fs/promises');
require('./bar');
require('o/a.js');
})`;
Expand Down

0 comments on commit 812ad38

Please sign in to comment.