/
index.js
151 lines (121 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
150
151
import Module from "module";
import { pathToFileURL } from "url";
import schema from "./options.json";
const parentModule = module;
function execute(code, loaderContext) {
const module = new Module(loaderContext.resource, parentModule);
// eslint-disable-next-line no-underscore-dangle
module.paths = Module._nodeModulePaths(loaderContext.context);
// Use the path without webpack-specific parts (`resourceQuery` or `resourceFragment`)
module.filename = loaderContext.resourcePath;
// eslint-disable-next-line no-underscore-dangle
module._compile(code, loaderContext.resource);
return module.exports;
}
function processResult(loaderContext, result) {
if (!result || typeof result !== "object" || "code" in result === false) {
loaderContext.callback(
new Error(
`The returned result of module "${loaderContext.resource}" is not an object with a "code" property`,
),
);
return;
}
if (
typeof result.code !== "string" &&
result.code instanceof Buffer === false
) {
loaderContext.callback(
new Error(
`The returned code of module "${loaderContext.resource}" is neither a string nor an instance of Buffer`,
),
);
return;
}
(result.dependencies || []).forEach((dep) =>
loaderContext.addDependency(dep),
);
(result.contextDependencies || []).forEach((dep) =>
loaderContext.addContextDependency(dep),
);
(result.buildDependencies || []).forEach((dep) =>
loaderContext.addBuildDependency(dep),
);
// Defaults to false which is a good default here because we assume that
// results tend to be not cacheable when this loader is necessary
loaderContext.cacheable(Boolean(result.cacheable));
loaderContext.callback(
null,
result.code,
result.sourceMap || null,
result.ast || null,
);
}
export default async function loader(content) {
const options = this.getOptions(schema);
const { executableFile } = options;
const callback = this.async();
let exports;
if (executableFile) {
try {
// eslint-disable-next-line global-require,import/no-dynamic-require
exports = require(executableFile);
} catch (requireError) {
try {
let importESM;
try {
// eslint-disable-next-line no-new-func
importESM = new Function("id", "return import(id);");
} catch (e) {
importESM = null;
}
if (
requireError.code === "ERR_REQUIRE_ESM" &&
pathToFileURL &&
importESM
) {
const urlForConfig = pathToFileURL(executableFile);
exports = await importESM(urlForConfig);
} else {
throw requireError;
}
} catch (error) {
callback(new Error(`Unable to require "${executableFile}": ${error}`));
return;
}
}
} else {
try {
exports = execute(content, this);
} catch (error) {
callback(new Error(`Unable to execute "${this.resource}": ${error}`));
return;
}
}
const func = exports && exports.default ? exports.default : exports;
if (typeof func !== "function") {
callback(
new Error(
`Module "${this.resource}" does not export a function as default`,
),
);
return;
}
let result;
try {
result = func(options, this, content);
} catch (error) {
callback(new Error(`Module "${this.resource}" throw error: ${error}`));
return;
}
if (result && typeof result.then === "function") {
result
.then((res) => processResult(this, res))
.catch((error) => {
callback(new Error(`Module "${this.resource}" throw error: ${error}`));
});
return;
}
// No return necessary because processResult calls this.callback()
processResult(this, result);
}