1 | "use strict";
|
---|
2 | /**
|
---|
3 | * @license
|
---|
4 | * Copyright Google LLC All Rights Reserved.
|
---|
5 | *
|
---|
6 | * Use of this source code is governed by an MIT-style license that can be
|
---|
7 | * found in the LICENSE file at https://angular.io/license
|
---|
8 | */
|
---|
9 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
---|
10 | if (k2 === undefined) k2 = k;
|
---|
11 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
---|
12 | }) : (function(o, m, k, k2) {
|
---|
13 | if (k2 === undefined) k2 = k;
|
---|
14 | o[k2] = m[k];
|
---|
15 | }));
|
---|
16 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
---|
17 | Object.defineProperty(o, "default", { enumerable: true, value: v });
|
---|
18 | }) : function(o, v) {
|
---|
19 | o["default"] = v;
|
---|
20 | });
|
---|
21 | var __importStar = (this && this.__importStar) || function (mod) {
|
---|
22 | if (mod && mod.__esModule) return mod;
|
---|
23 | var result = {};
|
---|
24 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
---|
25 | __setModuleDefault(result, mod);
|
---|
26 | return result;
|
---|
27 | };
|
---|
28 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
29 | exports.getStylesConfig = void 0;
|
---|
30 | const fs = __importStar(require("fs"));
|
---|
31 | const path = __importStar(require("path"));
|
---|
32 | const sass_service_1 = require("../../sass/sass-service");
|
---|
33 | const build_browser_features_1 = require("../../utils/build-browser-features");
|
---|
34 | const environment_options_1 = require("../../utils/environment-options");
|
---|
35 | const plugins_1 = require("../plugins");
|
---|
36 | const esbuild_executor_1 = require("../plugins/esbuild-executor");
|
---|
37 | const helpers_1 = require("../utils/helpers");
|
---|
38 | function resolveGlobalStyles(styleEntrypoints, root, preserveSymlinks) {
|
---|
39 | const entryPoints = {};
|
---|
40 | const noInjectNames = [];
|
---|
41 | const paths = [];
|
---|
42 | if (styleEntrypoints.length === 0) {
|
---|
43 | return { entryPoints, noInjectNames, paths };
|
---|
44 | }
|
---|
45 | for (const style of helpers_1.normalizeExtraEntryPoints(styleEntrypoints, 'styles')) {
|
---|
46 | let resolvedPath = path.resolve(root, style.input);
|
---|
47 | if (!fs.existsSync(resolvedPath)) {
|
---|
48 | try {
|
---|
49 | resolvedPath = require.resolve(style.input, { paths: [root] });
|
---|
50 | }
|
---|
51 | catch { }
|
---|
52 | }
|
---|
53 | if (!preserveSymlinks) {
|
---|
54 | resolvedPath = fs.realpathSync(resolvedPath);
|
---|
55 | }
|
---|
56 | // Add style entry points.
|
---|
57 | if (entryPoints[style.bundleName]) {
|
---|
58 | entryPoints[style.bundleName].push(resolvedPath);
|
---|
59 | }
|
---|
60 | else {
|
---|
61 | entryPoints[style.bundleName] = [resolvedPath];
|
---|
62 | }
|
---|
63 | // Add non injected styles to the list.
|
---|
64 | if (!style.inject) {
|
---|
65 | noInjectNames.push(style.bundleName);
|
---|
66 | }
|
---|
67 | // Add global css paths.
|
---|
68 | paths.push(resolvedPath);
|
---|
69 | }
|
---|
70 | return { entryPoints, noInjectNames, paths };
|
---|
71 | }
|
---|
72 | // eslint-disable-next-line max-lines-per-function
|
---|
73 | function getStylesConfig(wco) {
|
---|
74 | var _a, _b, _c;
|
---|
75 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
---|
76 | const postcssImports = require('postcss-import');
|
---|
77 | const postcssPresetEnv = require('postcss-preset-env');
|
---|
78 | const { root, buildOptions } = wco;
|
---|
79 | const extraPlugins = [];
|
---|
80 | extraPlugins.push(new plugins_1.AnyComponentStyleBudgetChecker(buildOptions.budgets));
|
---|
81 | const cssSourceMap = buildOptions.sourceMap.styles;
|
---|
82 | // Determine hashing format.
|
---|
83 | const hashFormat = helpers_1.getOutputHashFormat(buildOptions.outputHashing);
|
---|
84 | // use includePaths from appConfig
|
---|
85 | const includePaths = (_c = (_b = (_a = buildOptions.stylePreprocessorOptions) === null || _a === void 0 ? void 0 : _a.includePaths) === null || _b === void 0 ? void 0 : _b.map((p) => path.resolve(root, p))) !== null && _c !== void 0 ? _c : [];
|
---|
86 | // Process global styles.
|
---|
87 | const { entryPoints, noInjectNames, paths: globalStylePaths, } = resolveGlobalStyles(buildOptions.styles, root, !!buildOptions.preserveSymlinks);
|
---|
88 | if (noInjectNames.length > 0) {
|
---|
89 | // Add plugin to remove hashes from lazy styles.
|
---|
90 | extraPlugins.push(new plugins_1.RemoveHashPlugin({ chunkNames: noInjectNames, hashFormat }));
|
---|
91 | }
|
---|
92 | if (globalStylePaths.some((p) => p.endsWith('.styl'))) {
|
---|
93 | wco.logger.warn('Stylus usage is deprecated and will be removed in a future major version. ' +
|
---|
94 | 'To opt-out of the deprecated behaviour, please migrate to another stylesheet language.');
|
---|
95 | }
|
---|
96 | let sassImplementation;
|
---|
97 | try {
|
---|
98 | sassImplementation = require('node-sass');
|
---|
99 | wco.logger.warn(`'node-sass' usage is deprecated and will be removed in a future major version. ` +
|
---|
100 | `To opt-out of the deprecated behaviour and start using 'sass' uninstall 'node-sass'.`);
|
---|
101 | }
|
---|
102 | catch {
|
---|
103 | sassImplementation = new sass_service_1.SassWorkerImplementation();
|
---|
104 | extraPlugins.push({
|
---|
105 | apply(compiler) {
|
---|
106 | compiler.hooks.shutdown.tap('sass-worker', () => {
|
---|
107 | sassImplementation === null || sassImplementation === void 0 ? void 0 : sassImplementation.close();
|
---|
108 | });
|
---|
109 | },
|
---|
110 | });
|
---|
111 | }
|
---|
112 | const assetNameTemplate = helpers_1.assetNameTemplateFactory(hashFormat);
|
---|
113 | const extraPostcssPlugins = [];
|
---|
114 | // Attempt to setup Tailwind CSS
|
---|
115 | // A configuration file can exist in the project or workspace root
|
---|
116 | const tailwindConfigFile = 'tailwind.config.js';
|
---|
117 | let tailwindConfigPath;
|
---|
118 | for (const basePath of [wco.projectRoot, wco.root]) {
|
---|
119 | const fullPath = path.join(basePath, tailwindConfigFile);
|
---|
120 | if (fs.existsSync(fullPath)) {
|
---|
121 | tailwindConfigPath = fullPath;
|
---|
122 | break;
|
---|
123 | }
|
---|
124 | }
|
---|
125 | // Only load Tailwind CSS plugin if configuration file was found.
|
---|
126 | // This acts as a guard to ensure the project actually wants to use Tailwind CSS.
|
---|
127 | // The package may be unknowningly present due to a third-party transitive package dependency.
|
---|
128 | if (tailwindConfigPath) {
|
---|
129 | let tailwindPackagePath;
|
---|
130 | try {
|
---|
131 | tailwindPackagePath = require.resolve('tailwindcss', { paths: [wco.root] });
|
---|
132 | }
|
---|
133 | catch {
|
---|
134 | const relativeTailwindConfigPath = path.relative(wco.root, tailwindConfigPath);
|
---|
135 | wco.logger.warn(`Tailwind CSS configuration file found (${relativeTailwindConfigPath})` +
|
---|
136 | ` but the 'tailwindcss' package is not installed.` +
|
---|
137 | ` To enable Tailwind CSS, please install the 'tailwindcss' package.`);
|
---|
138 | }
|
---|
139 | if (tailwindPackagePath) {
|
---|
140 | if (process.env['TAILWIND_MODE'] === undefined) {
|
---|
141 | process.env['TAILWIND_MODE'] = buildOptions.watch ? 'watch' : 'build';
|
---|
142 | }
|
---|
143 | extraPostcssPlugins.push(require(tailwindPackagePath)({ config: tailwindConfigPath }));
|
---|
144 | }
|
---|
145 | }
|
---|
146 | const { supportedBrowsers } = new build_browser_features_1.BuildBrowserFeatures(wco.projectRoot);
|
---|
147 | const postcssPresetEnvPlugin = postcssPresetEnv({
|
---|
148 | browsers: supportedBrowsers,
|
---|
149 | autoprefixer: true,
|
---|
150 | stage: 3,
|
---|
151 | });
|
---|
152 | const postcssOptionsCreator = (inlineSourcemaps, extracted) => {
|
---|
153 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
---|
154 | const optionGenerator = (loader) => ({
|
---|
155 | map: inlineSourcemaps
|
---|
156 | ? {
|
---|
157 | inline: true,
|
---|
158 | annotation: false,
|
---|
159 | }
|
---|
160 | : undefined,
|
---|
161 | plugins: [
|
---|
162 | postcssImports({
|
---|
163 | resolve: (url) => (url.startsWith('~') ? url.substr(1) : url),
|
---|
164 | load: (filename) => {
|
---|
165 | return new Promise((resolve, reject) => {
|
---|
166 | loader.fs.readFile(filename, (err, data) => {
|
---|
167 | if (err) {
|
---|
168 | reject(err);
|
---|
169 | return;
|
---|
170 | }
|
---|
171 | const content = data.toString();
|
---|
172 | resolve(content);
|
---|
173 | });
|
---|
174 | });
|
---|
175 | },
|
---|
176 | }),
|
---|
177 | plugins_1.PostcssCliResources({
|
---|
178 | baseHref: buildOptions.baseHref,
|
---|
179 | deployUrl: buildOptions.deployUrl,
|
---|
180 | resourcesOutputPath: buildOptions.resourcesOutputPath,
|
---|
181 | loader,
|
---|
182 | filename: assetNameTemplate,
|
---|
183 | emitFile: buildOptions.platform !== 'server',
|
---|
184 | extracted,
|
---|
185 | }),
|
---|
186 | ...extraPostcssPlugins,
|
---|
187 | postcssPresetEnvPlugin,
|
---|
188 | ],
|
---|
189 | });
|
---|
190 | // postcss-loader fails when trying to determine configuration files for data URIs
|
---|
191 | optionGenerator.config = false;
|
---|
192 | return optionGenerator;
|
---|
193 | };
|
---|
194 | // load component css as raw strings
|
---|
195 | const componentsSourceMap = !!(cssSourceMap &&
|
---|
196 | // Never use component css sourcemap when style optimizations are on.
|
---|
197 | // It will just increase bundle size without offering good debug experience.
|
---|
198 | !buildOptions.optimization.styles.minify &&
|
---|
199 | // Inline all sourcemap types except hidden ones, which are the same as no sourcemaps
|
---|
200 | // for component css.
|
---|
201 | !buildOptions.sourceMap.hidden);
|
---|
202 | if (buildOptions.extractCss) {
|
---|
203 | // extract global css from js files into own css file.
|
---|
204 | extraPlugins.push(new MiniCssExtractPlugin({ filename: `[name]${hashFormat.extract}.css` }));
|
---|
205 | if (!buildOptions.hmr) {
|
---|
206 | // don't remove `.js` files for `.css` when we are using HMR these contain HMR accept codes.
|
---|
207 | // suppress empty .js files in css only entry points.
|
---|
208 | extraPlugins.push(new plugins_1.SuppressExtractedTextChunksWebpackPlugin());
|
---|
209 | }
|
---|
210 | }
|
---|
211 | const postCss = require('postcss');
|
---|
212 | const postCssLoaderPath = require.resolve('postcss-loader');
|
---|
213 | const componentStyleLoaders = [
|
---|
214 | {
|
---|
215 | loader: postCssLoaderPath,
|
---|
216 | options: {
|
---|
217 | implementation: postCss,
|
---|
218 | postcssOptions: postcssOptionsCreator(componentsSourceMap, false),
|
---|
219 | },
|
---|
220 | },
|
---|
221 | ];
|
---|
222 | const globalStyleLoaders = [
|
---|
223 | buildOptions.extractCss
|
---|
224 | ? {
|
---|
225 | loader: MiniCssExtractPlugin.loader,
|
---|
226 | }
|
---|
227 | : require.resolve('style-loader'),
|
---|
228 | {
|
---|
229 | loader: require.resolve('css-loader'),
|
---|
230 | options: {
|
---|
231 | url: false,
|
---|
232 | sourceMap: !!cssSourceMap,
|
---|
233 | },
|
---|
234 | },
|
---|
235 | {
|
---|
236 | loader: postCssLoaderPath,
|
---|
237 | options: {
|
---|
238 | implementation: postCss,
|
---|
239 | postcssOptions: postcssOptionsCreator(false, buildOptions.extractCss),
|
---|
240 | sourceMap: !!cssSourceMap,
|
---|
241 | },
|
---|
242 | },
|
---|
243 | ];
|
---|
244 | const extraMinimizers = [];
|
---|
245 | if (buildOptions.optimization.styles.minify) {
|
---|
246 | const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
---|
247 | const esbuild = new esbuild_executor_1.EsbuildExecutor();
|
---|
248 | const cssnanoOptions = {
|
---|
249 | preset: [
|
---|
250 | 'default',
|
---|
251 | {
|
---|
252 | // Disable SVG optimizations, as this can cause optimizations which are not compatible in all browsers.
|
---|
253 | svgo: false,
|
---|
254 | // Disable `calc` optimizations, due to several issues. #16910, #16875, #17890
|
---|
255 | calc: false,
|
---|
256 | // Disable CSS rules sorted due to several issues #20693, https://github.com/ionic-team/ionic-framework/issues/23266 and https://github.com/cssnano/cssnano/issues/1054
|
---|
257 | cssDeclarationSorter: false,
|
---|
258 | // Workaround for Critters as it doesn't work when `@media all {}` is minified to `@media {}`.
|
---|
259 | // TODO: Remove once they move to postcss.
|
---|
260 | minifyParams: !buildOptions.optimization.styles.inlineCritical,
|
---|
261 | },
|
---|
262 | ],
|
---|
263 | };
|
---|
264 | const globalBundlesRegExp = new RegExp(`^(${Object.keys(entryPoints).join('|')})(\.[0-9a-f]{20})?.css$`);
|
---|
265 | const target = transformSupportedBrowsersToTargets(supportedBrowsers);
|
---|
266 | extraMinimizers.push(
|
---|
267 | // Component styles use esbuild which is faster and generates smaller files on average.
|
---|
268 | // esbuild does not yet support style sourcemaps but component style sourcemaps are not
|
---|
269 | // supported by the CLI when style minify is enabled.
|
---|
270 | new CssMinimizerPlugin({
|
---|
271 | // Component styles retain their original file name
|
---|
272 | test: /\.(?:css|scss|sass|less|styl)$/,
|
---|
273 | exclude: globalBundlesRegExp,
|
---|
274 | parallel: false,
|
---|
275 | minify: async (data) => {
|
---|
276 | const [[sourcefile, input]] = Object.entries(data);
|
---|
277 | const { code, warnings } = await esbuild.transform(input, {
|
---|
278 | loader: 'css',
|
---|
279 | minify: true,
|
---|
280 | sourcefile,
|
---|
281 | target,
|
---|
282 | });
|
---|
283 | return {
|
---|
284 | code,
|
---|
285 | warnings: warnings.length > 0
|
---|
286 | ? await esbuild.formatMessages(warnings, { kind: 'warning' })
|
---|
287 | : [],
|
---|
288 | };
|
---|
289 | },
|
---|
290 | }),
|
---|
291 | // Global styles use cssnano since sourcemap support is required even when minify
|
---|
292 | // is enabled. Once esbuild supports style sourcemaps this can be changed.
|
---|
293 | // esbuild stylesheet source map support issue: https://github.com/evanw/esbuild/issues/519
|
---|
294 | new CssMinimizerPlugin({
|
---|
295 | test: /\.css$/,
|
---|
296 | include: globalBundlesRegExp,
|
---|
297 | parallel: environment_options_1.maxWorkers,
|
---|
298 | minify: [CssMinimizerPlugin.cssnanoMinify],
|
---|
299 | minimizerOptions: cssnanoOptions,
|
---|
300 | }));
|
---|
301 | }
|
---|
302 | const styleLanguages = [
|
---|
303 | {
|
---|
304 | extensions: ['css'],
|
---|
305 | use: [],
|
---|
306 | },
|
---|
307 | {
|
---|
308 | extensions: ['scss'],
|
---|
309 | use: [
|
---|
310 | {
|
---|
311 | loader: require.resolve('resolve-url-loader'),
|
---|
312 | options: {
|
---|
313 | sourceMap: cssSourceMap,
|
---|
314 | },
|
---|
315 | },
|
---|
316 | {
|
---|
317 | loader: require.resolve('sass-loader'),
|
---|
318 | options: {
|
---|
319 | implementation: sassImplementation,
|
---|
320 | sourceMap: true,
|
---|
321 | sassOptions: {
|
---|
322 | // Prevent use of `fibers` package as it no longer works in newer Node.js versions
|
---|
323 | fiber: false,
|
---|
324 | // bootstrap-sass requires a minimum precision of 8
|
---|
325 | precision: 8,
|
---|
326 | includePaths,
|
---|
327 | // Use expanded as otherwise sass will remove comments that are needed for autoprefixer
|
---|
328 | // Ex: /* autoprefixer grid: autoplace */
|
---|
329 | // See: https://github.com/webpack-contrib/sass-loader/blob/45ad0be17264ceada5f0b4fb87e9357abe85c4ff/src/getSassOptions.js#L68-L70
|
---|
330 | outputStyle: 'expanded',
|
---|
331 | // Silences compiler warnings from 3rd party stylesheets
|
---|
332 | quietDeps: !buildOptions.verbose,
|
---|
333 | verbose: buildOptions.verbose,
|
---|
334 | },
|
---|
335 | },
|
---|
336 | },
|
---|
337 | ],
|
---|
338 | },
|
---|
339 | {
|
---|
340 | extensions: ['sass'],
|
---|
341 | use: [
|
---|
342 | {
|
---|
343 | loader: require.resolve('resolve-url-loader'),
|
---|
344 | options: {
|
---|
345 | sourceMap: cssSourceMap,
|
---|
346 | },
|
---|
347 | },
|
---|
348 | {
|
---|
349 | loader: require.resolve('sass-loader'),
|
---|
350 | options: {
|
---|
351 | implementation: sassImplementation,
|
---|
352 | sourceMap: true,
|
---|
353 | sassOptions: {
|
---|
354 | // Prevent use of `fibers` package as it no longer works in newer Node.js versions
|
---|
355 | fiber: false,
|
---|
356 | indentedSyntax: true,
|
---|
357 | // bootstrap-sass requires a minimum precision of 8
|
---|
358 | precision: 8,
|
---|
359 | includePaths,
|
---|
360 | // Use expanded as otherwise sass will remove comments that are needed for autoprefixer
|
---|
361 | // Ex: /* autoprefixer grid: autoplace */
|
---|
362 | // See: https://github.com/webpack-contrib/sass-loader/blob/45ad0be17264ceada5f0b4fb87e9357abe85c4ff/src/getSassOptions.js#L68-L70
|
---|
363 | outputStyle: 'expanded',
|
---|
364 | // Silences compiler warnings from 3rd party stylesheets
|
---|
365 | quietDeps: !buildOptions.verbose,
|
---|
366 | verbose: buildOptions.verbose,
|
---|
367 | },
|
---|
368 | },
|
---|
369 | },
|
---|
370 | ],
|
---|
371 | },
|
---|
372 | {
|
---|
373 | extensions: ['less'],
|
---|
374 | use: [
|
---|
375 | {
|
---|
376 | loader: require.resolve('less-loader'),
|
---|
377 | options: {
|
---|
378 | implementation: require('less'),
|
---|
379 | sourceMap: cssSourceMap,
|
---|
380 | lessOptions: {
|
---|
381 | javascriptEnabled: true,
|
---|
382 | paths: includePaths,
|
---|
383 | },
|
---|
384 | },
|
---|
385 | },
|
---|
386 | ],
|
---|
387 | },
|
---|
388 | {
|
---|
389 | extensions: ['styl'],
|
---|
390 | use: [
|
---|
391 | {
|
---|
392 | loader: require.resolve('stylus-loader'),
|
---|
393 | options: {
|
---|
394 | sourceMap: cssSourceMap,
|
---|
395 | stylusOptions: {
|
---|
396 | compress: false,
|
---|
397 | sourceMap: { comment: false },
|
---|
398 | paths: includePaths,
|
---|
399 | },
|
---|
400 | },
|
---|
401 | },
|
---|
402 | ],
|
---|
403 | },
|
---|
404 | ];
|
---|
405 | return {
|
---|
406 | entry: entryPoints,
|
---|
407 | module: {
|
---|
408 | rules: styleLanguages.map(({ extensions, use }) => ({
|
---|
409 | test: new RegExp(`\\.(?:${extensions.join('|')})$`, 'i'),
|
---|
410 | rules: [
|
---|
411 | // Setup processing rules for global and component styles
|
---|
412 | {
|
---|
413 | oneOf: [
|
---|
414 | // Component styles are all styles except defined global styles
|
---|
415 | {
|
---|
416 | exclude: globalStylePaths,
|
---|
417 | use: componentStyleLoaders,
|
---|
418 | type: 'asset/source',
|
---|
419 | },
|
---|
420 | // Global styles are only defined global styles
|
---|
421 | {
|
---|
422 | include: globalStylePaths,
|
---|
423 | use: globalStyleLoaders,
|
---|
424 | },
|
---|
425 | ],
|
---|
426 | },
|
---|
427 | { use },
|
---|
428 | ],
|
---|
429 | })),
|
---|
430 | },
|
---|
431 | optimization: {
|
---|
432 | minimizer: extraMinimizers,
|
---|
433 | },
|
---|
434 | plugins: extraPlugins,
|
---|
435 | };
|
---|
436 | }
|
---|
437 | exports.getStylesConfig = getStylesConfig;
|
---|
438 | function transformSupportedBrowsersToTargets(supportedBrowsers) {
|
---|
439 | const transformed = [];
|
---|
440 | // https://esbuild.github.io/api/#target
|
---|
441 | const esBuildSupportedBrowsers = new Set(['safari', 'firefox', 'edge', 'chrome', 'ios']);
|
---|
442 | for (const browser of supportedBrowsers) {
|
---|
443 | let [browserName, version] = browser.split(' ');
|
---|
444 | // browserslist uses the name `ios_saf` for iOS Safari whereas esbuild uses `ios`
|
---|
445 | if (browserName === 'ios_saf') {
|
---|
446 | browserName = 'ios';
|
---|
447 | // browserslist also uses ranges for iOS Safari versions but only the lowest is required
|
---|
448 | // to perform minimum supported feature checks. esbuild also expects a single version.
|
---|
449 | [version] = version.split('-');
|
---|
450 | }
|
---|
451 | if (browserName === 'ie') {
|
---|
452 | transformed.push('edge12');
|
---|
453 | }
|
---|
454 | else if (esBuildSupportedBrowsers.has(browserName)) {
|
---|
455 | if (browserName === 'safari' && version === 'TP') {
|
---|
456 | // esbuild only supports numeric versions so `TP` is converted to a high number (999) since
|
---|
457 | // a Technology Preview (TP) of Safari is assumed to support all currently known features.
|
---|
458 | version = '999';
|
---|
459 | }
|
---|
460 | transformed.push(browserName + version);
|
---|
461 | }
|
---|
462 | }
|
---|
463 | return transformed.length ? transformed : undefined;
|
---|
464 | }
|
---|