Urthen / case-sensitive-paths-webpack-plugin

Enforces case sensitive paths in Webpack requires.
MIT License
428 stars 45 forks source link

Passing paths with null bytes to webpack's cache breaks the build #54

Closed airhorns closed 3 years ago

airhorns commented 3 years ago

I get this error when trying to build my (sizable) webpack project in the production with this plugin active:

yarn run v1.22.10
$ rm -rf packages/web/dist/* && NODE_ENV=production yarn workspace web webpack
$ /Users/airhorns/Code/gadget/node_modules/.bin/webpack
(node:13837) [DEP_WEBPACK_COMPILATION_NORMAL_MODULE_LOADER_HOOK] DeprecationWarning: Compilation.hooks.normalModuleLoader was moved to NormalModule.getCompilationHooks(compilation).loader
(Use `node --trace-deprecation ...` to show where the warning was created)
internal/fs/utils.js:618
    throw err;
    ^

TypeError [ERR_INVALID_ARG_VALUE]: The argument 'path' must be a string or Uint8Array without null bytes. Received '/Users/airhorns/Code/gadget/node_modules/es5-ext/string/\x00#/contains'
    at Object.readdir (fs.js:956:10)
    at go$readdir (/Users/airhorns/Code/gadget/node_modules/graceful-fs/graceful-fs.js:202:23)
    at Object.readdir (/Users/airhorns/Code/gadget/node_modules/graceful-fs/graceful-fs.js:184:12)
    at CacheBackend.provide (/Users/airhorns/Code/gadget/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:187:18)
    at CaseSensitivePathsPlugin.getFilenamesInDir (/Users/airhorns/Code/gadget/node_modules/case-sensitive-paths-webpack-plugin/index.js:58:6)
    at CaseSensitivePathsPlugin.fileExistsWithCase (/Users/airhorns/Code/gadget/node_modules/case-sensitive-paths-webpack-plugin/index.js:89:8)
    at checkFile (/Users/airhorns/Code/gadget/node_modules/case-sensitive-paths-webpack-plugin/index.js:147:10)
    at /Users/airhorns/Code/gadget/node_modules/case-sensitive-paths-webpack-plugin/index.js:169:7
    at CaseSensitivePathsPlugin.primeCache (/Users/airhorns/Code/gadget/node_modules/case-sensitive-paths-webpack-plugin/index.js:120:5)
    at onAfterResolve (/Users/airhorns/Code/gadget/node_modules/case-sensitive-paths-webpack-plugin/index.js:164:10) {
  code: 'ERR_INVALID_ARG_VALUE'
}
error Command failed with exit code 1.

AFAICT, there really is a null byte (\x00) in the path there. Very strangely, it's in the path of a folder on disk, that as far as I can tell does not have an actual null byte in the pathname. The folder exists just fine:

inspector ~/C/gadget (dependabot/npm_and_yarn/webpack-5.5.1) ➜  ls -lA /Users/airhorns/Code/gadget/node_modules/es5-ext/string/#
total 104
drwxr-xr-x  6 airhorns  staff   192 11 Nov 09:50 @@iterator
-rw-r--r--  1 airhorns  staff  1072 11 Nov 09:49 at.js
-rw-r--r--  1 airhorns  staff   217 11 Nov 09:49 camel-to-hyphen.js
-rw-r--r--  1 airhorns  staff   183 11 Nov 09:49 capitalize.js
-rw-r--r--  1 airhorns  staff   182 11 Nov 09:49 case-insensitive-compare.js
drwxr-xr-x  6 airhorns  staff   192 11 Nov 09:50 code-point-at
drwxr-xr-x  6 airhorns  staff   192 11 Nov 09:50 contains
-rw-r--r--  1 airhorns  staff   399 11 Nov 09:49 count.js
drwxr-xr-x  6 airhorns  staff   192 11 Nov 09:50 ends-with
-rw-r--r--  1 airhorns  staff   224 11 Nov 09:49 hyphen-to-camel.js
-rw-r--r--  1 airhorns  staff   419 11 Nov 09:49 indent.js
-rw-r--r--  1 airhorns  staff   787 11 Nov 09:49 index.js
-rw-r--r--  1 airhorns  staff   196 11 Nov 09:49 last.js
drwxr-xr-x  7 airhorns  staff   224 11 Nov 09:50 normalize
-rw-r--r--  1 airhorns  staff   582 11 Nov 09:49 pad.js
-rw-r--r--  1 airhorns  staff   419 11 Nov 09:49 plain-replace-all.js
-rw-r--r--  1 airhorns  staff   314 11 Nov 09:49 plain-replace.js
drwxr-xr-x  6 airhorns  staff   192 11 Nov 09:50 repeat
drwxr-xr-x  6 airhorns  staff   192 11 Nov 09:50 starts-with
-rw-r--r--  1 airhorns  staff   220 11 Nov 09:49 uncapitalize.js
inspector ~/C/gadget (dependabot/npm_and_yarn/webpack-5.5.1) ➜
ls -lA /Users/airhorns/Code/gadget/node_modules/es5-ext/string/#/contains
total 32
-rw-r--r--  1 airhorns  staff  203 11 Nov 09:49 implement.js
-rw-r--r--  1 airhorns  staff  111 11 Nov 09:49 index.js
-rw-r--r--  1 airhorns  staff  200 11 Nov 09:49 is-implemented.js
-rw-r--r--  1 airhorns  staff  177 11 Nov 09:49 shim.js

And the only thing that seems special about it is that it's got a # in the filename. I tried my best to search for null bytes within dependencies and my code and couldn't find any.

Removing this plugin from my webpack plugins list makes the bundling succeed.

This happens for me on any webpack version greater than 5.0.0-beta.22, including the latest which is 5.5.1. I am not sure what changed in 5.0.0-beta.23 that started complaining about the null bytes.

lbnelson commented 3 years ago

Also experiencing this with webpack 5.2.0 and case-sensitive-paths-webpack-plugin 2.3.0.

Urthen commented 3 years ago

@lbnelson Are you also using the es5-ext package?

This seems an oddball edge case, I'm not doing anything particularly weird with strings, but I can look into it.

burnnat commented 3 years ago

I did some investigation, it looks like the null byte is intentionally added by Webpack when parsing the resource location (see here):

enhanced-resolve will try to resolve requests containing # as path and as fragment, so it will automatically figure out if ./some#thing means .../some.js#thing or .../some#thing.js. When a # is resolved as path it will be escaped in the result. Here: .../some\0#thing.js

Seems like "\0#" should be replaced back to "#" in onAfterResolve to clean up the path, similar to the way "?" is stripped out already.

lbnelson commented 3 years ago

Apologies for the delayed reply. @Urthen I am not using es5-ext and it does not appear to be a dependency of any of my dependencies either. Here is my full dependency list if that's helpful:

"dependencies": {
    "@azure/ms-rest-js": "^2.0.4",
    "@fluentui/font-icons-mdl2": "^8.0.0-beta.0",
    "@fluentui/react": "^7.115.4",
    "@fluentui/react-cards": "^1.0.0-beta.0",
    "@fluentui/react-hooks": "^8.0.0-beta.0",
    "@fluentui/theme": "^1.7.0",
    "@microsoft/applicationinsights-react-js": "^2.1.1",
    "@microsoft/applicationinsights-web": "^2.1.1",
    "@microsoft/signalr": "^3.1.3",
    "@typescript-eslint/eslint-plugin": "^2.10.0",
    "@typescript-eslint/parser": "^2.10.0",
    "@uifabric/fluent-theme": "^7.1.93",
    "@uifabric/react-cards": "^0.109.93",
    "axios": "^0.19.0",
    "case-sensitive-paths-webpack-plugin": "^2.3.0",
    "classnames": "^2.2.6",
    "core-js": "^3.7.0",
    "css-loader": "3.4.2",
    "dompurify": "^2.0.7",
    "dotenv": "8.2.0",
    "eslint-loader": "3.0.3",
    "eslint-plugin-flowtype": "4.6.0",
    "eslint-plugin-import": "2.20.1",
    "eslint-plugin-jsx-a11y": "6.2.3",
    "eslint-plugin-react": "7.19.0",
    "eslint-plugin-react-hooks": "^1.6.1",
    "identity-obj-proxy": "3.0.0",
    "jest-environment-jsdom-fourteen": "1.0.1",
    "jest-resolve": "24.9.0",
    "jest-watch-typeahead": "0.4.2",
    "js-file-download": "^0.4.1",
    "moment": "^2.24.0",
    "msal": "1.3.1",
    "optimize-css-assets-webpack-plugin": "5.0.3",
    "path-to-regexp": "^6.2.0",
    "postcss-flexbugs-fixes": "4.1.0",
    "postcss-loader": "3.0.0",
    "postcss-normalize": "8.0.1",
    "postcss-preset-env": "6.7.0",
    "postcss-safe-parser": "4.0.1",
    "query-string": "6.8.2",
    "react": "^16.8.6",
    "react-datetime": "^2.16.3",
    "react-dom": "^16.8.6",
    "react-feature-flags": "^1.0.0",
    "react-redux": "^7.1.0",
    "react-responsive": "^8.1.0",
    "react-router": "^5.1.2",
    "react-router-dom": "^5.1.2",
    "react-router-hashlink": "^0.6.0",
    "react-router-redux": "^4.0.8",
    "react-truncate": "^2.4.0",
    "redux-thunk": "^2.3.0",
    "reselect": "^4.0.0",
    "resolve": "1.15.0",
    "rimraf": "^2.6.3",
    "swagger-ui-react": "^3.26.0",
    "terser-webpack-plugin": "2.3.8",
    "use-debounce": "^3.4.3",
    "uuid": "^3.3.2",
    "webpack-dev-server": "^3.11.0",
  },
  "devDependencies": {
    "@babel/core": "^7.12.7",
    "@babel/plugin-transform-react-jsx": "^7.12.7",
    "@babel/plugin-transform-runtime": "^7.12.1",
    "@babel/preset-env": "^7.12.7",
    "@babel/preset-react": "^7.12.7",
    "@babel/preset-typescript": "^7.12.7",
    "@babel/runtime": "^7.12.5",
    "@svgr/webpack": "^5.4.0",
    "@types/dompurify": "^2.0.2",
    "@types/es6-promise": "^3.3.0",
    "@types/jest": "^26.0.19",
    "@types/react": "^16.8.25",
    "@types/react-dom": "^16.8.5",
    "@types/react-redux": "^7.1.1",
    "@types/react-router-dom": "^5.1.3",
    "@types/react-truncate": "^2.3.3",
    "babel-eslint": "10.1.0",
    "babel-jest": "^24.9.0",
    "babel-loader": "^8.1.0",
    "babel-plugin-add-module-exports": "^1.0.4",
    "babel-plugin-module-resolver": "^4.0.0",
    "babel-plugin-named-asset-import": "^0.3.7",
    "cross-env": "^5.2.0",
    "css-loader": "3.2.0",
    "dart-sass": "^1.25.0",
    "dotenv": "^8.2.0",
    "dotenv-expand": "^5.1.0",
    "eslint": "^7.14.0",
    "eslint-config-react-app": "^5.2.1",
    "eslint-webpack-plugin": "^2.4.0",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^5.0.0-beta.4",
    "jest": "^26.6.3",
    "mini-css-extract-plugin": "^1.3.2",
    "patch-package": "^6.2.2",
    "react-app-polyfill": "^2.0.0",
    "react-dev-utils": "^11.0.1",
    "redux": "^4.0.4",
    "redux-logger": "^3.0.6",
    "resolve-url-loader": "^3.1.2",
    "run-script-os": "^1.1.1",
    "sass": "^1.29.0",
    "sass-loader": "^10.1.0",
    "source-map-explorer": "^2.5.1",
    "style-loader": "^2.0.0",
    "ts-jest": "^26.4.4",
    "ts-loader": "^8.0.11",
    "ts-node": "^9.1.1",
    "tsconfig-paths-webpack-plugin": "^3.3.0",
    "tslint": "^5.18.0",
    "tslint-eslint-rules": "^5.4.0",
    "typescript": "^3.9.5",
    "typescript-tslint-plugin": "^0.5.4",
    "uglifyjs-webpack-plugin": "^2.2.0",
    "url-loader": "^4.1.1",
    "webpack": "^5.2.0",
    "webpack-bundle-analyzer": "^4.2.0",
    "webpack-cli": "^4.2.0"
  },
gustaff-weldon commented 3 years ago

I'm experiencing the exact same problem with Webpack 5:

TypeError [ERR_INVALID_ARG_VALUE]: The argument 'path' must be a string or Uint8Array without null bytes. Received '/Users/redacted/work/projectX/node_modules/es5-ext/string/\u0000#/contains'

Versions:

"webpack": "^5.23.0",
"case-sensitive-paths-webpack-plugin": "^2.3.0",

es5-next seems to be dependency of dependency:

yarn why v1.22.4
[1/4] 🤔  Why do we have the module "es5-ext"...?
[2/4] 🚚  Initialising dependency graph...
[3/4] 🔍  Finding dependency...
[4/4] 🚡  Calculating file sizes...
=> Found "es5-ext@0.10.53"
info Reasons this module exists
   - "deep-map-keys#es6-weak-map" depends on it
   - Hoisted from "deep-map-keys#es6-weak-map#es5-ext"
   - Hoisted from "deep-map-keys#es6-weak-map#es6-iterator#es5-ext"
   - Hoisted from "deep-map-keys#es6-weak-map#d#es5-ext"
   - Hoisted from "@graphql-codegen#cli#@graphql-tools#url-loader#websocket#es5-ext"
info Disk size without dependencies: "4.15MB"
info Disk size with unique dependencies: "4.42MB"
info Disk size with transitive dependencies: "10.14MB"
info Number of shared dependencies: 4
✨  Done in 1.25s.

This is pretty much preventing me from using this plugin after switching to webpack 5

gustaff-weldon commented 3 years ago

@Urthen I have added a fix in https://github.com/Urthen/case-sensitive-paths-webpack-plugin/pull/58 can you please take a look and ideally release a new version?

Urthen commented 3 years ago

v2.4.0 has been released with your changes, @gustaff-weldon

Anyone who can test this out to make sure it fixes your issue, please do so.

gustaff-weldon commented 3 years ago

Awesome, @Urthen, thank you. I'm using it now in my build obviously, all good. I hope @airhorns or @lbnelson could verify as well :)

Urthen commented 3 years ago

Nothing but a positive response so I'm going to close this for now, if anyone else sees this issue on 2.4.0 or up please reopen an issue.