/
stylesheets.ts
122 lines (114 loc) · 3.56 KB
/
stylesheets.ts
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
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import type { BuildOptions, OutputFile } from 'esbuild';
import * as path from 'path';
import { createCssResourcePlugin } from './css-resource-plugin';
import { bundle } from './esbuild';
import { createSassPlugin } from './sass-plugin';
export interface BundleStylesheetOptions {
workspaceRoot: string;
optimization: boolean;
preserveSymlinks?: boolean;
sourcemap: boolean | 'external' | 'inline';
outputNames?: { bundles?: string; media?: string };
includePaths?: string[];
externalDependencies?: string[];
target: string[];
}
async function bundleStylesheet(
entry: Required<Pick<BuildOptions, 'stdin'> | Pick<BuildOptions, 'entryPoints'>>,
options: BundleStylesheetOptions,
) {
// Execute esbuild
const result = await bundle({
...entry,
absWorkingDir: options.workspaceRoot,
bundle: true,
entryNames: options.outputNames?.bundles,
assetNames: options.outputNames?.media,
logLevel: 'silent',
minify: options.optimization,
sourcemap: options.sourcemap,
outdir: options.workspaceRoot,
write: false,
platform: 'browser',
target: options.target,
preserveSymlinks: options.preserveSymlinks,
external: options.externalDependencies,
conditions: ['style', 'sass'],
mainFields: ['style', 'sass'],
plugins: [
createSassPlugin({ sourcemap: !!options.sourcemap, loadPaths: options.includePaths }),
createCssResourcePlugin(),
],
});
// Extract the result of the bundling from the output files
let contents = '';
let map;
let outputPath;
const resourceFiles: OutputFile[] = [];
if (result.outputFiles) {
for (const outputFile of result.outputFiles) {
outputFile.path = path.relative(options.workspaceRoot, outputFile.path);
const filename = path.basename(outputFile.path);
if (filename.endsWith('.css')) {
outputPath = outputFile.path;
contents = outputFile.text;
} else if (filename.endsWith('.css.map')) {
map = outputFile.text;
} else {
// The output files could also contain resources (images/fonts/etc.) that were referenced
resourceFiles.push(outputFile);
}
}
}
return {
errors: result.errors,
warnings: result.warnings,
contents,
map,
path: outputPath,
resourceFiles,
};
}
/**
* Bundle a stylesheet that exists as a file on the filesystem.
*
* @param filename The path to the file to bundle.
* @param options The stylesheet bundling options to use.
* @returns The bundle result object.
*/
export async function bundleStylesheetFile(filename: string, options: BundleStylesheetOptions) {
return bundleStylesheet({ entryPoints: [filename] }, options);
}
/**
* Bundle stylesheet text data from a string.
*
* @param data The string content of a stylesheet to bundle.
* @param dataOptions The options to use to resolve references and name output of the stylesheet data.
* @param bundleOptions The stylesheet bundling options to use.
* @returns The bundle result object.
*/
export async function bundleStylesheetText(
data: string,
dataOptions: { resolvePath: string; virtualName?: string },
bundleOptions: BundleStylesheetOptions,
) {
const result = bundleStylesheet(
{
stdin: {
contents: data,
sourcefile: dataOptions.virtualName,
resolveDir: dataOptions.resolvePath,
loader: 'css',
},
},
bundleOptions,
);
return result;
}