tailwindcss 0.0.0-insiders.c5ca373 → 0.0.0-insiders.c5eef09
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/lib/cli/build/index.js +5 -1
- package/lib/cli/build/plugin.js +84 -34
- package/lib/cli/build/watching.js +77 -12
- package/lib/cli/index.js +231 -10
- package/lib/cli/init/index.js +2 -2
- package/lib/cli.js +4 -226
- package/lib/corePlugins.js +344 -31
- package/lib/css/preflight.css +2 -0
- package/lib/featureFlags.js +12 -10
- package/lib/index.js +4 -46
- package/lib/lib/collapseAdjacentRules.js +2 -2
- package/lib/lib/collapseDuplicateDeclarations.js +2 -2
- package/lib/lib/content.js +24 -9
- package/lib/lib/defaultExtractor.js +15 -5
- package/lib/lib/detectNesting.js +7 -1
- package/lib/lib/evaluateTailwindFunctions.js +4 -4
- package/lib/lib/expandApplyAtRules.js +36 -17
- package/lib/lib/expandTailwindAtRules.js +36 -10
- package/lib/lib/findAtConfigPath.js +7 -7
- package/lib/lib/generateRules.js +147 -66
- package/lib/lib/offsets.js +90 -2
- package/lib/lib/remap-bitfield.js +87 -0
- package/lib/lib/resolveDefaultsAtRules.js +4 -4
- package/lib/lib/setupContextUtils.js +286 -79
- package/lib/lib/setupTrackingContext.js +25 -4
- package/lib/lib/sharedState.js +21 -1
- package/lib/oxide/cli/build/deps.js +81 -0
- package/lib/oxide/cli/build/index.js +47 -0
- package/lib/oxide/cli/build/plugin.js +364 -0
- package/lib/oxide/cli/build/utils.js +77 -0
- package/lib/oxide/cli/build/watching.js +177 -0
- package/lib/oxide/cli/help/index.js +70 -0
- package/lib/oxide/cli/index.js +220 -0
- package/lib/oxide/cli/init/index.js +35 -0
- package/lib/oxide/cli.js +5 -0
- package/lib/oxide/postcss-plugin.js +2 -0
- package/lib/plugin.js +98 -0
- package/lib/postcss-plugins/nesting/plugin.js +2 -2
- package/lib/util/buildMediaQuery.js +5 -2
- package/lib/util/cloneNodes.js +2 -2
- package/lib/util/color.js +4 -4
- package/lib/util/createUtilityPlugin.js +2 -2
- package/lib/util/dataTypes.js +29 -2
- package/lib/util/defaults.js +4 -4
- package/lib/util/escapeClassName.js +3 -3
- package/lib/util/formatVariantSelector.js +173 -107
- package/lib/util/getAllConfigs.js +2 -2
- package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +2 -2
- package/lib/util/nameClass.js +3 -0
- package/lib/util/negateValue.js +2 -2
- package/lib/util/normalizeConfig.js +36 -22
- package/lib/util/normalizeScreens.js +100 -3
- package/lib/util/pluginUtils.js +107 -22
- package/lib/util/prefixSelector.js +22 -8
- package/lib/util/resolveConfig.js +11 -16
- package/oxide-node-api-shim/index.js +21 -0
- package/oxide-node-api-shim/package.json +5 -0
- package/package.json +38 -24
- package/peers/index.js +790 -765
- package/resolveConfig.d.ts +11 -2
- package/scripts/release-channel.js +18 -0
- package/scripts/release-notes.js +21 -0
- package/scripts/swap-engines.js +40 -0
- package/src/cli/build/index.js +6 -2
- package/src/cli/build/plugin.js +82 -15
- package/src/cli/build/watching.js +105 -12
- package/src/cli/index.js +234 -3
- package/src/cli.js +4 -220
- package/src/corePlugins.js +283 -23
- package/src/css/preflight.css +2 -0
- package/src/featureFlags.js +2 -0
- package/src/index.js +4 -46
- package/src/lib/content.js +21 -12
- package/src/lib/defaultExtractor.js +12 -3
- package/src/lib/detectNesting.js +9 -1
- package/src/lib/expandApplyAtRules.js +35 -15
- package/src/lib/expandTailwindAtRules.js +37 -6
- package/src/lib/findAtConfigPath.js +4 -6
- package/src/lib/generateRules.js +152 -55
- package/src/lib/offsets.js +110 -3
- package/src/lib/remap-bitfield.js +82 -0
- package/src/lib/setupContextUtils.js +315 -60
- package/src/lib/setupTrackingContext.js +31 -6
- package/src/lib/sharedState.js +19 -0
- package/src/oxide/cli/build/deps.ts +91 -0
- package/src/oxide/cli/build/index.ts +47 -0
- package/src/oxide/cli/build/plugin.ts +436 -0
- package/src/oxide/cli/build/utils.ts +74 -0
- package/src/oxide/cli/build/watching.ts +225 -0
- package/src/oxide/cli/help/index.ts +69 -0
- package/src/oxide/cli/index.ts +212 -0
- package/src/oxide/cli/init/index.ts +32 -0
- package/src/oxide/cli.ts +1 -0
- package/src/oxide/postcss-plugin.ts +1 -0
- package/src/plugin.js +107 -0
- package/src/util/buildMediaQuery.js +5 -3
- package/src/util/dataTypes.js +33 -4
- package/src/util/formatVariantSelector.js +217 -124
- package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
- package/src/util/nameClass.js +4 -0
- package/src/util/negateValue.js +1 -1
- package/src/util/normalizeConfig.js +18 -0
- package/src/util/normalizeScreens.js +99 -4
- package/src/util/pluginUtils.js +116 -8
- package/src/util/prefixSelector.js +28 -10
- package/src/util/resolveConfig.js +3 -9
- package/stubs/defaultConfig.stub.js +162 -166
- package/types/config.d.ts +37 -10
- package/types/generated/default-theme.d.ts +92 -78
- package/CHANGELOG.md +0 -2269
- package/lib/cli/shared.js +0 -12
- package/scripts/install-integrations.js +0 -27
- package/scripts/rebuildFixtures.js +0 -68
- package/src/cli/shared.js +0 -5
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<a href="https://tailwindcss.com
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
<a href="https://tailwindcss.com" target="_blank">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-dark.svg">
|
|
5
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg">
|
|
6
|
+
<img alt="Tailwind CSS" src="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg" width="350" height="70" style="max-width: 100%;">
|
|
7
|
+
</picture>
|
|
7
8
|
</a>
|
|
8
9
|
</p>
|
|
9
10
|
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
<p align="center">
|
|
16
|
-
<a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/workflow/status/tailwindlabs/tailwindcss/
|
|
17
|
+
<a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/actions/workflow/status/tailwindlabs/tailwindcss/ci-stable.yml?branch=master" alt="Build Status"></a>
|
|
17
18
|
<a href="https://www.npmjs.com/package/tailwindcss"><img src="https://img.shields.io/npm/dt/tailwindcss.svg" alt="Total Downloads"></a>
|
|
18
19
|
<a href="https://github.com/tailwindcss/tailwindcss/releases"><img src="https://img.shields.io/npm/v/tailwindcss.svg" alt="Latest Release"></a>
|
|
19
20
|
<a href="https://github.com/tailwindcss/tailwindcss/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/tailwindcss.svg" alt="License"></a>
|
package/lib/cli/build/index.js
CHANGED
|
@@ -35,7 +35,11 @@ async function build(args, configs) {
|
|
|
35
35
|
let configPath = args["--config"] ? args["--config"] : ((defaultPath)=>_fs.default.existsSync(defaultPath) ? defaultPath : null)(_path.default.resolve(`./${configs.tailwind}`));
|
|
36
36
|
let processor = await (0, _pluginJs.createProcessor)(args, configPath);
|
|
37
37
|
if (shouldWatch) {
|
|
38
|
-
|
|
38
|
+
// Abort the watcher if stdin is closed to avoid zombie processes
|
|
39
|
+
// You can disable this behavior with --watch=always
|
|
40
|
+
if (args["--watch"] !== "always") {
|
|
41
|
+
process.stdin.on("end", ()=>process.exit(0));
|
|
42
|
+
}
|
|
39
43
|
process.stdin.resume();
|
|
40
44
|
await processor.watch();
|
|
41
45
|
} else {
|
package/lib/cli/build/plugin.js
CHANGED
|
@@ -18,13 +18,14 @@ const _options = /*#__PURE__*/ _interopRequireDefault(require("postcss-load-conf
|
|
|
18
18
|
const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("../../processTailwindFeatures"));
|
|
19
19
|
const _deps = require("./deps");
|
|
20
20
|
const _utils = require("./utils");
|
|
21
|
-
const
|
|
21
|
+
const _sharedState = require("../../lib/sharedState");
|
|
22
22
|
const _resolveConfigJs = /*#__PURE__*/ _interopRequireDefault(require("../../../resolveConfig.js"));
|
|
23
23
|
const _getModuleDependenciesJs = /*#__PURE__*/ _interopRequireDefault(require("../../lib/getModuleDependencies.js"));
|
|
24
24
|
const _contentJs = require("../../lib/content.js");
|
|
25
25
|
const _watchingJs = require("./watching.js");
|
|
26
26
|
const _fastGlob = /*#__PURE__*/ _interopRequireDefault(require("fast-glob"));
|
|
27
27
|
const _findAtConfigPathJs = require("../../lib/findAtConfigPath.js");
|
|
28
|
+
const _log = /*#__PURE__*/ _interopRequireDefault(require("../../util/log"));
|
|
28
29
|
function _interopRequireDefault(obj) {
|
|
29
30
|
return obj && obj.__esModule ? obj : {
|
|
30
31
|
default: obj
|
|
@@ -112,8 +113,8 @@ let state = {
|
|
|
112
113
|
contextDependencies: new Set(),
|
|
113
114
|
/** @type {import('../../lib/content.js').ContentPath[]} */ contentPaths: [],
|
|
114
115
|
refreshContentPaths () {
|
|
115
|
-
var
|
|
116
|
-
this.contentPaths = (0, _contentJs.parseCandidateFiles)(this.context, (
|
|
116
|
+
var _this_context;
|
|
117
|
+
this.contentPaths = (0, _contentJs.parseCandidateFiles)(this.context, (_this_context = this.context) === null || _this_context === void 0 ? void 0 : _this_context.tailwindConfig);
|
|
117
118
|
},
|
|
118
119
|
get config () {
|
|
119
120
|
return this.context.tailwindConfig;
|
|
@@ -124,7 +125,7 @@ let state = {
|
|
|
124
125
|
dynamic: this.contentPaths.filter((contentPath)=>contentPath.glob !== undefined).map((contentPath)=>contentPath.pattern)
|
|
125
126
|
};
|
|
126
127
|
},
|
|
127
|
-
loadConfig (configPath) {
|
|
128
|
+
loadConfig (configPath, content) {
|
|
128
129
|
if (this.watcher && configPath) {
|
|
129
130
|
this.refreshConfigDependencies(configPath);
|
|
130
131
|
}
|
|
@@ -135,10 +136,14 @@ let state = {
|
|
|
135
136
|
files: []
|
|
136
137
|
}
|
|
137
138
|
});
|
|
139
|
+
// Override content files if `--content` has been passed explicitly
|
|
140
|
+
if ((content === null || content === void 0 ? void 0 : content.length) > 0) {
|
|
141
|
+
config.content.files = content;
|
|
142
|
+
}
|
|
138
143
|
return config;
|
|
139
144
|
},
|
|
140
145
|
refreshConfigDependencies (configPath) {
|
|
141
|
-
|
|
146
|
+
_sharedState.env.DEBUG && console.time("Module dependencies");
|
|
142
147
|
for (let file of this.configDependencies){
|
|
143
148
|
delete require.cache[require.resolve(file)];
|
|
144
149
|
}
|
|
@@ -148,7 +153,7 @@ let state = {
|
|
|
148
153
|
this.configDependencies.add(dependency);
|
|
149
154
|
}
|
|
150
155
|
}
|
|
151
|
-
|
|
156
|
+
_sharedState.env.DEBUG && console.timeEnd("Module dependencies");
|
|
152
157
|
},
|
|
153
158
|
readContentPaths () {
|
|
154
159
|
let content = [];
|
|
@@ -156,69 +161,86 @@ let state = {
|
|
|
156
161
|
// TODO: When we make the postcss plugin async-capable this can become async
|
|
157
162
|
let files = _fastGlob.default.sync(this.contentPatterns.all);
|
|
158
163
|
for (let file of files){
|
|
159
|
-
|
|
160
|
-
content
|
|
161
|
-
|
|
162
|
-
|
|
164
|
+
if (_sharedState.env.OXIDE) {
|
|
165
|
+
content.push({
|
|
166
|
+
file,
|
|
167
|
+
extension: _path.default.extname(file).slice(1)
|
|
168
|
+
});
|
|
169
|
+
} else {
|
|
170
|
+
content.push({
|
|
171
|
+
content: _fs.default.readFileSync(_path.default.resolve(file), "utf8"),
|
|
172
|
+
extension: _path.default.extname(file).slice(1)
|
|
173
|
+
});
|
|
174
|
+
}
|
|
163
175
|
}
|
|
164
176
|
// Resolve raw content in the tailwind config
|
|
165
177
|
let rawContent = this.config.content.files.filter((file)=>{
|
|
166
178
|
return file !== null && typeof file === "object";
|
|
167
179
|
});
|
|
168
|
-
for (let { raw:
|
|
169
|
-
|
|
170
|
-
content:
|
|
180
|
+
for (let { raw: htmlContent , extension ="html" } of rawContent){
|
|
181
|
+
content.push({
|
|
182
|
+
content: htmlContent,
|
|
171
183
|
extension
|
|
172
184
|
});
|
|
173
185
|
}
|
|
174
186
|
return content;
|
|
175
187
|
},
|
|
176
|
-
getContext ({ createContext , cliConfigPath , root , result }) {
|
|
188
|
+
getContext ({ createContext , cliConfigPath , root , result , content }) {
|
|
177
189
|
if (this.context) {
|
|
178
190
|
this.context.changedContent = this.changedContent.splice(0);
|
|
179
191
|
return this.context;
|
|
180
192
|
}
|
|
181
|
-
|
|
182
|
-
var
|
|
183
|
-
let configPath = (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
let config = this.loadConfig(configPath);
|
|
187
|
-
|
|
188
|
-
|
|
193
|
+
_sharedState.env.DEBUG && console.time("Searching for config");
|
|
194
|
+
var _findAtConfigPath;
|
|
195
|
+
let configPath = (_findAtConfigPath = (0, _findAtConfigPathJs.findAtConfigPath)(root, result)) !== null && _findAtConfigPath !== void 0 ? _findAtConfigPath : cliConfigPath;
|
|
196
|
+
_sharedState.env.DEBUG && console.timeEnd("Searching for config");
|
|
197
|
+
_sharedState.env.DEBUG && console.time("Loading config");
|
|
198
|
+
let config = this.loadConfig(configPath, content);
|
|
199
|
+
_sharedState.env.DEBUG && console.timeEnd("Loading config");
|
|
200
|
+
_sharedState.env.DEBUG && console.time("Creating context");
|
|
189
201
|
this.context = createContext(config, []);
|
|
190
202
|
Object.assign(this.context, {
|
|
191
203
|
userConfigPath: configPath
|
|
192
204
|
});
|
|
193
|
-
|
|
194
|
-
|
|
205
|
+
_sharedState.env.DEBUG && console.timeEnd("Creating context");
|
|
206
|
+
_sharedState.env.DEBUG && console.time("Resolving content paths");
|
|
195
207
|
this.refreshContentPaths();
|
|
196
|
-
|
|
208
|
+
_sharedState.env.DEBUG && console.timeEnd("Resolving content paths");
|
|
197
209
|
if (this.watcher) {
|
|
198
|
-
|
|
210
|
+
_sharedState.env.DEBUG && console.time("Watch new files");
|
|
199
211
|
this.watcher.refreshWatchedFiles();
|
|
200
|
-
|
|
212
|
+
_sharedState.env.DEBUG && console.timeEnd("Watch new files");
|
|
201
213
|
}
|
|
202
|
-
_shared.env.DEBUG && console.time("Reading content files");
|
|
203
214
|
for (let file of this.readContentPaths()){
|
|
204
215
|
this.context.changedContent.push(file);
|
|
205
216
|
}
|
|
206
|
-
_shared.env.DEBUG && console.timeEnd("Reading content files");
|
|
207
217
|
return this.context;
|
|
208
218
|
}
|
|
209
219
|
};
|
|
210
220
|
async function createProcessor(args, cliConfigPath) {
|
|
221
|
+
var _args_content;
|
|
211
222
|
let postcss = (0, _deps.loadPostcss)();
|
|
212
223
|
let input = args["--input"];
|
|
213
224
|
let output = args["--output"];
|
|
214
225
|
let includePostCss = args["--postcss"];
|
|
215
226
|
let customPostCssPath = typeof args["--postcss"] === "string" ? args["--postcss"] : undefined;
|
|
216
227
|
let [beforePlugins, afterPlugins, postcssOptions] = includePostCss ? await loadPostCssPlugins(customPostCssPath) : loadBuiltinPostcssPlugins();
|
|
228
|
+
if (args["--purge"]) {
|
|
229
|
+
_log.default.warn("purge-flag-deprecated", [
|
|
230
|
+
"The `--purge` flag has been deprecated.",
|
|
231
|
+
"Please use `--content` instead."
|
|
232
|
+
]);
|
|
233
|
+
if (!args["--content"]) {
|
|
234
|
+
args["--content"] = args["--purge"];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
var _args_content_split;
|
|
238
|
+
let content = (_args_content_split = (_args_content = args["--content"]) === null || _args_content === void 0 ? void 0 : _args_content.split(/(?<!{[^}]+),/)) !== null && _args_content_split !== void 0 ? _args_content_split : [];
|
|
217
239
|
let tailwindPlugin = ()=>{
|
|
218
240
|
return {
|
|
219
241
|
postcssPlugin: "tailwindcss",
|
|
220
242
|
Once (root, { result }) {
|
|
221
|
-
|
|
243
|
+
_sharedState.env.DEBUG && console.time("Compiling CSS");
|
|
222
244
|
(0, _processTailwindFeatures.default)(({ createContext })=>{
|
|
223
245
|
console.error();
|
|
224
246
|
console.error("Rebuilding...");
|
|
@@ -227,11 +249,12 @@ async function createProcessor(args, cliConfigPath) {
|
|
|
227
249
|
createContext,
|
|
228
250
|
cliConfigPath,
|
|
229
251
|
root,
|
|
230
|
-
result
|
|
252
|
+
result,
|
|
253
|
+
content
|
|
231
254
|
});
|
|
232
255
|
};
|
|
233
256
|
})(root, result);
|
|
234
|
-
|
|
257
|
+
_sharedState.env.DEBUG && console.timeEnd("Compiling CSS");
|
|
235
258
|
}
|
|
236
259
|
};
|
|
237
260
|
};
|
|
@@ -265,18 +288,45 @@ async function createProcessor(args, cliConfigPath) {
|
|
|
265
288
|
from: input,
|
|
266
289
|
to: output
|
|
267
290
|
})).then((result)=>{
|
|
291
|
+
if (!state.watcher) {
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
_sharedState.env.DEBUG && console.time("Recording PostCSS dependencies");
|
|
295
|
+
for (let message of result.messages){
|
|
296
|
+
if (message.type === "dependency") {
|
|
297
|
+
state.contextDependencies.add(message.file);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
_sharedState.env.DEBUG && console.timeEnd("Recording PostCSS dependencies");
|
|
301
|
+
// TODO: This needs to be in a different spot
|
|
302
|
+
_sharedState.env.DEBUG && console.time("Watch new files");
|
|
303
|
+
state.watcher.refreshWatchedFiles();
|
|
304
|
+
_sharedState.env.DEBUG && console.timeEnd("Watch new files");
|
|
305
|
+
return result;
|
|
306
|
+
}).then((result)=>{
|
|
268
307
|
if (!output) {
|
|
269
308
|
process.stdout.write(result.css);
|
|
270
309
|
return;
|
|
271
310
|
}
|
|
272
311
|
return Promise.all([
|
|
273
|
-
(0, _utils.outputFile)(
|
|
274
|
-
result.map && (0, _utils.outputFile)(
|
|
312
|
+
(0, _utils.outputFile)(result.opts.to, result.css),
|
|
313
|
+
result.map && (0, _utils.outputFile)(result.opts.to + ".map", result.map.toString())
|
|
275
314
|
]);
|
|
276
315
|
}).then(()=>{
|
|
277
316
|
let end = process.hrtime.bigint();
|
|
278
317
|
console.error();
|
|
279
318
|
console.error("Done in", (end - start) / BigInt(1e6) + "ms.");
|
|
319
|
+
}).then(()=>{}, (err)=>{
|
|
320
|
+
// TODO: If an initial build fails we can't easily pick up any PostCSS dependencies
|
|
321
|
+
// that were collected before the error occurred
|
|
322
|
+
// The result is not stored on the error so we have to store it externally
|
|
323
|
+
// and pull the messages off of it here somehow
|
|
324
|
+
// This results in a less than ideal DX because the watcher will not pick up
|
|
325
|
+
// changes to imported CSS if one of them caused an error during the initial build
|
|
326
|
+
// If you fix it and then save the main CSS file so there's no error
|
|
327
|
+
// The watcher will start watching the imported CSS files and will be
|
|
328
|
+
// resilient to future errors.
|
|
329
|
+
console.error(err);
|
|
280
330
|
});
|
|
281
331
|
}
|
|
282
332
|
/**
|
|
@@ -37,22 +37,70 @@ function createWatcher(args, { state , rebuild }) {
|
|
|
37
37
|
pollInterval: pollInterval
|
|
38
38
|
} : false
|
|
39
39
|
});
|
|
40
|
+
// A queue of rebuilds, file reads, etc… to run
|
|
40
41
|
let chain = Promise.resolve();
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
/**
|
|
43
|
+
* A list of files that have been changed since the last rebuild
|
|
44
|
+
*
|
|
45
|
+
* @type {{file: string, content: () => Promise<string>, extension: string}[]}
|
|
46
|
+
*/ let changedContent = [];
|
|
47
|
+
/**
|
|
48
|
+
* A list of files for which a rebuild has already been queued.
|
|
49
|
+
* This is used to prevent duplicate rebuilds when multiple events are fired for the same file.
|
|
50
|
+
* The rebuilt file is cleared from this list when it's associated rebuild has _started_
|
|
51
|
+
* This is because if the file is changed during a rebuild it won't trigger a new rebuild which it should
|
|
52
|
+
**/ let pendingRebuilds = new Set();
|
|
53
|
+
let _timer;
|
|
54
|
+
let _reject;
|
|
55
|
+
/**
|
|
56
|
+
* Rebuilds the changed files and resolves when the rebuild is
|
|
57
|
+
* complete regardless of whether it was successful or not
|
|
58
|
+
*/ async function rebuildAndContinue() {
|
|
59
|
+
let changes = changedContent.splice(0);
|
|
60
|
+
// There are no changes to rebuild so we can just do nothing
|
|
61
|
+
if (changes.length === 0) {
|
|
62
|
+
return Promise.resolve();
|
|
63
|
+
}
|
|
64
|
+
// Clear all pending rebuilds for the about-to-be-built files
|
|
65
|
+
changes.forEach((change)=>pendingRebuilds.delete(change.file));
|
|
66
|
+
// Resolve the promise even when the rebuild fails
|
|
67
|
+
return rebuild(changes).then(()=>{}, ()=>{});
|
|
68
|
+
}
|
|
43
69
|
/**
|
|
44
70
|
*
|
|
45
71
|
* @param {*} file
|
|
46
72
|
* @param {(() => Promise<string>) | null} content
|
|
47
|
-
|
|
73
|
+
* @param {boolean} skipPendingCheck
|
|
74
|
+
* @returns {Promise<void>}
|
|
75
|
+
*/ function recordChangedFile(file, content = null, skipPendingCheck = false) {
|
|
48
76
|
file = _path.default.resolve(file);
|
|
49
|
-
|
|
77
|
+
// Applications like Vim/Neovim fire both rename and change events in succession for atomic writes
|
|
78
|
+
// In that case rebuild has already been queued by rename, so can be skipped in change
|
|
79
|
+
if (pendingRebuilds.has(file) && !skipPendingCheck) {
|
|
80
|
+
return Promise.resolve();
|
|
81
|
+
}
|
|
82
|
+
// Mark that a rebuild of this file is going to happen
|
|
83
|
+
// It MUST happen synchronously before the rebuild is queued for this to be effective
|
|
84
|
+
pendingRebuilds.add(file);
|
|
50
85
|
changedContent.push({
|
|
51
86
|
file,
|
|
52
|
-
content,
|
|
87
|
+
content: content !== null && content !== void 0 ? content : ()=>_fs.default.promises.readFile(file, "utf8"),
|
|
53
88
|
extension: _path.default.extname(file).slice(1)
|
|
54
89
|
});
|
|
55
|
-
|
|
90
|
+
if (_timer) {
|
|
91
|
+
clearTimeout(_timer);
|
|
92
|
+
_reject();
|
|
93
|
+
}
|
|
94
|
+
// If a rebuild is already in progress we don't want to start another one until the 10ms timer has expired
|
|
95
|
+
chain = chain.then(()=>new Promise((resolve, reject)=>{
|
|
96
|
+
_timer = setTimeout(resolve, 10);
|
|
97
|
+
_reject = reject;
|
|
98
|
+
}));
|
|
99
|
+
// Resolves once this file has been rebuilt (or the rebuild for this file has failed)
|
|
100
|
+
// This queues as many rebuilds as there are changed files
|
|
101
|
+
// But those rebuilds happen after some delay
|
|
102
|
+
// And will immediately resolve if there are no changes
|
|
103
|
+
chain = chain.then(rebuildAndContinue, rebuildAndContinue);
|
|
56
104
|
return chain;
|
|
57
105
|
}
|
|
58
106
|
watcher.on("change", (file)=>recordChangedFile(file));
|
|
@@ -91,15 +139,32 @@ function createWatcher(args, { state , rebuild }) {
|
|
|
91
139
|
if (pendingRebuilds.has(filePath)) {
|
|
92
140
|
return;
|
|
93
141
|
}
|
|
142
|
+
// We'll go ahead and add the file to the pending rebuilds list here
|
|
143
|
+
// It'll be removed when the rebuild starts unless the read fails
|
|
144
|
+
// which will be taken care of as well
|
|
94
145
|
pendingRebuilds.add(filePath);
|
|
95
|
-
|
|
96
|
-
let content;
|
|
146
|
+
async function enqueue() {
|
|
97
147
|
try {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
148
|
+
// We need to read the file as early as possible outside of the chain
|
|
149
|
+
// because it may be gone by the time we get to it. doing the read
|
|
150
|
+
// immediately increases the chance that the file is still there
|
|
151
|
+
let content = await (0, _utilsJs.readFileWithRetries)(_path.default.resolve(filePath));
|
|
152
|
+
if (content === undefined) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
// This will push the rebuild onto the chain
|
|
156
|
+
// We MUST skip the rebuild check here otherwise the rebuild will never happen on Linux
|
|
157
|
+
// This is because the order of events and timing is different on Linux
|
|
158
|
+
// @ts-ignore: TypeScript isn't picking up that content is a string here
|
|
159
|
+
await recordChangedFile(filePath, ()=>content, true);
|
|
160
|
+
} catch {
|
|
161
|
+
// If reading the file fails, it's was probably a deleted temporary file
|
|
162
|
+
// So we can ignore it and no rebuild is needed
|
|
101
163
|
}
|
|
102
|
-
|
|
164
|
+
}
|
|
165
|
+
enqueue().then(()=>{
|
|
166
|
+
// If the file read fails we still need to make sure the file isn't stuck in the pending rebuilds list
|
|
167
|
+
pendingRebuilds.delete(filePath);
|
|
103
168
|
});
|
|
104
169
|
});
|
|
105
170
|
return {
|
package/lib/cli/index.js
CHANGED
|
@@ -1,18 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
"use strict";
|
|
2
3
|
Object.defineProperty(exports, "__esModule", {
|
|
3
4
|
value: true
|
|
4
5
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
const _path = /*#__PURE__*/ _interopRequireDefault(require("path"));
|
|
7
|
+
const _arg = /*#__PURE__*/ _interopRequireDefault(require("arg"));
|
|
8
|
+
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs"));
|
|
9
|
+
const _build = require("./build");
|
|
10
|
+
const _help = require("./help");
|
|
11
|
+
const _init = require("./init");
|
|
12
|
+
function _interopRequireDefault(obj) {
|
|
13
|
+
return obj && obj.__esModule ? obj : {
|
|
14
|
+
default: obj
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function isESM() {
|
|
18
|
+
const pkgPath = _path.default.resolve("./package.json");
|
|
19
|
+
try {
|
|
20
|
+
let pkg = JSON.parse(_fs.default.readFileSync(pkgPath, "utf8"));
|
|
21
|
+
return pkg.type && pkg.type === "module";
|
|
22
|
+
} catch (err) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
let configs = isESM() ? {
|
|
27
|
+
tailwind: "tailwind.config.cjs",
|
|
28
|
+
postcss: "postcss.config.cjs"
|
|
29
|
+
} : {
|
|
30
|
+
tailwind: "tailwind.config.js",
|
|
31
|
+
postcss: "postcss.config.js"
|
|
32
|
+
};
|
|
33
|
+
// ---
|
|
34
|
+
function oneOf(...options) {
|
|
35
|
+
return Object.assign((value = true)=>{
|
|
36
|
+
for (let option of options){
|
|
37
|
+
let parsed = option(value);
|
|
38
|
+
if (parsed === value) {
|
|
39
|
+
return parsed;
|
|
14
40
|
}
|
|
41
|
+
}
|
|
42
|
+
throw new Error("...");
|
|
43
|
+
}, {
|
|
44
|
+
manualParsing: true
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
let commands = {
|
|
48
|
+
init: {
|
|
49
|
+
run: _init.init,
|
|
50
|
+
args: {
|
|
51
|
+
"--full": {
|
|
52
|
+
type: Boolean,
|
|
53
|
+
description: `Initialize a full \`${configs.tailwind}\` file`
|
|
54
|
+
},
|
|
55
|
+
"--postcss": {
|
|
56
|
+
type: Boolean,
|
|
57
|
+
description: `Initialize a \`${configs.postcss}\` file`
|
|
58
|
+
},
|
|
59
|
+
"-f": "--full",
|
|
60
|
+
"-p": "--postcss"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
build: {
|
|
64
|
+
run: _build.build,
|
|
65
|
+
args: {
|
|
66
|
+
"--input": {
|
|
67
|
+
type: String,
|
|
68
|
+
description: "Input file"
|
|
69
|
+
},
|
|
70
|
+
"--output": {
|
|
71
|
+
type: String,
|
|
72
|
+
description: "Output file"
|
|
73
|
+
},
|
|
74
|
+
"--watch": {
|
|
75
|
+
type: oneOf(String, Boolean),
|
|
76
|
+
description: "Watch for changes and rebuild as needed"
|
|
77
|
+
},
|
|
78
|
+
"--poll": {
|
|
79
|
+
type: Boolean,
|
|
80
|
+
description: "Use polling instead of filesystem events when watching"
|
|
81
|
+
},
|
|
82
|
+
"--content": {
|
|
83
|
+
type: String,
|
|
84
|
+
description: "Content paths to use for removing unused classes"
|
|
85
|
+
},
|
|
86
|
+
"--purge": {
|
|
87
|
+
type: String,
|
|
88
|
+
deprecated: true
|
|
89
|
+
},
|
|
90
|
+
"--postcss": {
|
|
91
|
+
type: oneOf(String, Boolean),
|
|
92
|
+
description: "Load custom PostCSS configuration"
|
|
93
|
+
},
|
|
94
|
+
"--minify": {
|
|
95
|
+
type: Boolean,
|
|
96
|
+
description: "Minify the output"
|
|
97
|
+
},
|
|
98
|
+
"--config": {
|
|
99
|
+
type: String,
|
|
100
|
+
description: "Path to a custom config file"
|
|
101
|
+
},
|
|
102
|
+
"--no-autoprefixer": {
|
|
103
|
+
type: Boolean,
|
|
104
|
+
description: "Disable autoprefixer"
|
|
105
|
+
},
|
|
106
|
+
"-c": "--config",
|
|
107
|
+
"-i": "--input",
|
|
108
|
+
"-o": "--output",
|
|
109
|
+
"-m": "--minify",
|
|
110
|
+
"-w": "--watch",
|
|
111
|
+
"-p": "--poll"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
let sharedFlags = {
|
|
116
|
+
"--help": {
|
|
117
|
+
type: Boolean,
|
|
118
|
+
description: "Display usage information"
|
|
119
|
+
},
|
|
120
|
+
"-h": "--help"
|
|
121
|
+
};
|
|
122
|
+
if (process.stdout.isTTY /* Detect redirecting output to a file */ && (process.argv[2] === undefined || process.argv.slice(2).every((flag)=>sharedFlags[flag] !== undefined))) {
|
|
123
|
+
(0, _help.help)({
|
|
124
|
+
usage: [
|
|
125
|
+
"tailwindcss [--input input.css] [--output output.css] [--watch] [options...]",
|
|
126
|
+
"tailwindcss init [--full] [--postcss] [options...]"
|
|
127
|
+
],
|
|
128
|
+
commands: Object.keys(commands).filter((command)=>command !== "build").map((command)=>`${command} [options]`),
|
|
129
|
+
options: {
|
|
130
|
+
...commands.build.args,
|
|
131
|
+
...sharedFlags
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
let command = ((arg = "")=>arg.startsWith("-") ? undefined : arg)(process.argv[2]) || "build";
|
|
137
|
+
if (commands[command] === undefined) {
|
|
138
|
+
if (_fs.default.existsSync(_path.default.resolve(command))) {
|
|
139
|
+
// TODO: Deprecate this in future versions
|
|
140
|
+
// Check if non-existing command, might be a file.
|
|
141
|
+
command = "build";
|
|
142
|
+
} else {
|
|
143
|
+
(0, _help.help)({
|
|
144
|
+
message: `Invalid command: ${command}`,
|
|
145
|
+
usage: [
|
|
146
|
+
"tailwindcss <command> [options]"
|
|
147
|
+
],
|
|
148
|
+
commands: Object.keys(commands).filter((command)=>command !== "build").map((command)=>`${command} [options]`),
|
|
149
|
+
options: sharedFlags
|
|
150
|
+
});
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Execute command
|
|
155
|
+
let { args: flags , run } = commands[command];
|
|
156
|
+
let args = (()=>{
|
|
157
|
+
try {
|
|
158
|
+
let result = (0, _arg.default)(Object.fromEntries(Object.entries({
|
|
159
|
+
...flags,
|
|
160
|
+
...sharedFlags
|
|
161
|
+
}).filter(([_key, value])=>{
|
|
162
|
+
var _value_type;
|
|
163
|
+
return !(value === null || value === void 0 ? void 0 : (_value_type = value.type) === null || _value_type === void 0 ? void 0 : _value_type.manualParsing);
|
|
164
|
+
}).map(([key, value])=>[
|
|
165
|
+
key,
|
|
166
|
+
typeof value === "object" ? value.type : value
|
|
167
|
+
])), {
|
|
168
|
+
permissive: true
|
|
15
169
|
});
|
|
170
|
+
// Manual parsing of flags to allow for special flags like oneOf(Boolean, String)
|
|
171
|
+
for(let i = result["_"].length - 1; i >= 0; --i){
|
|
172
|
+
let flag = result["_"][i];
|
|
173
|
+
if (!flag.startsWith("-")) continue;
|
|
174
|
+
let [flagName, flagValue] = flag.split("=");
|
|
175
|
+
let handler = flags[flagName];
|
|
176
|
+
// Resolve flagName & handler
|
|
177
|
+
while(typeof handler === "string"){
|
|
178
|
+
flagName = handler;
|
|
179
|
+
handler = flags[handler];
|
|
180
|
+
}
|
|
181
|
+
if (!handler) continue;
|
|
182
|
+
let args = [];
|
|
183
|
+
let offset = i + 1;
|
|
184
|
+
// --flag value syntax was used so we need to pull `value` from `args`
|
|
185
|
+
if (flagValue === undefined) {
|
|
186
|
+
// Parse args for current flag
|
|
187
|
+
while(result["_"][offset] && !result["_"][offset].startsWith("-")){
|
|
188
|
+
args.push(result["_"][offset++]);
|
|
189
|
+
}
|
|
190
|
+
// Cleanup manually parsed flags + args
|
|
191
|
+
result["_"].splice(i, 1 + args.length);
|
|
192
|
+
// No args were provided, use default value defined in handler
|
|
193
|
+
// One arg was provided, use that directly
|
|
194
|
+
// Multiple args were provided so pass them all in an array
|
|
195
|
+
flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
|
|
196
|
+
} else {
|
|
197
|
+
// Remove the whole flag from the args array
|
|
198
|
+
result["_"].splice(i, 1);
|
|
199
|
+
}
|
|
200
|
+
// Set the resolved value in the `result` object
|
|
201
|
+
result[flagName] = handler.type(flagValue, flagName);
|
|
202
|
+
}
|
|
203
|
+
// Ensure that the `command` is always the first argument in the `args`.
|
|
204
|
+
// This is important so that we don't have to check if a default command
|
|
205
|
+
// (build) was used or not from within each plugin.
|
|
206
|
+
//
|
|
207
|
+
// E.g.: tailwindcss input.css -> _: ['build', 'input.css']
|
|
208
|
+
// E.g.: tailwindcss build input.css -> _: ['build', 'input.css']
|
|
209
|
+
if (result["_"][0] !== command) {
|
|
210
|
+
result["_"].unshift(command);
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
213
|
+
} catch (err) {
|
|
214
|
+
if (err.code === "ARG_UNKNOWN_OPTION") {
|
|
215
|
+
(0, _help.help)({
|
|
216
|
+
message: err.message,
|
|
217
|
+
usage: [
|
|
218
|
+
"tailwindcss <command> [options]"
|
|
219
|
+
],
|
|
220
|
+
options: sharedFlags
|
|
221
|
+
});
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
throw err;
|
|
225
|
+
}
|
|
226
|
+
})();
|
|
227
|
+
if (args["--help"]) {
|
|
228
|
+
(0, _help.help)({
|
|
229
|
+
options: {
|
|
230
|
+
...flags,
|
|
231
|
+
...sharedFlags
|
|
232
|
+
},
|
|
233
|
+
usage: [
|
|
234
|
+
`tailwindcss ${command} [options]`
|
|
235
|
+
]
|
|
16
236
|
});
|
|
17
|
-
|
|
237
|
+
process.exit(0);
|
|
18
238
|
}
|
|
239
|
+
run(args, configs);
|
package/lib/cli/init/index.js
CHANGED
|
@@ -16,8 +16,8 @@ function _interopRequireDefault(obj) {
|
|
|
16
16
|
}
|
|
17
17
|
function init(args, configs) {
|
|
18
18
|
let messages = [];
|
|
19
|
-
var
|
|
20
|
-
let tailwindConfigLocation = _path.default.resolve((
|
|
19
|
+
var _args___;
|
|
20
|
+
let tailwindConfigLocation = _path.default.resolve((_args___ = args["_"][1]) !== null && _args___ !== void 0 ? _args___ : `./${configs.tailwind}`);
|
|
21
21
|
if (_fs.default.existsSync(tailwindConfigLocation)) {
|
|
22
22
|
messages.push(`${_path.default.basename(tailwindConfigLocation)} already exists.`);
|
|
23
23
|
} else {
|