Bug Description
On Windows, generateWildcardRequire can generate invalid conditions due to inconsistent handling of path separators (/ vs \).
There's an active issue about this bug here: vercel/ncc#593. An example of generated buggy code (borrowed from /urbdyn/ncc-bug-1):
/***/ 71330:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
function __ncc_wildcard$0 (arg) {
if (arg === "C:/code/urbdyn/ncc-bug-1/node_modules/knex/lib/dialects/") return __webpack_require__(19427);
else if (arg === "C:/code/urbdyn/ncc-bug-1/node_modules/knex/lib/dialects/") return __webpack_require__(75941);
else if (arg === "C:/code/urbdyn/ncc-bug-1/node_modules/knex/lib/dialects/") return __webpack_require__(17653);
else if (arg === "C:/code/urbdyn/ncc-bug-1/node_modules/knex/lib/dialects/") return __webpack_require__(9051);
else if (arg === "C:/code/urbdyn/ncc-bug-1/node_modules/knex/lib/dialects/") return __webpack_require__(25310);
else if (arg === "C:/code/urbdyn/ncc-bug-1/node_modules/knex/lib/dialects/") return __webpack_require__(64482);
else if (arg === "C:/code/urbdyn/ncc-bug-1/node_modules/knex/lib/dialects/") return __webpack_require__(97332);
else if (arg === "C:/code/urbdyn/ncc-bug-1/node_modules/knex/lib/dialects/") return __webpack_require__(85370);
}
Cause
|
function generateWildcardRequire(dir, wildcardPath, wildcardParam, wildcardBlocks, log) { |
|
const wildcardBlockIndex = wildcardBlocks.length; |
|
const trailingWildcard = wildcardPath.endsWith(WILDCARD); |
|
|
|
const wildcardIndex = wildcardPath.indexOf(WILDCARD); |
|
|
|
const wildcardPrefix = wildcardPath.substr(0, wildcardIndex); |
|
const wildcardSuffix = wildcardPath.substr(wildcardIndex + 1); |
|
const endPattern = wildcardSuffix ? '?(.@(js|json|node))' : '.@(js|json|node)'; |
|
|
|
// sync to support no emission case |
|
if (log) |
|
console.log('Generating wildcard requires for ' + wildcardPath.replace(WILDCARD, '*')); |
|
let options = glob.sync(wildcardPrefix + '**' + wildcardSuffix + endPattern, { mark: true, ignore: 'node_modules/**/*' }); |
|
|
|
if (!options.length) |
|
return; |
|
|
|
const optionConditions = options.map((file, index) => { |
|
const arg = JSON.stringify(file.substring(wildcardPrefix.length, file.lastIndexOf(wildcardSuffix))); |
|
let relPath = path.relative(dir, file).replace(/\\/g, '/'); |
|
if (!relPath.startsWith('../')) |
|
relPath = './' + relPath; |
|
let condition = index === 0 ? ' ' : ' else '; |
|
if (trailingWildcard && arg.endsWith('.js"')) |
|
condition += `if (arg === ${arg} || arg === ${arg.substr(0, arg.length - 4)}")`; |
|
else if (trailingWildcard && arg.endsWith('.json"')) |
|
condition += `if (arg === ${arg} || arg === ${arg.substr(0, arg.length - 6)}")`; |
|
else if (trailingWildcard && arg.endsWith('.node"')) |
|
condition += `if (arg === ${arg} || arg === ${arg.substr(0, arg.length - 6)}")`; |
|
else |
|
condition += `if (arg === ${arg})`; |
|
condition += ` return require(${JSON.stringify(relPath)});`; |
|
return condition; |
|
}).join('\n'); |
|
|
|
wildcardBlocks.push(`function __ncc_wildcard$${wildcardBlockIndex} (arg) {\n${optionConditions}\n}`); |
|
return `__ncc_wildcard$${wildcardBlockIndex}(${wildcardParam})`; |
|
} |
On Windows, wildcardPath uses \ as separators. In the example above:
wildcardPath = "C:\\SOME\\PATH\\node_modules\\knex\\lib\\dialects\\*\\index.js";
wildcardPrefix = "C:\\SOME\\PATH\\node_modules\\knex\\lib\\dialects\\";
wildcardSuffix = "\\index.js";
The options returned by glob.sync, however, are in POSIX format.
options = [
"C:/SOME/PATH/node_modules/knex/lib/dialects/better-sqlite3/index.js",
"C:/SOME/PATH/node_modules/knex/lib/dialects/cockroachdb/index.js",
"C:/SOME/PATH/node_modules/knex/lib/dialects/mssql/index.js",
// ...
];
As the result, file.lastIndexOf(wildcardSuffix) will always be -1, and file.substring(...) is just the prefix (but in POSIX format), which is obviously not right.
Also, the glob implementation asks for / regardless of POSIX or Windows, and passing Windows style wildcardPrefix + '**' + wildcardSuffix + endPattern could be considered invalid.
Proposed Fix
We normalize dir and wildcardPath to POSIX style, and use path.posix.relative instead of path.relative.
I implemented this very simple fix in this PR: #153
I'd like some code review to make sure I haven't messed up.
Bug Description
On Windows, generateWildcardRequire can generate invalid conditions due to inconsistent handling of path separators (
/vs\).There's an active issue about this bug here: vercel/ncc#593. An example of generated buggy code (borrowed from /urbdyn/ncc-bug-1):
Cause
webpack-asset-relocator-loader/src/asset-relocator.js
Lines 286 to 324 in 4cdf816
On Windows,
wildcardPathuses\as separators. In the example above:The options returned by
glob.sync, however, are in POSIX format.As the result,
file.lastIndexOf(wildcardSuffix)will always be-1, andfile.substring(...)is just the prefix (but in POSIX format), which is obviously not right.Also, the glob implementation asks for
/regardless of POSIX or Windows, and passing Windows stylewildcardPrefix + '**' + wildcardSuffix + endPatterncould be considered invalid.Proposed Fix
We normalize
dirandwildcardPathto POSIX style, and usepath.posix.relativeinstead ofpath.relative.I implemented this very simple fix in this PR: #153
I'd like some code review to make sure I haven't messed up.