-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathplugin-node-modules.js
More file actions
137 lines (113 loc) · 4.29 KB
/
Copy pathplugin-node-modules.js
File metadata and controls
137 lines (113 loc) · 4.29 KB
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
/*
*
* Detects and fully resolves requests to node_modules and handles creating an importMap.
*
*/
import { checkResourceExists } from "../../lib/resource-utils.js";
import fs from "node:fs/promises";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import {
getPackageJsonForProject,
getResolvedHrefFromPathnameShortcut,
mergeImportMap,
} from "../../lib/node-modules-utils.js";
import { walkPackageJson, IMPORT_MAP_RESOLVED_PREFIX } from "../../lib/walker-package-ranger.js";
let generatedImportMap;
class NodeModulesResource {
constructor(compilation) {
this.compilation = compilation;
this.extensions = ["js", "mjs"];
this.contentType = "text/javascript";
}
async shouldResolve(url) {
const { pathname } = url;
return pathname.startsWith(IMPORT_MAP_RESOLVED_PREFIX) || pathname.startsWith("/node_modules/");
}
async resolve(url) {
const { projectDirectory } = this.compilation.context;
const { pathname, searchParams } = url;
const fromImportMap = pathname.startsWith(IMPORT_MAP_RESOLVED_PREFIX);
const resolvedHref = fromImportMap
? pathname.replace(IMPORT_MAP_RESOLVED_PREFIX, "file://")
: getResolvedHrefFromPathnameShortcut(pathname, projectDirectory);
const params = searchParams.size > 0 ? `?${searchParams.toString()}` : "";
return new Request(`${resolvedHref}${params}`);
}
async shouldServe(url) {
const { href, protocol, pathname } = url;
return (
protocol === "file:" &&
pathname.indexOf("/node_modules/") >= 0 &&
(await checkResourceExists(new URL(href)))
);
}
async serve(url, request) {
const body = await fs.readFile(url, "utf-8");
const contentType = request.headers.get("content-type") ?? this.contentType;
return new Response(body, {
headers: new Headers({
"Content-Type": contentType,
}),
});
}
async shouldIntercept(url, request, response) {
return response.headers.get("Content-Type")?.indexOf("text/html") >= 0;
}
async intercept(url, request, response) {
const { context, config } = this.compilation;
const { importMaps } = config.polyfills;
const importMapShimScript = importMaps
? '<script defer src="/node_modules/es-module-shims/dist/es-module-shims.js"></script>'
: "";
let body = await response.text();
const hasHead = body.match(/<head>(.*)<\/head>/s);
if (importMaps && hasHead && hasHead.length > 0) {
const contents = hasHead[0].replace(/type="module"/g, 'type="module-shim"');
body = body.replace(/<head>(.*)<\/head>/s, contents.replace(/\$/g, "$$$")); // https://github.com/ProjectEvergreen/greenwood/issues/656);
}
const userPackageJson = await getPackageJsonForProject(context);
// if there are dependencies and we haven't generated the importMap already
// walk the project's package.json for all its direct and transitive dependencies
if (!generatedImportMap && Object.keys(userPackageJson.dependencies || []).length > 0) {
console.log("Generating import map from project dependencies...");
const { importMap, diagnostics } = await walkPackageJson(userPackageJson);
if (diagnostics.size > 0) {
console.log("****************************************************************************");
diagnostics.forEach((value) => {
console.warn(`- ${value}\n`);
});
console.log(
"\n>>> Some issue were detected, learn more about these warnings at https://greenwoodjs.dev/docs/introduction/web-standards/#import-maps",
);
console.log("****************************************************************************");
}
generatedImportMap = Object.fromEntries(importMap);
} else {
generatedImportMap = generatedImportMap || {};
}
body = mergeImportMap(body, generatedImportMap, importMaps);
body = body.replace(
"<head>",
`
<head>
${importMapShimScript}
`,
);
return new Response(body);
}
}
const greenwoodPluginNodeModules = [
{
type: "resource",
name: "plugin-node-modules:resource",
provider: (compilation) => new NodeModulesResource(compilation),
},
{
type: "rollup",
name: "plugin-node-modules:rollup",
provider: () => {
return [nodeResolve()];
},
},
];
export { greenwoodPluginNodeModules };