|
1 | 1 | "use strict"; |
2 | 2 |
|
3 | 3 | const path = require("path"); |
| 4 | +const utils = require("loader-utils"); |
4 | 5 |
|
5 | | -// libsass uses this precedence when importing files without extension |
6 | | -const extPrecedence = [".scss", ".sass", ".css"]; |
| 6 | +const matchModuleImport = /^~([^\/]+|@[^\/]+[\/][^\/]+)$/g; |
7 | 7 |
|
8 | 8 | /** |
9 | 9 | * When libsass tries to resolve an import, it uses a special algorithm. |
10 | 10 | * Since the sass-loader uses webpack to resolve the modules, we need to simulate that algorithm. This function |
11 | | - * returns an array of import paths to try. |
| 11 | + * returns an array of import paths to try. The first entry in the array is always the original url |
| 12 | + * to enable straight-forward webpack.config aliases. |
12 | 13 | * |
13 | | - * @param {string} request |
| 14 | + * @param {string} url |
14 | 15 | * @returns {Array<string>} |
15 | 16 | */ |
16 | | -function importsToResolve(request) { |
| 17 | +function importsToResolve(url) { |
| 18 | + const request = utils.urlToRequest(url); |
| 19 | + // Keep in mind: ext can also be something like '.datepicker' when the true extension is omitted and the filename contains a dot. |
| 20 | + // @see https://github.com/webpack-contrib/sass-loader/issues/167 |
| 21 | + const ext = path.extname(request); |
| 22 | + |
| 23 | + if (matchModuleImport.test(url)) { |
| 24 | + return [url, request]; |
| 25 | + } |
| 26 | + |
17 | 27 | // libsass' import algorithm works like this: |
18 | | - // In case there is no file extension... |
19 | | - // - Prefer modules starting with '_'. |
20 | | - // - File extension precedence: .scss, .sass, .css. |
| 28 | + |
21 | 29 | // In case there is a file extension... |
22 | 30 | // - If the file is a CSS-file, do not include it all, but just link it via @import url(). |
23 | 31 | // - The exact file name must match (no auto-resolving of '_'-modules). |
| 32 | + if (ext === ".css") { |
| 33 | + return []; |
| 34 | + } |
| 35 | + if (ext === ".scss" || ext === ".sass") { |
| 36 | + return [url, request]; |
| 37 | + } |
24 | 38 |
|
25 | | - // Keep in mind: ext can also be something like '.datepicker' when the true extension is omitted and the filename contains a dot. |
26 | | - // @see https://github.com/webpack-contrib/sass-loader/issues/167 |
27 | | - const ext = path.extname(request); |
| 39 | + // In case there is no file extension... |
| 40 | + // - Prefer modules starting with '_'. |
| 41 | + // - File extension precedence: .scss, .sass, .css. |
28 | 42 | const basename = path.basename(request); |
29 | | - const dirname = path.dirname(request); |
30 | | - const startsWithUnderscore = basename.charAt(0) === "_"; |
31 | | - const hasCssExt = ext === ".css"; |
32 | | - const hasSassExt = ext === ".scss" || ext === ".sass"; |
33 | | - |
34 | | - // a module import is an identifier like 'bootstrap-sass' |
35 | | - // We also need to check for dirname since it might also be a deep import like 'bootstrap-sass/something' |
36 | | - let isModuleImport = request.charAt(0) !== "." && dirname === "."; |
37 | | - |
38 | | - if (dirname.charAt(0) === "@") { |
39 | | - // Check whether it is a deep import from scoped npm package |
40 | | - // (i.e. @pkg/foo/file), if so, process import as file import; |
41 | | - // otherwise, if we import from root npm scoped package (i.e. @pkg/foo) |
42 | | - // process import as a module import. |
43 | | - isModuleImport = !(dirname.indexOf("/") > -1); |
| 43 | + |
| 44 | + if (basename.charAt(0) === "_") { |
| 45 | + return [ |
| 46 | + url, |
| 47 | + `${ request }.scss`, `${ request }.sass`, `${ request }.css` |
| 48 | + ]; |
44 | 49 | } |
45 | 50 |
|
46 | | - return (isModuleImport && [request]) || // Do not modify module imports |
47 | | - (hasCssExt && []) || // Do not import css files |
48 | | - (hasSassExt && [request]) || // Do not modify imports with explicit extensions |
49 | | - (startsWithUnderscore ? [] : extPrecedence) // Do not add underscore imports if there is already an underscore |
50 | | - .map(ext => "_" + basename + ext) |
51 | | - .concat( |
52 | | - extPrecedence.map(ext => basename + ext) |
53 | | - ).map( |
54 | | - file => dirname + "/" + file // No path.sep required here, because imports inside SASS are usually with / |
55 | | - ); |
| 51 | + const dirname = path.dirname(request); |
| 52 | + |
| 53 | + return [ |
| 54 | + url, |
| 55 | + `${ dirname }/_${ basename }.scss`, `${ dirname }/_${ basename }.sass`, `${ dirname }/_${ basename }.css`, |
| 56 | + `${ request }.scss`, `${ request }.sass`, `${ request }.css` |
| 57 | + ]; |
56 | 58 | } |
57 | 59 |
|
58 | 60 | module.exports = importsToResolve; |
0 commit comments