Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom importer in modern api mode may cause ERR_INVALID_URL_SCHEME error. #1122

Closed
notzheng opened this issue Mar 17, 2023 · 4 comments · Fixed by #1123
Closed

Custom importer in modern api mode may cause ERR_INVALID_URL_SCHEME error. #1122

notzheng opened this issue Mar 17, 2023 · 4 comments · Fixed by #1123

Comments

@notzheng
Copy link
Contributor

Bug report

When passing the following sassOptions (as shown in the SASS documentation) to sass-loader:

const sassOptions = {
  importers: [
    {
      canonicalize(url) {
        if (!url.startsWith('bgcolor:')) return null;
        return new URL(url);
      },
      load(canonicalUrl) {
        return {
          contents: `body {background-color: ${canonicalUrl.pathname}}`,
          syntax: 'scss',
        };
      },
    },
  ],
};

In sass file usage looks like this:

@import 'vars';
// this is import by custom importer
@import 'bgcolor:cornflowerblue';

:root {
  --color-fg: $color-fg;
}

Actual Behavior

when running webpack build, the following error is thrown:

TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file
....
code: 'ERR_INVALID_URL_SCHEME'

Expected Behavior

The above error should not occur, as is the case in legacy mode (as seen in the reproduced repository).

How Do We Reproduce?

Reproduce repo:

https://stackblitz.com/edit/sass-loader-err-invalid-url-scheme?file=package.json

  • Run this command to reproduce.
npm run webpack:modern
  • No error in legacy mode.
npm run webpack:legacy
  • Compile with sass to show loaded urls.
npm run sass

Reason and fix

reason

In legacy mode, the sass.render method would return included file paths as Array<string>. In modern mode, the compile method returns Array<URL> .

view result in reproduce repo.

Thus, the file @import 'bgcolor:cornflowerblue', imported via a custom importer, will be treated as URL("bgcolor:cornflowerblue"), with the protocol as bgcolor:. Then, line 101 uses url.fileURLToPath to normalize the file path, but fileURLToPath throws an ERR_INVALID_URL_SCHEME error if the protocol is not file: (see fileURLToPath source).

sass-loader/src/index.js

Lines 98 to 108 in de29518

// Modern API
if (typeof result.loadedUrls !== "undefined") {
result.loadedUrls.forEach((includedFile) => {
const normalizedIncludedFile = url.fileURLToPath(includedFile);
// Custom `importer` can return only `contents` so includedFile will be relative
if (path.isAbsolute(normalizedIncludedFile)) {
this.addDependency(normalizedIncludedFile);
}
});
}

In legacy mode, line 115 will not throw an error and line 118 will get false, so the error is not encountered.

sass-loader/src/index.js

Lines 110 to 122 in de29518

else if (
typeof result.stats !== "undefined" &&
typeof result.stats.includedFiles !== "undefined"
) {
result.stats.includedFiles.forEach((includedFile) => {
const normalizedIncludedFile = path.normalize(includedFile);
// Custom `importer` can return only `contents` so includedFile will be relative
if (path.isAbsolute(normalizedIncludedFile)) {
this.addDependency(normalizedIncludedFile);
}
});
}

fix

Adding result.loadedUrls.filter(url=>url.protocol === 'file').... to line 100 can be a possible fix to ignore invalid URLs.

Please paste the results of npx webpack-cli info here, and mention other relevant information

Okay, but may be not useful for this issue.

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
  Binaries:
    Node: 16.14.2 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 7.17.0 - /usr/local/bin/npm
  Packages:
    css-loader: ^6.7.3 => 6.7.3 
    sass-loader: ^13.2.0 => 13.2.0 
    style-loader: ^3.3.2 => 3.3.2 
    webpack: ^5.38.1 => 5.76.2 
    webpack-cli: ^4.7.2 => 4.10.0 
@alexander-akait
Copy link
Member

Yeah, modern API is still experiments, do you want to send a PR with fix?

@alexander-akait
Copy link
Member

@notzheng
Copy link
Contributor Author

https://github.com/webpack-contrib/sass-loader/releases/tag/v13.2.1

I apologize for the delayed response. It seems that you have already fixed it. Thank you very much. I also learnt a lot from your PR. Thank you again.

@notzheng
Copy link
Contributor Author

@alexander-akait
I am very sorry for the typo in my original post, which misled you (the protocol property in new URL("file://index.scss") should be file: instead of file).

I truly apologize for that.

I just found out that the fix for this issue, while solving the problem, has caused a new problem - no files are added to the dependencies so the nested imported SCSS files will not be watched. because the array is empty after being filtered.

.filter((url) => url.protocol === "file")

I'm very sorry that my carelessness has caused such a big problem.

I have created a PR here: #1125

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants