handle hashbangs in javascript files

fixes https://github.com/vercel/next.js/issues/27806
This commit is contained in:
Tobias Koppers 2021-08-10 11:23:30 +02:00
parent fcdd04a833
commit 720aa43bd3
9 changed files with 42 additions and 5 deletions

View File

@ -187,6 +187,7 @@
"kaios",
"parallelism",
"gitattributes",
"hashbang",
"webassemblyjs",
"fsevents",

View File

@ -69,7 +69,8 @@ class CompatibilityPlugin {
* @param {JavascriptParser} parser the parser
* @returns {void}
*/
const nestedWebpackRequireHandler = parser => {
const handler = parser => {
// Handle nested requires
parser.hooks.preStatement.tap("CompatibilityPlugin", statement => {
if (
statement.type === "FunctionDeclaration" &&
@ -117,17 +118,33 @@ class CompatibilityPlugin {
parser.state.module.addPresentationalDependency(dep);
return true;
});
// Handle hashbang
parser.hooks.program.tap(
"CompatibilityPlugin",
(program, comments) => {
if (comments.length === 0) return;
const c = comments[0];
if (c.type === "Line" && c.range[0] === 0) {
if (parser.state.source.slice(0, 2).toString() !== "#!") return;
// this is a hashbang comment
const dep = new ConstDependency("//", 0);
dep.loc = c.loc;
parser.state.module.addPresentationalDependency(dep);
}
}
);
};
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("CompatibilityPlugin", nestedWebpackRequireHandler);
.tap("CompatibilityPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("CompatibilityPlugin", nestedWebpackRequireHandler);
.tap("CompatibilityPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("CompatibilityPlugin", nestedWebpackRequireHandler);
.tap("CompatibilityPlugin", handler);
}
);
}

View File

@ -1025,7 +1025,9 @@ class NormalModule extends Module {
let result;
try {
result = this.parser.parse(this._ast || this._source.source(), {
const source = this._source.source();
result = this.parser.parse(this._ast || source, {
source,
current: this,
module: this,
compilation: compilation,

View File

@ -12,6 +12,7 @@
/**
* @typedef {Object} ParserStateBase
* @property {string | Buffer} source
* @property {NormalModule} current
* @property {NormalModule} module
* @property {Compilation} compilation

View File

@ -135,6 +135,8 @@ const defaultParserOptions = {
locations: true,
ecmaVersion: "latest",
sourceType: "module",
// https://github.com/tc39/proposal-hashbang
allowHashBang: true,
onComment: null
};

View File

@ -0,0 +1,2 @@
#!/usr/bin/env node
module.exports = "ok";

View File

@ -0,0 +1,2 @@
#!/usr/bin/env node
export default "ok";

View File

@ -0,0 +1,9 @@
it("should load a file with hashbang", function () {
var result = require("./file.js");
expect(result).toEqual("ok");
});
import result from "./file.mjs";
it("should load a module with hashbang", function () {
expect(result).toEqual("ok");
});

1
types.d.ts vendored
View File

@ -8470,6 +8470,7 @@ declare interface ParserOptionsByModuleTypeUnknown {
}
type ParserState = Record<string, any> & ParserStateBase;
declare interface ParserStateBase {
source: string | Buffer;
current: NormalModule;
module: NormalModule;
compilation: Compilation;