-
-
Notifications
You must be signed in to change notification settings - Fork 431
/
Copy pathindex.js
149 lines (126 loc) · 3.72 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import url from "url";
import path from "path";
import schema from "./options.json";
import {
getSassImplementation,
getSassOptions,
getWebpackImporter,
getModernWebpackImporter,
getCompileFn,
normalizeSourceMap,
errorFactory,
} from "./utils";
/**
* The sass-loader makes node-sass and dart-sass available to webpack modules.
*
* @this {object}
* @param {string} content
*/
async function loader(content) {
const options = this.getOptions(schema);
const callback = this.async();
let implementation;
try {
implementation = getSassImplementation(this, options.implementation);
} catch (error) {
callback(error);
return;
}
const useSourceMap =
typeof options.sourceMap === "boolean" ? options.sourceMap : this.sourceMap;
// Use `legacy` for `node-sass` and `modern` for `dart-sass` and `sass-embedded`
const apiType =
typeof implementation.compileStringAsync === "undefined"
? "legacy"
: typeof options.api === "undefined"
? "modern"
: options.api;
const sassOptions = await getSassOptions(
this,
options,
content,
implementation,
useSourceMap,
apiType,
);
const shouldUseWebpackImporter =
typeof options.webpackImporter === "boolean"
? options.webpackImporter
: true;
if (shouldUseWebpackImporter) {
const isModernAPI = apiType === "modern" || apiType === "modern-compiler";
if (!isModernAPI) {
const { includePaths } = sassOptions;
sassOptions.importer.push(
getWebpackImporter(this, implementation, includePaths),
);
} else {
sassOptions.importers.push(
// No need to pass `loadPaths`, because modern API handle them itself
getModernWebpackImporter(this, implementation, []),
);
}
}
let compile;
try {
compile = getCompileFn(this, implementation, apiType);
} catch (error) {
callback(error);
return;
}
let result;
try {
result = await compile(sassOptions);
} catch (error) {
// There are situations when the `file`/`span.url` property do not exist
// Modern API
if (error.span && typeof error.span.url !== "undefined") {
this.addDependency(url.fileURLToPath(error.span.url));
}
// Legacy API
else if (typeof error.file !== "undefined") {
// `node-sass` returns POSIX paths
this.addDependency(path.normalize(error.file));
}
callback(errorFactory(error));
return;
}
let map =
// Modern API, then legacy API
result.sourceMap
? result.sourceMap
: result.map
? JSON.parse(result.map)
: null;
// Modify source paths only for webpack, otherwise we do nothing
if (map && useSourceMap) {
map = normalizeSourceMap(map, this.rootContext);
}
// Modern API
if (typeof result.loadedUrls !== "undefined") {
result.loadedUrls
.filter((loadedUrl) => loadedUrl.protocol === "file:")
.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);
}
});
}
// Legacy API
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);
}
});
}
callback(null, result.css.toString(), map);
}
export default loader;