UNPKG

8.44 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 var desc = Object.getOwnPropertyDescriptor(m, k);
5 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6 desc = { enumerable: true, get: function() { return m[k]; } };
7 }
8 Object.defineProperty(o, k2, desc);
9}) : (function(o, m, k, k2) {
10 if (k2 === undefined) k2 = k;
11 o[k2] = m[k];
12}));
13var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14 Object.defineProperty(o, "default", { enumerable: true, value: v });
15}) : function(o, v) {
16 o["default"] = v;
17});
18var __importStar = (this && this.__importStar) || function (mod) {
19 if (mod && mod.__esModule) return mod;
20 var result = {};
21 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22 __setModuleDefault(result, mod);
23 return result;
24};
25var __importDefault = (this && this.__importDefault) || function (mod) {
26 return (mod && mod.__esModule) ? mod : { "default": mod };
27};
28Object.defineProperty(exports, "__esModule", { value: true });
29const esbuild_1 = require("esbuild");
30const node_path_1 = require("node:path");
31const node_url_1 = require("node:url");
32const node_worker_threads_1 = require("node:worker_threads");
33const postcss_1 = __importDefault(require("postcss"));
34const cache_1 = require("../utils/cache");
35const log = __importStar(require("../utils/log"));
36const css_resource_plugin_1 = require("./css-resource-plugin");
37const { tailwindConfigPath, projectBasePath, browserslistData, targets, cssUrl, styleIncludePaths, postcssConfiguration, } = node_worker_threads_1.workerData;
38let cacheDirectory = node_worker_threads_1.workerData.cacheDirectory;
39let postCssProcessor;
40const CACHE_KEY_VALUES = [...browserslistData, ...styleIncludePaths, cssUrl].join(':');
41/**
42 * An array of keywords that indicate Tailwind CSS processing is required for a stylesheet.
43 *
44 * Based on https://tailwindcss.com/docs/functions-and-directives
45 */
46const TAILWIND_KEYWORDS = [
47 '@tailwind',
48 '@layer',
49 '@apply',
50 '@config',
51 'theme(',
52 'screen(',
53 '@screen', // Undocumented in version 3, see: https://github.com/tailwindlabs/tailwindcss/discussions/7516.
54];
55async function render({ content, filePath }) {
56 let key;
57 if (cacheDirectory && !content.includes('@import') && !content.includes('@use')) {
58 // No transitive deps, we can cache more aggressively.
59 key = await (0, cache_1.generateKey)(content, CACHE_KEY_VALUES);
60 const result = await (0, cache_1.readCacheEntry)(cacheDirectory, key);
61 if (result) {
62 result.warnings.forEach(msg => log.warn(msg));
63 return result.css;
64 }
65 }
66 // Render pre-processor language (sass, styl, less)
67 let renderedCss = await renderCss(filePath, content);
68 // We cannot cache CSS re-rendering phase, because a transitive dependency via (@import) can case different CSS output.
69 // Example a change in a mixin or SCSS variable.
70 if (!key) {
71 key = await (0, cache_1.generateKey)(renderedCss, CACHE_KEY_VALUES);
72 }
73 if (cacheDirectory) {
74 const cachedResult = await (0, cache_1.readCacheEntry)(cacheDirectory, key);
75 if (cachedResult) {
76 cachedResult.warnings.forEach(msg => log.warn(msg));
77 return cachedResult.css;
78 }
79 }
80 const warnings = [];
81 if (postCssProcessor && (postcssConfiguration || (tailwindConfigPath && hasTailwindKeywords(renderedCss)))) {
82 const result = await postCssProcessor.process(renderedCss, {
83 from: filePath,
84 to: filePath.replace((0, node_path_1.extname)(filePath), '.css'),
85 });
86 warnings.push(...result.warnings().map(w => w.toString()));
87 renderedCss = result.css;
88 }
89 const { outputFiles, warnings: esBuildWarnings, errors: esbuildErrors, } = await (0, esbuild_1.build)({
90 stdin: {
91 contents: renderedCss,
92 loader: 'css',
93 resolveDir: (0, node_path_1.dirname)(filePath),
94 },
95 plugins: [(0, css_resource_plugin_1.createCssResourcePlugin)(cssUrl)],
96 write: false,
97 sourcemap: false,
98 minify: true,
99 bundle: true,
100 absWorkingDir: projectBasePath,
101 target: targets,
102 });
103 const code = outputFiles[0].text;
104 if (esBuildWarnings.length > 0) {
105 warnings.push(...(await (0, esbuild_1.formatMessages)(esBuildWarnings, { kind: 'warning' })));
106 warnings.forEach(msg => log.warn(msg));
107 }
108 if (esbuildErrors.length > 0) {
109 const errors = await (0, esbuild_1.formatMessages)(esBuildWarnings, { kind: 'error' });
110 errors.forEach(msg => log.error(msg));
111 throw new Error(`An error has occuried while processing ${filePath}.`);
112 }
113 if (cacheDirectory) {
114 await (0, cache_1.saveCacheEntry)(cacheDirectory, key, JSON.stringify({
115 css: code,
116 warnings,
117 }));
118 }
119 return code;
120}
121async function renderCss(filePath, css) {
122 const ext = (0, node_path_1.extname)(filePath);
123 switch (ext) {
124 case '.sass':
125 case '.scss': {
126 return (await Promise.resolve().then(() => __importStar(require('sass')))).compileString(css, {
127 url: (0, node_url_1.pathToFileURL)(filePath),
128 syntax: '.sass' === ext ? 'indented' : 'scss',
129 loadPaths: styleIncludePaths,
130 }).css;
131 }
132 case '.less': {
133 const { css: content } = await (await Promise.resolve().then(() => __importStar(require('less')))).default.render(css, {
134 filename: filePath,
135 javascriptEnabled: true,
136 paths: styleIncludePaths,
137 });
138 return content;
139 }
140 case '.css':
141 default:
142 return css;
143 }
144}
145function getTailwindPlugin() {
146 // Attempt to setup Tailwind CSS
147 // Only load Tailwind CSS plugin if configuration file was found.
148 // This acts as a guard to ensure the project actually wants to use Tailwind CSS.
149 // The package may be unknowningly present due to a third-party transitive package dependency.
150 if (tailwindConfigPath) {
151 let tailwindPackagePath;
152 try {
153 tailwindPackagePath = require.resolve('tailwindcss', { paths: [projectBasePath] });
154 }
155 catch {
156 const relativeTailwindConfigPath = (0, node_path_1.relative)(projectBasePath, tailwindConfigPath);
157 log.warn(`Tailwind CSS configuration file found (${relativeTailwindConfigPath})` +
158 ` but the 'tailwindcss' package is not installed.` +
159 ` To enable Tailwind CSS, please install the 'tailwindcss' package.`);
160 }
161 if (tailwindPackagePath) {
162 return require(tailwindPackagePath)({ config: tailwindConfigPath });
163 }
164 }
165}
166async function initialize() {
167 const postCssPlugins = [];
168 if (postcssConfiguration) {
169 for (const [pluginName, pluginOptions] of postcssConfiguration.plugins) {
170 const { default: plugin } = await Promise.resolve(`${pluginName}`).then(s => __importStar(require(s)));
171 if (typeof plugin !== 'function' || plugin.postcss !== true) {
172 throw new Error(`Attempted to load invalid Postcss plugin: "${pluginName}"`);
173 }
174 postCssPlugins.push(plugin(pluginOptions));
175 }
176 }
177 else {
178 const tailwinds = getTailwindPlugin();
179 if (tailwinds) {
180 postCssPlugins.push(tailwinds);
181 cacheDirectory = undefined;
182 }
183 }
184 if (postCssPlugins.length) {
185 postCssProcessor = (0, postcss_1.default)(postCssPlugins);
186 }
187 // Return the render function for use
188 return render;
189}
190/**
191 * Searches the provided contents for keywords that indicate Tailwind is used
192 * within a stylesheet.
193 */
194function hasTailwindKeywords(contents) {
195 // TODO: use better search algorithm for keywords
196 return TAILWIND_KEYWORDS.some(keyword => contents.includes(keyword));
197}
198/**
199 * The default export will be the promise returned by the initialize function.
200 * This is awaited by piscina prior to using the Worker.
201 */
202exports.default = initialize();
203//# sourceMappingURL=stylesheet-processor-worker.js.map
\No newline at end of file