Skip to content

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

@notzheng

Description

@notzheng

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).

https://github.com/webpack-contrib/sass-loader/blob/de29518c568b37ca63f703b3cb8717f9fe12091d/src/index.js#L98-L108

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

https://github.com/webpack-contrib/sass-loader/blob/de29518c568b37ca63f703b3cb8717f9fe12091d/src/index.js#L110-L122

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 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions