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 | import { readFileSync } from "fs"
|
29 | import { dirname, resolve } from "path"
|
30 | import {
|
31 | pathnameToOperatingSystemPath,
|
32 | pathnameIsInside,
|
33 | pathnameToRelativePathname,
|
34 | operatingSystemPathToPathname,
|
35 | } from "@jsenv/operating-system-path"
|
36 | import { writeOrUpdateSourceMappingURL } from "./helpers/source-mapping-url.js"
|
37 |
|
38 | export const bundleToCompilationResult = (
|
39 | { rollupBundle, relativePathAbstractArray },
|
40 | {
|
41 | projectPathname,
|
42 | compileIntoRelativePath,
|
43 | entryRelativePath,
|
44 | sourcemapAssetPath,
|
45 | sourcemapPath = sourcemapAssetPath,
|
46 | },
|
47 | ) => {
|
48 | const sources = []
|
49 | const sourcesContent = []
|
50 | const assets = []
|
51 | const assetsContent = []
|
52 |
|
53 | const output = rollupBundle.output
|
54 | const main = output[0]
|
55 | const mainRollupSourcemap = main.map
|
56 |
|
57 | const mainDependencyMap = rollupSourcemapToDependencyMap({
|
58 | rollupSourcemap: mainRollupSourcemap,
|
59 | projectPathname,
|
60 | compileIntoRelativePath,
|
61 | entryRelativePath,
|
62 | relativePathAbstractArray,
|
63 | })
|
64 |
|
65 | const addDependencyMap = (dependencyMap) => {
|
66 | Object.keys(dependencyMap).forEach((relativePath) => {
|
67 | if (relativePathAbstractArray.includes(relativePath)) return
|
68 | if (sources.includes(relativePath)) return
|
69 |
|
70 | sources.push(relativePath)
|
71 | sourcesContent.push(dependencyMap[relativePath])
|
72 | })
|
73 | }
|
74 |
|
75 |
|
76 | const mainSourceContent = writeOrUpdateSourceMappingURL(main.code, sourcemapPath)
|
77 |
|
78 | assets.push(sourcemapAssetPath.slice(2))
|
79 | const mainSourcemap = {
|
80 | ...mainRollupSourcemap,
|
81 | ...dependencyMapToSourcemapSubset(mainDependencyMap),
|
82 | }
|
83 | assetsContent.push(JSON.stringify(mainSourcemap, null, " "))
|
84 |
|
85 | addDependencyMap(mainDependencyMap)
|
86 |
|
87 | output.slice(1).forEach((chunk) => {
|
88 | const chunkRollupSourcemap = chunk.map
|
89 | const chunkDependencyMap = rollupSourcemapToDependencyMap({
|
90 | rollupSourcemap: chunkRollupSourcemap,
|
91 | projectPathname,
|
92 | compileIntoRelativePath,
|
93 | entryRelativePath,
|
94 | relativePathAbstractArray,
|
95 | })
|
96 |
|
97 |
|
98 | assets.push(chunk.fileName)
|
99 | const chunkSourceContent = writeOrUpdateSourceMappingURL(chunk.code, `./${chunk.fileName}.map`)
|
100 | assetsContent.push(chunkSourceContent)
|
101 |
|
102 | assets.push(`${chunk.fileName}.map`)
|
103 | const chunkSourcemap = {
|
104 | ...chunkRollupSourcemap,
|
105 | ...dependencyMapToSourcemapSubset(chunkDependencyMap),
|
106 | }
|
107 | assetsContent.push(JSON.stringify(chunkSourcemap, null, " "))
|
108 |
|
109 | addDependencyMap(chunkDependencyMap)
|
110 | })
|
111 |
|
112 | return {
|
113 | contentType: "application/javascript",
|
114 | compiledSource: mainSourceContent,
|
115 | sources,
|
116 | sourcesContent,
|
117 | assets,
|
118 | assetsContent,
|
119 | }
|
120 | }
|
121 |
|
122 | const dependencyMapToSourcemapSubset = (dependencyMap) => {
|
123 | const sources = Object.keys(dependencyMap)
|
124 | const sourcesContent = sources.map((source) => {
|
125 |
|
126 |
|
127 | if (source.endsWith(".json")) return `export default ${dependencyMap[source]}`
|
128 | return dependencyMap[source]
|
129 | })
|
130 | return {
|
131 | sources,
|
132 | sourcesContent,
|
133 | }
|
134 | }
|
135 |
|
136 | const rollupSourcemapToDependencyMap = ({
|
137 | rollupSourcemap,
|
138 | projectPathname,
|
139 | compileIntoRelativePath,
|
140 | entryRelativePath,
|
141 | relativePathAbstractArray,
|
142 | }) => {
|
143 | const dependencyMap = {}
|
144 |
|
145 | rollupSourcemap.sources.forEach((sourceRelativeToEntry, index) => {
|
146 | const sourcePath = resolve(
|
147 | dirname(
|
148 | pathnameToOperatingSystemPath(
|
149 | `${projectPathname}${compileIntoRelativePath}${entryRelativePath}`,
|
150 | ),
|
151 | ),
|
152 | sourceRelativeToEntry,
|
153 | )
|
154 | const sourcePathname = operatingSystemPathToPathname(sourcePath)
|
155 |
|
156 | if (!pathnameIsInside(sourcePathname, projectPathname)) {
|
157 | throw createSourceOutsideProjectError({
|
158 | sourcePath,
|
159 | projectPathname,
|
160 | source: sourceRelativeToEntry,
|
161 | file: entryRelativePath,
|
162 | })
|
163 | }
|
164 |
|
165 | const sourceRelativePath = pathnameToRelativePathname(sourcePathname, projectPathname)
|
166 | const isAbstract = relativePathAbstractArray.includes(sourceRelativePath)
|
167 |
|
168 | let dependencyContent
|
169 | const sourcesContent = rollupSourcemap.sourcesContent || []
|
170 | if (index in sourcesContent) {
|
171 |
|
172 |
|
173 | if (isAbstract) {
|
174 | dependencyContent = sourcesContent[index]
|
175 | }
|
176 |
|
177 |
|
178 |
|
179 |
|
180 | else if (sourceRelativePath.endsWith(".json")) {
|
181 | dependencyContent = readSourceContent({
|
182 | projectPathname,
|
183 | sourceRelativePath,
|
184 | entryRelativePath,
|
185 | })
|
186 | } else {
|
187 | dependencyContent = sourcesContent[index]
|
188 | }
|
189 | } else {
|
190 | if (isAbstract) {
|
191 | throw createAbstractSourceMissingError({ sourceRelativePath, entryRelativePath })
|
192 | }
|
193 | dependencyContent = readSourceContent({
|
194 | projectPathname,
|
195 | sourceRelativePath,
|
196 | entryRelativePath,
|
197 | })
|
198 | }
|
199 |
|
200 | dependencyMap[sourceRelativePath] = dependencyContent
|
201 | })
|
202 |
|
203 | return dependencyMap
|
204 | }
|
205 |
|
206 | const readSourceContent = ({ projectPathname, sourceRelativePath, entryRelativePath }) => {
|
207 | const sourcePath = pathnameToOperatingSystemPath(`${projectPathname}${sourceRelativePath}`)
|
208 |
|
209 |
|
210 |
|
211 | try {
|
212 | const buffer = readFileSync(sourcePath)
|
213 | return String(buffer)
|
214 | } catch (e) {
|
215 | if (e && e.code === "ENOENT") {
|
216 | throw createSourceNotFoundError({
|
217 | sourcePath,
|
218 | projectPathname,
|
219 | source: sourceRelativePath,
|
220 | file: entryRelativePath,
|
221 | })
|
222 | }
|
223 | throw e
|
224 | }
|
225 | }
|
226 |
|
227 | const createAbstractSourceMissingError = ({ source, file }) =>
|
228 | new Error(`an abstract file source content is missing.
|
229 | source: ${source}
|
230 | file: ${file}`)
|
231 |
|
232 | const createSourceNotFoundError = ({ sourcePath, projectPathname, source, file }) =>
|
233 | new Error(`a file source cannot be found.
|
234 | source path: ${sourcePath}
|
235 | project path: ${pathnameToOperatingSystemPath(projectPathname)}
|
236 | source: ${source}
|
237 | file: ${file}`)
|
238 |
|
239 | const createSourceOutsideProjectError = ({ sourcePath, projectPathname, source, file }) =>
|
240 | new Error(`a file source is not inside project.
|
241 | source path: ${sourcePath}
|
242 | project path: ${pathnameToOperatingSystemPath(projectPathname)}
|
243 | source: ${source}
|
244 | file: ${file}`)
|