Skip to content

Commit

Permalink
Fix double-loading packages on npm (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 authored Jun 15, 2023
1 parent 07290f7 commit 513a0ae
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 2 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2.4.7
g
* Fix a bug where npm packages could crash on Node.js if loaded both through
`require()` and `import`.

## 2.4.6

* Properly mark NPM packages as `"type": "module"` when `pkg.jsEsmExports` is
Expand Down
25 changes: 24 additions & 1 deletion lib/src/npm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,11 @@ void _writePlatformWrapper(String path, JSRequireSet requires,
{bool node = false}) {
var exports = jsEsmExports.value;
if (exports != null) {
_writeImportWrapper('$path.${node ? 'mjs' : 'js'}', requires, exports);
if (node) {
_writeNodeImportWrapper('$path.mjs', exports);
} else {
_writeImportWrapper('$path.${node ? 'mjs' : 'js'}', requires, exports);
}
_writeRequireWrapper('$path.${node ? 'js' : 'cjs'}', requires);
} else {
_writeRequireWrapper('$path.js', requires);
Expand Down Expand Up @@ -613,6 +617,25 @@ String _loadRequires(JSRequireSet requires) {
return buffer.toString();
}

/// Writes a wrapper to [path] that loads and re-exports `$_npmName.node.js`
/// using ESM imports.
///
/// Rather than having a totally separate ESM wrapper, for Node we load ESM
/// exports *through* the require wrapper. This ensures that we don't run into
/// issues like sass/dart-sass#2017 if both are loaded in the same Node process.
///
/// [exports] is the value of [jsEsmExports].
void _writeNodeImportWrapper(String path, Set<String> exports) {
var cjsUrl = './' + p.setExtension(p.basename(path), '.js');
var buffer = StringBuffer("import cjs from ${json.encode(cjsUrl)};\n\n");

for (var export in exports) {
buffer.writeln("export const $export = cjs.$export;");
}

writeString(path, buffer.toString());
}

/// Writes a wrapper to [path] that loads and re-exports `$_npmName.dart.js`
/// using ESM imports with [requires] injected.
///
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: cli_pkg
version: 2.4.6
version: 2.4.7
description: Grinder tasks for releasing Dart CLI packages.
homepage: https://github.com/google/dart_cli_pkg

Expand Down
11 changes: 11 additions & 0 deletions test/npm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,11 @@ void main() {
const myApp = require("my_app");
console.log(myApp.hello);
"""),
// Regression test for sass/dart-sass#2017
d.file("both.mjs", """
import "./test.mjs";
import "./test.cjs";
""")
]).create();

Expand All @@ -717,6 +722,12 @@ void main() {
await TestProcess.start("node$dotExe", [d.path("depender/test.cjs")]);
expect(cjsProcess.stdout, emits("true"));
await cjsProcess.shouldExit(0);

var bothProcess =
await TestProcess.start("node$dotExe", [d.path("depender/both.mjs")]);
expect(bothProcess.stdout, emits("true"));
expect(bothProcess.stdout, emits("true"));
await bothProcess.shouldExit(0);
});

test("overwrite existing string value", () async {
Expand Down

0 comments on commit 513a0ae

Please sign in to comment.