@master/css-cli 2.0.0-rc.69 → 2.0.0-rc.71
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 +44 -10
- package/dist/bin/index.mjs +1 -1
- package/dist/core.mjs +25 -10
- package/dist/scan.mjs +181 -0
- package/package.json +1 -1
- package/dist/commands/extract.mjs +0 -54
- package/dist/commands/render.mjs +0 -64
package/README.md
CHANGED
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
<img alt="NPM Version" src="https://img.shields.io/github/v/release/master-co/css?include_prereleases&color=f6f7f8&label=&style=for-the-badge&logo=github">
|
|
21
21
|
</picture>
|
|
22
22
|
</a>
|
|
23
|
-
<a aria-label="NPM Package" href="https://www.npmjs.com/package/@master/
|
|
23
|
+
<a aria-label="NPM Package" href="https://www.npmjs.com/package/@master/css-cli">
|
|
24
24
|
<picture>
|
|
25
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/dm/@master/
|
|
26
|
-
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/npm/dm/@master/
|
|
27
|
-
<img alt="NPM package ( download / month )" src="https://img.shields.io/npm/dm/@master/
|
|
25
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/dm/@master/css-cli?color=212022&label=%20&logo=npm&style=for-the-badge">
|
|
26
|
+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/npm/dm/@master/css-cli?color=f6f7f8&label=%20&logo=npm&style=for-the-badge">
|
|
27
|
+
<img alt="NPM package ( download / month )" src="https://img.shields.io/npm/dm/@master/css-cli?color=f6f7f8&label=%20&logo=npm&style=for-the-badge">
|
|
28
28
|
</picture>
|
|
29
29
|
</a>
|
|
30
30
|
<a aria-label="Discord Community" href="https://discord.gg/sZNKpAAAw6">
|
|
@@ -41,16 +41,50 @@
|
|
|
41
41
|
<img alt="Follow @mastercorg" src="https://img.shields.io/static/v1?label=%20&message=twitter&color=f6f7f8&logo=twitter&style=for-the-badge">
|
|
42
42
|
</picture>
|
|
43
43
|
</a>
|
|
44
|
-
<a aria-label="Github Actions" href="https://github.com/master-co/css/actions/workflows/release.yml">
|
|
44
|
+
<a aria-label="Github Actions" href="https://github.com/master-co/css/actions/workflows/ci-release.yml">
|
|
45
45
|
<picture>
|
|
46
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/release.yml?branch=rc&label=%20&message=twitter&color=212022&logo=githubactions&style=for-the-badge">
|
|
47
|
-
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
48
|
-
<img alt="Github release actions" src="https://img.shields.io/github/actions/workflow/status/master-co/css/release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
46
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=212022&logo=githubactions&style=for-the-badge">
|
|
47
|
+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
48
|
+
<img alt="Github release actions" src="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
49
49
|
</picture>
|
|
50
50
|
</a>
|
|
51
51
|
</p>
|
|
52
52
|
|
|
53
53
|
</div>
|
|
54
54
|
|
|
55
|
-
##
|
|
56
|
-
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm install -D @master/css-cli
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Run the package binary directly with `npx @master/css-cli`. The package does not expose `mcss` or `mastercss` aliases.
|
|
62
|
+
|
|
63
|
+
## Commands
|
|
64
|
+
|
|
65
|
+
### `npx @master/css-cli [source paths]`
|
|
66
|
+
|
|
67
|
+
Scan source files, detect Master CSS classes, generate CSS rules, and write the generated CSS file.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx @master/css-cli index.html main.js
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
When no source paths are passed, the CLI scans the current project with the default scanner `include` and `exclude` options.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx @master/css-cli
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Options:
|
|
80
|
+
|
|
81
|
+
| Option | Type | Default | Description |
|
|
82
|
+
| --- | --- | --- | --- |
|
|
83
|
+
| `-o, --output <path>` | `string` | `master.css` | Generated CSS output path. |
|
|
84
|
+
| `-v, --verbose <level>` | `number` | `1` | Logging level. Use `0` to silence terminal output. |
|
|
85
|
+
| `-w, --watch` | `boolean` | `false` | Watch files and rebuild continuously. |
|
|
86
|
+
|
|
87
|
+
## Related docs
|
|
88
|
+
|
|
89
|
+
- [Static rendering guide](https://rc.css.master.co/guide/installation)
|
|
90
|
+
- [Scanner package](../scanner)
|
package/dist/bin/index.mjs
CHANGED
package/dist/core.mjs
CHANGED
|
@@ -3,18 +3,33 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { readJSONFileSync } from '@techor/fs';
|
|
4
4
|
import { dirname } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
-
import
|
|
7
|
-
import commandRender from './commands/render.mjs';
|
|
6
|
+
import runScan, { DEFAULT_SCAN_OUTPUT } from './scan.mjs';
|
|
8
7
|
|
|
9
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
-
const __dirname = dirname(__filename);
|
|
11
|
-
const pkg = readJSONFileSync(resolve(__dirname, '../package.json'));
|
|
12
|
-
|
|
8
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname$1 = dirname(__filename$1);
|
|
10
|
+
const pkg = readJSONFileSync(resolve(__dirname$1, '../package.json'));
|
|
11
|
+
const removedCommands = new Set([
|
|
12
|
+
'extract',
|
|
13
|
+
'render',
|
|
14
|
+
'scan'
|
|
15
|
+
]);
|
|
16
|
+
function errorRemovedCommand(program, command) {
|
|
17
|
+
program.error(`The "${command}" command was removed. Use "${pkg.name}" directly, for example "${pkg.name} -w".`);
|
|
18
|
+
}
|
|
19
|
+
async function runProgram(argv = process.argv) {
|
|
13
20
|
const program = new Command();
|
|
14
|
-
program.name(pkg.name).description(pkg.description).version(pkg.version || '0.0.0')
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
program.name(pkg.name).description(pkg.description).version(pkg.version || '0.0.0').argument('[source paths...]', 'The glob pattern paths to scan sources').option('-w, --watch', 'Watch file changes and generate CSS rules.').option('-o, --output <path>', 'Specify your CSS file output path', DEFAULT_SCAN_OUTPUT).option('-v, --verbose <level>', 'Verbose logging 0~N', '1').option('--no-export', 'Print only CSS results.').action((sourcePaths, options)=>{
|
|
22
|
+
const removedCommand = sourcePaths[0];
|
|
23
|
+
if (removedCommand && removedCommands.has(removedCommand)) {
|
|
24
|
+
errorRemovedCommand(program, removedCommand);
|
|
25
|
+
}
|
|
26
|
+
return runScan(sourcePaths, options);
|
|
27
|
+
});
|
|
28
|
+
const firstArgument = argv[2];
|
|
29
|
+
if (firstArgument && removedCommands.has(firstArgument)) {
|
|
30
|
+
errorRemovedCommand(program, firstArgument);
|
|
31
|
+
}
|
|
32
|
+
await program.parseAsync(argv);
|
|
18
33
|
return program;
|
|
19
34
|
}
|
|
20
35
|
|
package/dist/scan.mjs
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { createExtractedCSS, registerStyleCSSSource } from '@master/css-stylesheet';
|
|
2
|
+
import { findCSSManifestEntryFiles } from '@master/css-project/entries';
|
|
3
|
+
import log from '@techor/log';
|
|
4
|
+
import { explorePathsSync } from '@techor/glob';
|
|
5
|
+
import bytes from 'bytes';
|
|
6
|
+
import chokidar from 'chokidar';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
|
|
10
|
+
const DEFAULT_SCAN_OUTPUT = 'master.css';
|
|
11
|
+
const DEFAULT_SOURCE_PATTERNS = [
|
|
12
|
+
'**/*.{html,htm,js,jsx,mjs,cjs,ts,tsx,mts,cts,svelte,astro,vue,md,mdx,pug,php}'
|
|
13
|
+
];
|
|
14
|
+
async function registerManagedCSSEntries(scanner, styleCSSSources) {
|
|
15
|
+
styleCSSSources.clear();
|
|
16
|
+
for (const entry of (await findCSSManifestEntryFiles(scanner.cwd))){
|
|
17
|
+
await registerStyleCSSSource(scanner, styleCSSSources, entry, fs.readFileSync(entry, 'utf8'), {
|
|
18
|
+
projectDir: scanner.cwd
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
scanner.resetDependencies = [
|
|
22
|
+
...new Set(Array.from(styleCSSSources.values()).flatMap((source)=>source.dependencies))
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
function normalizeSourcePatterns(specifiedSourcePaths) {
|
|
26
|
+
return specifiedSourcePaths?.length ? specifiedSourcePaths : DEFAULT_SOURCE_PATTERNS;
|
|
27
|
+
}
|
|
28
|
+
function resolveSourcePaths(scanner, sourcePatterns, ignore = []) {
|
|
29
|
+
return explorePathsSync(sourcePatterns, {
|
|
30
|
+
cwd: scanner.cwd,
|
|
31
|
+
ignore
|
|
32
|
+
}).filter(Boolean);
|
|
33
|
+
}
|
|
34
|
+
async function scanSourceFile(scanner, source) {
|
|
35
|
+
const filepath = path.resolve(scanner.cwd, source);
|
|
36
|
+
await scanner.scan(source, fs.readFileSync(filepath, 'utf8'));
|
|
37
|
+
}
|
|
38
|
+
async function scanSourceFiles(scanner, sourcePaths) {
|
|
39
|
+
await Promise.all(sourcePaths.map((source)=>scanSourceFile(scanner, source)));
|
|
40
|
+
}
|
|
41
|
+
async function prepareScanner(scanner, styleCSSSources, sourcePaths) {
|
|
42
|
+
await registerManagedCSSEntries(scanner, styleCSSSources);
|
|
43
|
+
await scanSourceFiles(scanner, sourcePaths);
|
|
44
|
+
}
|
|
45
|
+
function exportCSS(scanner, css, filename = DEFAULT_SCAN_OUTPUT) {
|
|
46
|
+
const filepath = path.resolve(scanner.cwd, filename);
|
|
47
|
+
const dir = path.dirname(filepath);
|
|
48
|
+
if (!fs.existsSync(dir)) {
|
|
49
|
+
fs.mkdirSync(dir, {
|
|
50
|
+
recursive: true
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
fs.writeFileSync(filepath, css);
|
|
54
|
+
if (scanner.options.verbose) {
|
|
55
|
+
log.ok`**${filename}** exported ${bytes(css.length)}`;
|
|
56
|
+
}
|
|
57
|
+
scanner.emit('export', filename, filepath);
|
|
58
|
+
}
|
|
59
|
+
function formatWatchedPath(cwd, file) {
|
|
60
|
+
return path.isAbsolute(file) ? path.relative(cwd, file) : file;
|
|
61
|
+
}
|
|
62
|
+
async function waitForWatcherReady(watcher) {
|
|
63
|
+
await new Promise((resolve)=>watcher.once('ready', resolve));
|
|
64
|
+
// Let chokidar finish registering native watchers before callers mutate files.
|
|
65
|
+
await new Promise((resolve)=>setTimeout(resolve, 0));
|
|
66
|
+
}
|
|
67
|
+
async function runScan(specifiedSourcePaths = [], options = {}) {
|
|
68
|
+
const CSSScanner = (await import('@master/css-scanner')).default;
|
|
69
|
+
const { watch, output, verbose, cwd } = options;
|
|
70
|
+
const scanner = new CSSScanner({}, cwd);
|
|
71
|
+
const styleCSSSources = new Map();
|
|
72
|
+
const sourcePatterns = normalizeSourcePatterns(specifiedSourcePaths);
|
|
73
|
+
const writeOutput = async ()=>{
|
|
74
|
+
const css = await createExtractedCSS({
|
|
75
|
+
scanner,
|
|
76
|
+
styleCSSSources,
|
|
77
|
+
projectDir: scanner.cwd
|
|
78
|
+
});
|
|
79
|
+
if (options.export) {
|
|
80
|
+
exportCSS(scanner, css, output);
|
|
81
|
+
} else {
|
|
82
|
+
console.log(css);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
scanner.on('init', (options)=>{
|
|
86
|
+
if (!specifiedSourcePaths.length) {
|
|
87
|
+
if (!options.exclude?.includes('**/node_modules/**')) {
|
|
88
|
+
options.exclude?.push('**/node_modules/**');
|
|
89
|
+
}
|
|
90
|
+
if (!options.exclude?.includes('node_modules')) {
|
|
91
|
+
options.exclude?.push('node_modules');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
options.verbose = verbose ? +verbose : options.verbose;
|
|
95
|
+
});
|
|
96
|
+
await scanner.init();
|
|
97
|
+
const scanPaths = ()=>resolveSourcePaths(scanner, sourcePatterns, specifiedSourcePaths.length ? [] : scanner.options.exclude);
|
|
98
|
+
if (watch) {
|
|
99
|
+
const watchers = [];
|
|
100
|
+
let restarting = false;
|
|
101
|
+
let writing = Promise.resolve();
|
|
102
|
+
const queueWrite = ()=>{
|
|
103
|
+
writing = writing.then(writeOutput);
|
|
104
|
+
return writing;
|
|
105
|
+
};
|
|
106
|
+
const closeWatchers = async ()=>{
|
|
107
|
+
await Promise.all(watchers.splice(0).map((watcher)=>watcher.close()));
|
|
108
|
+
};
|
|
109
|
+
const startWatchers = async ()=>{
|
|
110
|
+
const sourcePaths = scanPaths();
|
|
111
|
+
if (sourcePaths.length) {
|
|
112
|
+
const sourceWatcher = chokidar.watch(sourcePaths, {
|
|
113
|
+
cwd: scanner.cwd,
|
|
114
|
+
ignoreInitial: true
|
|
115
|
+
});
|
|
116
|
+
sourceWatcher.on('add', (source)=>{
|
|
117
|
+
void scanSourceFile(scanner, source).then(queueWrite);
|
|
118
|
+
});
|
|
119
|
+
sourceWatcher.on('change', (source)=>{
|
|
120
|
+
void scanSourceFile(scanner, source).then(queueWrite);
|
|
121
|
+
});
|
|
122
|
+
watchers.push(sourceWatcher);
|
|
123
|
+
await waitForWatcherReady(sourceWatcher);
|
|
124
|
+
}
|
|
125
|
+
if (scanner.resetDependencies.length) {
|
|
126
|
+
const planWatcher = chokidar.watch(scanner.resetDependencies, {
|
|
127
|
+
ignoreInitial: true
|
|
128
|
+
});
|
|
129
|
+
const handlePlanChange = async (resetDependency)=>{
|
|
130
|
+
if (restarting) return;
|
|
131
|
+
restarting = true;
|
|
132
|
+
try {
|
|
133
|
+
if (scanner.options.verbose) {
|
|
134
|
+
log``;
|
|
135
|
+
log`[change] **${formatWatchedPath(scanner.cwd, resetDependency)}**`;
|
|
136
|
+
}
|
|
137
|
+
await closeWatchers();
|
|
138
|
+
await scanner.reset(scanner.customOptions, {
|
|
139
|
+
emit: false
|
|
140
|
+
});
|
|
141
|
+
await prepareScanner(scanner, styleCSSSources, scanPaths());
|
|
142
|
+
await queueWrite();
|
|
143
|
+
await startWatchers();
|
|
144
|
+
log``;
|
|
145
|
+
log.t`Restart watching source changes`;
|
|
146
|
+
scanner.emit('resetDependencyChange');
|
|
147
|
+
} finally{
|
|
148
|
+
restarting = false;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
planWatcher.on('add', (resetDependency)=>{
|
|
152
|
+
void handlePlanChange(resetDependency);
|
|
153
|
+
});
|
|
154
|
+
planWatcher.on('change', (resetDependency)=>{
|
|
155
|
+
void handlePlanChange(resetDependency);
|
|
156
|
+
});
|
|
157
|
+
planWatcher.on('unlink', (resetDependency)=>{
|
|
158
|
+
void handlePlanChange(resetDependency);
|
|
159
|
+
});
|
|
160
|
+
watchers.push(planWatcher);
|
|
161
|
+
await waitForWatcherReady(planWatcher);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
process.once('SIGTERM', ()=>{
|
|
165
|
+
void closeWatchers().finally(()=>process.exit(0));
|
|
166
|
+
});
|
|
167
|
+
process.once('SIGINT', ()=>{
|
|
168
|
+
void closeWatchers().finally(()=>process.exit(0));
|
|
169
|
+
});
|
|
170
|
+
await prepareScanner(scanner, styleCSSSources, scanPaths());
|
|
171
|
+
await queueWrite();
|
|
172
|
+
await startWatchers();
|
|
173
|
+
log``;
|
|
174
|
+
log.t`Start watching source changes`;
|
|
175
|
+
} else {
|
|
176
|
+
await prepareScanner(scanner, styleCSSSources, scanPaths());
|
|
177
|
+
await writeOutput();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { DEFAULT_SCAN_OUTPUT, runScan as default };
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@master/css-cli","scripts":{"build":"techor build \"src/**/*.ts\" --formats esm","dev":"pnpm build --watch","lint":"eslint","type-check":"tsc --noEmit","test":"vitest"},"type":"module","license":"MIT","description":"Master CSS CLI","author":"Aoyue Design LLC.","funding":"https://rc.css.master.co/sponsor","homepage":"https://css.master.co","bugs":{"url":"https://github.com/master-co/css/issues"},"repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/cli"},"keywords":["cli","css","mastercss"],"bin":
|
|
1
|
+
{"name":"@master/css-cli","scripts":{"build":"techor build \"src/**/*.ts\" --formats esm","dev":"pnpm build --watch","lint":"eslint","type-check":"tsc --noEmit","test":"vitest"},"type":"module","license":"MIT","description":"Master CSS CLI","author":"Aoyue Design LLC.","funding":"https://rc.css.master.co/sponsor","homepage":"https://css.master.co","bugs":{"url":"https://github.com/master-co/css/issues"},"repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/cli"},"keywords":["cli","css","mastercss"],"bin":"./dist/bin/index.mjs","files":["dist"],"publishConfig":{"access":"public","provenance":true},"dependencies":{"@master/css":"^2.0.0-rc.71","@master/css-project":"^2.0.0-rc.71","@master/css-scanner":"^2.0.0-rc.71","@master/css-stylesheet":"^2.0.0-rc.71","@techor/fs":"^3.2.5","@techor/glob":"^3.2.5","@techor/log":"^3.2.5","bytes":"^3.1.2","chokidar":"^5.0.0","commander":"^14.0.3"},"devDependencies":{"@master/css-lexer":"^2.0.0-rc.71","@types/bytes":"^3.1.5","upath":"^2.0.1"},"version":"2.0.0-rc.71"}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { options } from '@master/css-extractor';
|
|
2
|
-
import log from '@techor/log';
|
|
3
|
-
|
|
4
|
-
var commandExtract = ((program)=>program.command('extract').argument('[source paths]', 'The glob pattern path to extract sources').option('-w, --watch', 'Watch file changed and generate CSS rules.').option('-o, --output <path>', 'Specify your CSS file output path', options.output).option('-v, --verbose <level>', 'Verbose logging 0~N', '1').option('--no-export', 'Print only CSS results.').option('--options <path>', 'Specify your extractor options sources', 'master.css-extractor').action(async function(specifiedSourcePaths, options) {
|
|
5
|
-
const CSSExtractor = (await import('@master/css-extractor')).default;
|
|
6
|
-
const { watch, output, verbose, cwd, options: customOptions } = options || {};
|
|
7
|
-
const extractor = new CSSExtractor(customOptions, cwd);
|
|
8
|
-
extractor.on('init', (options)=>{
|
|
9
|
-
if (specifiedSourcePaths?.length) {
|
|
10
|
-
options.include = specifiedSourcePaths;
|
|
11
|
-
options.exclude = [];
|
|
12
|
-
} else {
|
|
13
|
-
if (!options.exclude?.includes('**/node_modules/**')) {
|
|
14
|
-
options.exclude?.push('**/node_modules/**');
|
|
15
|
-
}
|
|
16
|
-
if (!options.exclude?.includes('node_modules')) {
|
|
17
|
-
options.exclude?.push('node_modules');
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
options.output = output;
|
|
21
|
-
options.verbose = verbose ? +verbose : options.verbose;
|
|
22
|
-
});
|
|
23
|
-
extractor.init();
|
|
24
|
-
if (watch) {
|
|
25
|
-
extractor.on('watchStart', async ()=>{
|
|
26
|
-
await extractor.prepare();
|
|
27
|
-
log``;
|
|
28
|
-
log.t`Start watching source changes`;
|
|
29
|
-
}).on('reset', async ()=>{
|
|
30
|
-
await extractor.reset();
|
|
31
|
-
log``;
|
|
32
|
-
log.t`Restart watching source changes`;
|
|
33
|
-
}).on('change', ()=>{
|
|
34
|
-
if (options?.export) {
|
|
35
|
-
extractor.export();
|
|
36
|
-
} else {
|
|
37
|
-
console.log(extractor.css.text);
|
|
38
|
-
}
|
|
39
|
-
}).on('watchClose', ()=>{
|
|
40
|
-
log``;
|
|
41
|
-
log.t`Stop watching source changes`;
|
|
42
|
-
});
|
|
43
|
-
await extractor.startWatch();
|
|
44
|
-
} else {
|
|
45
|
-
await extractor.prepare();
|
|
46
|
-
if (options?.export) {
|
|
47
|
-
extractor.export();
|
|
48
|
-
} else {
|
|
49
|
-
console.log(extractor.css.text);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}));
|
|
53
|
-
|
|
54
|
-
export { commandExtract as default };
|
package/dist/commands/render.mjs
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import log from '@techor/log';
|
|
2
|
-
import prettyHartime from 'pretty-hrtime';
|
|
3
|
-
import { explorePathsSync } from '@techor/glob';
|
|
4
|
-
import exploreConfig from '@master/css-explore-config';
|
|
5
|
-
import { readFile, writeFileSync } from 'fs';
|
|
6
|
-
import { brotliCompressSync } from 'zlib';
|
|
7
|
-
import bytes from 'bytes';
|
|
8
|
-
|
|
9
|
-
var commandRender = ((program)=>program.command('render').description('Scans HTML and injects generated CSS rules').argument('<source paths>', 'The path in glob patterns of the source of the HTML file').option('-c --config <path>', 'The source path of the Master CSS configuration', 'master.css').option('-a --analyze', 'Analyze injected CSS and HTML size ( brotli ) without writing to file').action(async function(filePatterns, options = {
|
|
10
|
-
config: 'master.css'
|
|
11
|
-
}) {
|
|
12
|
-
const { render } = await import('@master/css-server');
|
|
13
|
-
const sourcePaths = explorePathsSync(filePatterns);
|
|
14
|
-
if (sourcePaths.length) {
|
|
15
|
-
const renderStart = process.hrtime();
|
|
16
|
-
const col1Width = Math.max(sourcePaths.reduce((max, current)=>{
|
|
17
|
-
if (current.length > max.length) {
|
|
18
|
-
return current;
|
|
19
|
-
} else {
|
|
20
|
-
return max;
|
|
21
|
-
}
|
|
22
|
-
}).length + 10, 20);
|
|
23
|
-
const col2Width = 8;
|
|
24
|
-
const config = typeof options.config === 'string' ? exploreConfig({
|
|
25
|
-
name: options.config
|
|
26
|
-
}) : undefined;
|
|
27
|
-
log``;
|
|
28
|
-
log`${' Source Files'.padEnd(col1Width)}${'CSS Size'.padStart(col2Width)}`;
|
|
29
|
-
await Promise.all(sourcePaths.map(async (filename)=>new Promise((resolve, reject)=>{
|
|
30
|
-
readFile(filename, {
|
|
31
|
-
encoding: 'utf-8'
|
|
32
|
-
}, (err, content)=>{
|
|
33
|
-
if (err) reject(err);
|
|
34
|
-
const { html, css } = render(content, config);
|
|
35
|
-
const renderedCSSText = css?.text;
|
|
36
|
-
const renderedCSSSize = renderedCSSText ? options.analyze ? brotliCompressSync(renderedCSSText).length : renderedCSSText.length : 0;
|
|
37
|
-
if (!options.analyze) {
|
|
38
|
-
if (content !== html) {
|
|
39
|
-
writeFileSync(filename, html);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const prettifiedCSSSize = bytes(renderedCSSSize);
|
|
43
|
-
log.ok`**${filename}**${' '.repeat(col1Width - filename.length - 2)}${prettifiedCSSSize?.padStart(col2Width)}`;
|
|
44
|
-
resolve();
|
|
45
|
-
});
|
|
46
|
-
})));
|
|
47
|
-
const renderTime = process.hrtime(renderStart);
|
|
48
|
-
if (options.analyze) {
|
|
49
|
-
log`${' '.repeat(col1Width)}${'(Brotli)'.padStart(col2Width)}`;
|
|
50
|
-
log``;
|
|
51
|
-
log.success`**${sourcePaths.length}** files analyzed in ${prettyHartime(renderTime).replace(' ', '')}`;
|
|
52
|
-
log``;
|
|
53
|
-
log.i`The CSS output will be smaller because it doesn't yet consider the bytes shared with HTML.`;
|
|
54
|
-
} else {
|
|
55
|
-
log`${' '.repeat(col1Width)}${'(Raw)'.padStart(col2Width)}`;
|
|
56
|
-
log``;
|
|
57
|
-
log.success`**${sourcePaths.length}** files rendered in ${prettyHartime(renderTime).replace(' ', '')}`;
|
|
58
|
-
}
|
|
59
|
-
} else {
|
|
60
|
-
log.i`No **${filePatterns}** files found`;
|
|
61
|
-
}
|
|
62
|
-
}));
|
|
63
|
-
|
|
64
|
-
export { commandRender as default };
|