auklet 0.0.29 → 0.1.1
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 +25 -1
- package/dist/cli/inspect.d.ts +1 -0
- package/dist/cli/inspect.js +20 -0
- package/dist/cli/main.js +5 -0
- package/dist/css/inspect.d.ts +87 -0
- package/dist/css/inspect.js +303 -0
- package/dist/css/vite/hmr.js +0 -7
- package/dist/css/watch/watcher.d.ts +9 -2
- package/dist/css/watch/watcher.js +64 -15
- package/dist/publish/api/pnpmApi.d.ts +4 -0
- package/dist/publish/api/pnpmApi.js +54 -9
- package/dist/publish/api/publishArgs.d.ts +1 -0
- package/dist/publish/api/publishArgs.js +3 -3
- package/dist/publish/api/registry.d.ts +1 -0
- package/dist/publish/api/registry.js +7 -0
- package/dist/publish/cli.d.ts +11 -0
- package/dist/publish/cli.js +26 -16
- package/dist/publish/inspect.d.ts +29 -0
- package/dist/publish/inspect.js +220 -0
- package/dist/publish/inspectPack.d.ts +28 -0
- package/dist/publish/inspectPack.js +206 -0
- package/dist/publish/inspectRegistry.d.ts +23 -0
- package/dist/publish/inspectRegistry.js +107 -0
- package/dist/publish/runner/publishPreflight.js +1 -7
- package/dist/publish/runner/releaseGitController.js +4 -0
- package/dist/publish/types.d.ts +5 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -74,6 +74,9 @@ The package exposes both `auk` and `auklet`.
|
|
|
74
74
|
| `auk build-css` | Generate CSS output only. |
|
|
75
75
|
| `auk build-css --watch` | Watch source/config/style files and rebuild CSS. |
|
|
76
76
|
| `auk publish` | Run the pnpm-based publish workflow. |
|
|
77
|
+
| `auk inspect publish` | Check publish readiness without changing files or registry state. |
|
|
78
|
+
| `auk inspect pack` | Check package entry/export files before publishing. |
|
|
79
|
+
| `auk inspect css` | Explain CSS output entry, theme, and module plans. |
|
|
77
80
|
| `auk owner add <user>` | Add npm owners through pnpm. |
|
|
78
81
|
|
|
79
82
|
Build and dev commands can override package config for one run:
|
|
@@ -126,7 +129,11 @@ auk publish
|
|
|
126
129
|
auk publish --filter @scope/ui
|
|
127
130
|
auk publish --version patch --dry-run
|
|
128
131
|
auk publish --no-format
|
|
132
|
+
auk publish --no-git
|
|
129
133
|
auk publish --otp 123456
|
|
134
|
+
auk inspect publish --version patch
|
|
135
|
+
auk inspect pack --filter @scope/ui
|
|
136
|
+
auk inspect css --modules
|
|
130
137
|
auk owner add alice
|
|
131
138
|
auk owner add alice --filter @scope/ui --otp 123456
|
|
132
139
|
```
|
|
@@ -148,6 +155,8 @@ auk owner add <user...>
|
|
|
148
155
|
|
|
149
156
|
`--no-format` disables auklet's publish output formatter for that run. It is not
|
|
150
157
|
configured in `package.json`.
|
|
158
|
+
`--no-git` skips auklet's release commit and tag for that run. The publish flow
|
|
159
|
+
still checks that the git worktree is clean unless `--allow-dirty` is also set.
|
|
151
160
|
Before writing versions, auklet checks npm authentication from each target
|
|
152
161
|
package directory. Package-local `.npmrc` files and
|
|
153
162
|
`package.json#publishConfig.registry` are respected.
|
|
@@ -155,6 +164,21 @@ package directory. Package-local `.npmrc` files and
|
|
|
155
164
|
require publish 2FA, and to `pnpm owner add` for owner management 2FA. In CI,
|
|
156
165
|
prefer an npm automation token.
|
|
157
166
|
|
|
167
|
+
`auk inspect publish` accepts the same publish selection and version flags as
|
|
168
|
+
`auk publish`. It resolves the publish plan, checks package entry/export files,
|
|
169
|
+
then checks registry authentication and whether target versions already exist.
|
|
170
|
+
It does not write versions, run hooks, build, commit, tag, or publish packages.
|
|
171
|
+
Local package file failures or registry issues exit with code 1.
|
|
172
|
+
|
|
173
|
+
`auk inspect pack` accepts `--filter` for workspace package selection. It checks
|
|
174
|
+
whether `package.json` entry fields, `exports`, `bin`, `types`, CSS entry fields,
|
|
175
|
+
and declared `files` paths point to existing package files.
|
|
176
|
+
|
|
177
|
+
`auk inspect css` accepts the same build override flags as `auk build`. It
|
|
178
|
+
prints the normalized CSS plan, including output entries, theme files, and
|
|
179
|
+
module entries. When run from a pnpm workspace root, it inspects workspace child
|
|
180
|
+
packages instead of the root package. It does not write CSS output.
|
|
181
|
+
|
|
158
182
|
## Configuration
|
|
159
183
|
|
|
160
184
|
`auklet.config.js` or `auklet.config.mjs` is loaded from the current package
|
|
@@ -430,4 +454,4 @@ Notes:
|
|
|
430
454
|
|
|
431
455
|
- `pnpm build` rewrites `dist`.
|
|
432
456
|
- `pnpm run format` formats `bin`, `src`, `dist`, `examples`, and related files.
|
|
433
|
-
- Read `
|
|
457
|
+
- Read `docs/testing.md` before changing tests.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runInspect(args: Array<string>): Promise<number>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { runInspectCssCli } from '#auklet/css/inspect';
|
|
2
|
+
import { runInspectPublishCli } from '#auklet/publish/inspect';
|
|
3
|
+
import { runInspectPackCli } from '#auklet/publish/inspectPack';
|
|
4
|
+
export async function runInspect(args) {
|
|
5
|
+
const normalizedArgs = args[0] === '--' ? args.slice(1) : args;
|
|
6
|
+
const [command, ...restArgs] = normalizedArgs;
|
|
7
|
+
if (command === 'css') {
|
|
8
|
+
return runInspectCssCli(restArgs);
|
|
9
|
+
}
|
|
10
|
+
if (command === 'publish') {
|
|
11
|
+
return runInspectPublishCli(restArgs);
|
|
12
|
+
}
|
|
13
|
+
if (command === 'pack') {
|
|
14
|
+
return runInspectPackCli(restArgs);
|
|
15
|
+
}
|
|
16
|
+
if (command) {
|
|
17
|
+
throw new Error(`[inspect] unknown inspect command: ${command}`);
|
|
18
|
+
}
|
|
19
|
+
throw new Error('[inspect] expected inspect command: auk inspect publish, auk inspect pack, or auk inspect css');
|
|
20
|
+
}
|
package/dist/cli/main.js
CHANGED
|
@@ -7,6 +7,7 @@ import { runDev } from '#auklet/cli/dev';
|
|
|
7
7
|
import { runBuildCss } from '#auklet/cli/buildCss';
|
|
8
8
|
import { runBuild, runBuildJs } from '#auklet/cli/build';
|
|
9
9
|
import { runOwner, runPublish } from '#auklet/cli/publish';
|
|
10
|
+
import { runInspect } from '#auklet/cli/inspect';
|
|
10
11
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
12
|
const getPackageVersion = () => {
|
|
12
13
|
const packageJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../../package.json'), 'utf8'));
|
|
@@ -53,6 +54,10 @@ async function runCli(argv) {
|
|
|
53
54
|
.command('owner [...args]', 'Manage npm package owners with pnpm')
|
|
54
55
|
.allowUnknownOptions()
|
|
55
56
|
.action(() => runCliCommand(runOwner, getCommandArgs(argv, 'owner')));
|
|
57
|
+
cli
|
|
58
|
+
.command('inspect [...args]', 'Inspect auklet plans without side effects')
|
|
59
|
+
.allowUnknownOptions()
|
|
60
|
+
.action(() => runCliCommand(runInspect, getCommandArgs(argv, 'inspect')));
|
|
56
61
|
cli
|
|
57
62
|
.command('version', 'Print auklet version')
|
|
58
63
|
.action(() => runCliCommand(runVersion, []));
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { AukletConfig, ModuleStyleBuildConfig } from '#auklet/types';
|
|
2
|
+
type CssInspectEntryRow = {
|
|
3
|
+
entry: string;
|
|
4
|
+
parts: Array<string>;
|
|
5
|
+
};
|
|
6
|
+
type CssInspectModuleRow = {
|
|
7
|
+
sourceDir: string;
|
|
8
|
+
imports: Array<string>;
|
|
9
|
+
ownStyles: Array<string>;
|
|
10
|
+
};
|
|
11
|
+
export type CssInspectModel = {
|
|
12
|
+
details: {
|
|
13
|
+
packageName: string;
|
|
14
|
+
packageRoot: string;
|
|
15
|
+
source: string;
|
|
16
|
+
output: string;
|
|
17
|
+
modules: boolean;
|
|
18
|
+
sourceFiles: number;
|
|
19
|
+
styleFiles: number;
|
|
20
|
+
themes: number;
|
|
21
|
+
moduleEntries: number;
|
|
22
|
+
};
|
|
23
|
+
packageEntries: Array<CssInspectEntryRow>;
|
|
24
|
+
themeFiles: Array<{
|
|
25
|
+
theme: string;
|
|
26
|
+
file: string;
|
|
27
|
+
}>;
|
|
28
|
+
styleFiles: Array<string>;
|
|
29
|
+
moduleEntries: Array<CssInspectModuleRow>;
|
|
30
|
+
};
|
|
31
|
+
export declare function runInspectCssCli(args: Array<string>): Promise<number>;
|
|
32
|
+
export declare function resolveInspectCssOptions(args: Array<string>): Promise<{
|
|
33
|
+
cwd: string;
|
|
34
|
+
targets: {
|
|
35
|
+
packageRoot: string;
|
|
36
|
+
packageName: string;
|
|
37
|
+
aukletConfig: {
|
|
38
|
+
build: {
|
|
39
|
+
formats?: Array<import("#auklet/types").PackageBuildFormat>;
|
|
40
|
+
target?: import("#auklet/types").PackageBuildTarget;
|
|
41
|
+
platform?: import("#auklet/types").PackageBuildPlatform;
|
|
42
|
+
banner?: string;
|
|
43
|
+
externals?: Array<string>;
|
|
44
|
+
alias?: Record<string, string>;
|
|
45
|
+
mainFields?: Array<string>;
|
|
46
|
+
globals?: Record<string, string>;
|
|
47
|
+
configureTsdown?: import("#auklet/types").ConfigureTsdown;
|
|
48
|
+
tsconfig?: string;
|
|
49
|
+
} | undefined;
|
|
50
|
+
source?: string;
|
|
51
|
+
output?: string;
|
|
52
|
+
modules?: boolean;
|
|
53
|
+
styles?: import("#auklet/types").StyleOptions;
|
|
54
|
+
};
|
|
55
|
+
config: ModuleStyleBuildConfig;
|
|
56
|
+
}[];
|
|
57
|
+
}>;
|
|
58
|
+
export declare function createCssInspectModel(options: {
|
|
59
|
+
packageRoot: string;
|
|
60
|
+
packageName?: string;
|
|
61
|
+
aukletConfig?: AukletConfig;
|
|
62
|
+
config?: ModuleStyleBuildConfig;
|
|
63
|
+
}): {
|
|
64
|
+
details: {
|
|
65
|
+
packageName: string;
|
|
66
|
+
packageRoot: string;
|
|
67
|
+
source: string;
|
|
68
|
+
output: string;
|
|
69
|
+
modules: boolean;
|
|
70
|
+
sourceFiles: number;
|
|
71
|
+
styleFiles: number;
|
|
72
|
+
themes: number;
|
|
73
|
+
moduleEntries: number;
|
|
74
|
+
};
|
|
75
|
+
packageEntries: CssInspectEntryRow[];
|
|
76
|
+
themeFiles: {
|
|
77
|
+
theme: string;
|
|
78
|
+
file: string;
|
|
79
|
+
}[];
|
|
80
|
+
styleFiles: string[];
|
|
81
|
+
moduleEntries: {
|
|
82
|
+
sourceDir: string;
|
|
83
|
+
imports: string[];
|
|
84
|
+
ownStyles: string[];
|
|
85
|
+
}[];
|
|
86
|
+
};
|
|
87
|
+
export {};
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { isPlainObject, isString } from 'aidly';
|
|
4
|
+
import { normalizeAukletConfig } from '#auklet/config';
|
|
5
|
+
import { loadAukletConfig } from '#auklet/configLoader';
|
|
6
|
+
import { resolveBuildCliArgs } from '#auklet/cli/buildArgs';
|
|
7
|
+
import { moduleStyleBuildConfig } from '#auklet/css/config';
|
|
8
|
+
import { mergeAukletConfigOverrides } from '#auklet/build/cliOverrides';
|
|
9
|
+
import { createExternalEntryParts, createModuleStyleEntryPlans, createStyleEntryParts, createThemeEntryParts, } from '#auklet/css/core/style/entries';
|
|
10
|
+
import { toPosixPath } from '#auklet/utils';
|
|
11
|
+
import { createAukletLogger } from '#auklet/logger';
|
|
12
|
+
import { StylePackageContext } from '#auklet/css/core/stylePackageContext';
|
|
13
|
+
import { findWorkspaceRoot } from '#auklet/workspace/root';
|
|
14
|
+
import { readPnpmWorkspacePackageInfo } from '#auklet/workspace/packages';
|
|
15
|
+
const packageSeparator = '-'.repeat(84);
|
|
16
|
+
export async function runInspectCssCli(args) {
|
|
17
|
+
const inspectOptions = await resolveInspectCssOptions(args);
|
|
18
|
+
const models = inspectOptions.targets.map((target) => createCssInspectModel(target));
|
|
19
|
+
new CssInspectReporter(inspectOptions.cwd, models).report();
|
|
20
|
+
return 0;
|
|
21
|
+
}
|
|
22
|
+
export async function resolveInspectCssOptions(args) {
|
|
23
|
+
const buildArgs = resolveBuildCliArgs(args.filter((arg) => arg !== '--'));
|
|
24
|
+
if (buildArgs.args.length) {
|
|
25
|
+
throw new Error(`[inspect] unknown inspect css argument: ${buildArgs.args[0]}`);
|
|
26
|
+
}
|
|
27
|
+
const cwd = process.cwd();
|
|
28
|
+
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
29
|
+
const packageRoots = workspaceRoot === cwd
|
|
30
|
+
? (await readPnpmWorkspacePackageInfo(cwd))
|
|
31
|
+
.map((item) => path.resolve(item.path))
|
|
32
|
+
.filter((packageRoot) => packageRoot !== cwd)
|
|
33
|
+
: [cwd];
|
|
34
|
+
return {
|
|
35
|
+
cwd,
|
|
36
|
+
targets: await Promise.all(packageRoots.map(async (packageRoot) => ({
|
|
37
|
+
packageRoot,
|
|
38
|
+
packageName: readPackageName(packageRoot),
|
|
39
|
+
aukletConfig: mergeAukletConfigOverrides(await loadAukletConfig(packageRoot), buildArgs.config),
|
|
40
|
+
config: moduleStyleBuildConfig,
|
|
41
|
+
}))),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function createCssInspectModel(options) {
|
|
45
|
+
const config = options.config ?? moduleStyleBuildConfig;
|
|
46
|
+
const normalizedConfig = normalizeAukletConfig(options.aukletConfig ?? {});
|
|
47
|
+
const context = createBuildContext(options.packageRoot, normalizedConfig);
|
|
48
|
+
const packageContext = new StylePackageContext({
|
|
49
|
+
config,
|
|
50
|
+
context,
|
|
51
|
+
normalizedConfig,
|
|
52
|
+
});
|
|
53
|
+
const moduleEntries = normalizedConfig.modules
|
|
54
|
+
? createModuleStyleEntryPlans(packageContext)
|
|
55
|
+
: [];
|
|
56
|
+
const packageEntries = createCssInspectEntryRows(config, normalizedConfig, packageContext);
|
|
57
|
+
return {
|
|
58
|
+
details: {
|
|
59
|
+
packageName: options.packageName ?? readPackageName(context.packageRoot),
|
|
60
|
+
packageRoot: context.packageRoot,
|
|
61
|
+
source: context.sourceDir,
|
|
62
|
+
output: context.outputDir,
|
|
63
|
+
modules: normalizedConfig.modules,
|
|
64
|
+
sourceFiles: packageContext.sourceFiles.length,
|
|
65
|
+
styleFiles: packageContext.styleFiles.length,
|
|
66
|
+
themes: packageContext.themeFiles.size,
|
|
67
|
+
moduleEntries: moduleEntries.length,
|
|
68
|
+
},
|
|
69
|
+
packageEntries,
|
|
70
|
+
themeFiles: Array.from(packageContext.themeFiles.entries()).map(([theme, file]) => ({
|
|
71
|
+
theme,
|
|
72
|
+
file: toRelativePath(context.packageRoot, file),
|
|
73
|
+
})),
|
|
74
|
+
styleFiles: packageContext.styleFiles.map((file) => toRelativePath(context.packageRoot, file)),
|
|
75
|
+
moduleEntries: moduleEntries.map((entry) => ({
|
|
76
|
+
sourceDir: toPosixPath(entry.sourceDir),
|
|
77
|
+
imports: sortStyleDependencies(entry.moduleStyleImports),
|
|
78
|
+
ownStyles: entry.ownStyleFiles.map((file) => toRelativePath(context.packageRoot, file)),
|
|
79
|
+
})),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const createCssInspectEntryRows = (config, normalizedConfig, packageContext) => {
|
|
83
|
+
const rows = [];
|
|
84
|
+
const styleEntryParts = createStyleEntryParts(normalizedConfig);
|
|
85
|
+
const externalEntryParts = createExternalEntryParts(normalizedConfig);
|
|
86
|
+
if (packageContext.styleFiles.length ||
|
|
87
|
+
packageContext.themeFiles.size ||
|
|
88
|
+
hasDependencyParts(styleEntryParts)) {
|
|
89
|
+
rows.push({
|
|
90
|
+
entry: config.output.indexStyleFile,
|
|
91
|
+
parts: styleEntryParts.map(formatEntryPart),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (hasDependencyParts(externalEntryParts)) {
|
|
95
|
+
rows.push({
|
|
96
|
+
entry: path.posix.join(config.output.styleDir, config.output.externalStyleFile),
|
|
97
|
+
parts: externalEntryParts.map(formatEntryPart),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
rows.push(...packageContext.themeNames.map((themeName) => ({
|
|
101
|
+
entry: path.posix.join(config.output.styleDir, `${themeName}.css`),
|
|
102
|
+
parts: createThemeEntryParts(normalizedConfig, themeName).map(formatEntryPart),
|
|
103
|
+
})));
|
|
104
|
+
return rows;
|
|
105
|
+
};
|
|
106
|
+
const hasDependencyParts = (parts) => {
|
|
107
|
+
return parts.some((part) => {
|
|
108
|
+
if (part.type !== 'dependencies')
|
|
109
|
+
return false;
|
|
110
|
+
const specifiers = Reflect.get(part, 'specifiers');
|
|
111
|
+
return specifiers.length > 0;
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
const createBuildContext = (packageRoot, config) => {
|
|
115
|
+
return {
|
|
116
|
+
packageRoot,
|
|
117
|
+
sourceDir: config.source,
|
|
118
|
+
outputDir: config.output,
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
const readPackageName = (packageRoot) => {
|
|
122
|
+
const packageJson = JSON.parse(readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
|
|
123
|
+
if (!isPlainObject(packageJson) || !isString(packageJson.name)) {
|
|
124
|
+
return path.basename(packageRoot);
|
|
125
|
+
}
|
|
126
|
+
return packageJson.name;
|
|
127
|
+
};
|
|
128
|
+
const formatEntryPart = (part) => {
|
|
129
|
+
if (part.type === 'dependencies') {
|
|
130
|
+
const specifiers = Reflect.get(part, 'specifiers');
|
|
131
|
+
return specifiers.length
|
|
132
|
+
? `dependencies: ${specifiers.join(', ')}`
|
|
133
|
+
: 'dependencies: none';
|
|
134
|
+
}
|
|
135
|
+
if (part.type === 'themes') {
|
|
136
|
+
const themeNames = Reflect.get(part, 'themeNames');
|
|
137
|
+
return themeNames.length ? `themes: ${themeNames.join(', ')}` : 'themes';
|
|
138
|
+
}
|
|
139
|
+
if (part.type === 'theme') {
|
|
140
|
+
return `theme: ${String(Reflect.get(part, 'themeName'))}`;
|
|
141
|
+
}
|
|
142
|
+
return part.type;
|
|
143
|
+
};
|
|
144
|
+
const toRelativePath = (root, file) => {
|
|
145
|
+
return toPosixPath(path.relative(root, file));
|
|
146
|
+
};
|
|
147
|
+
const sortStyleDependencies = (dependencies) => {
|
|
148
|
+
return [...dependencies].sort((left, right) => {
|
|
149
|
+
const leftExternal = isExternalStyleDependency(left);
|
|
150
|
+
const rightExternal = isExternalStyleDependency(right);
|
|
151
|
+
if (leftExternal !== rightExternal)
|
|
152
|
+
return leftExternal ? -1 : 1;
|
|
153
|
+
return left.localeCompare(right);
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
const isExternalStyleDependency = (dependency) => {
|
|
157
|
+
return !dependency.startsWith('.') && !dependency.startsWith('/');
|
|
158
|
+
};
|
|
159
|
+
class CssInspectReporter {
|
|
160
|
+
cwd;
|
|
161
|
+
models;
|
|
162
|
+
logger = createAukletLogger();
|
|
163
|
+
constructor(cwd, models) {
|
|
164
|
+
this.cwd = cwd;
|
|
165
|
+
this.models = models;
|
|
166
|
+
}
|
|
167
|
+
report() {
|
|
168
|
+
this.logger.newline();
|
|
169
|
+
this.logger.result({
|
|
170
|
+
title: this.logger.colors.bold(this.logger.colors.green('CSS inspect')),
|
|
171
|
+
status: 'info',
|
|
172
|
+
body: [this.logger.colors.gray('Read-only CSS plan. No files changed.')],
|
|
173
|
+
details: {
|
|
174
|
+
packages: this.formatValue(this.models.length),
|
|
175
|
+
styles: this.formatValue(this.models.reduce((total, model) => total + model.details.styleFiles, 0)),
|
|
176
|
+
themes: this.formatValue(this.models.reduce((total, model) => total + model.details.themes, 0)),
|
|
177
|
+
entries: this.formatValue(this.models.reduce((total, model) => total + model.details.moduleEntries, 0)),
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
for (const [index, model] of this.models.entries()) {
|
|
181
|
+
this.logger.newline();
|
|
182
|
+
if (index > 0) {
|
|
183
|
+
this.writePackageSeparator();
|
|
184
|
+
this.logger.newline();
|
|
185
|
+
}
|
|
186
|
+
this.reportPackage(model);
|
|
187
|
+
}
|
|
188
|
+
this.logger.newline();
|
|
189
|
+
}
|
|
190
|
+
reportPackage(model) {
|
|
191
|
+
this.logger.result({
|
|
192
|
+
title: this.formatPackage(model.details.packageName),
|
|
193
|
+
status: 'info',
|
|
194
|
+
details: {
|
|
195
|
+
root: this.logger.path(toRelativePath(this.cwd, model.details.packageRoot) || '.'),
|
|
196
|
+
source: this.logger.path(model.details.source),
|
|
197
|
+
output: this.logger.path(model.details.output),
|
|
198
|
+
modules: this.formatValue(model.details.modules ? 'on' : 'off'),
|
|
199
|
+
styles: this.formatValue(model.details.styleFiles),
|
|
200
|
+
themes: this.formatValue(model.details.themes),
|
|
201
|
+
entries: this.formatValue(model.details.moduleEntries),
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
this.logger.newline();
|
|
205
|
+
this.writeSectionTitle('Output entries');
|
|
206
|
+
this.logger.rows({
|
|
207
|
+
columns: this.formatColumns(['entry', 'parts']),
|
|
208
|
+
rows: model.packageEntries.map((entry) => [
|
|
209
|
+
this.logger.path(entry.entry),
|
|
210
|
+
this.formatEntryParts(entry.parts),
|
|
211
|
+
]),
|
|
212
|
+
empty: this.logger.colors.gray('No package-level CSS entries found.'),
|
|
213
|
+
});
|
|
214
|
+
this.logger.newline();
|
|
215
|
+
this.writeSectionTitle('Theme files');
|
|
216
|
+
this.logger.rows({
|
|
217
|
+
columns: this.formatColumns(['theme', 'file']),
|
|
218
|
+
rows: model.themeFiles.map((theme) => [
|
|
219
|
+
this.formatTheme(theme.theme),
|
|
220
|
+
this.logger.path(theme.file),
|
|
221
|
+
]),
|
|
222
|
+
empty: this.logger.colors.gray('No theme files configured.'),
|
|
223
|
+
});
|
|
224
|
+
this.logger.newline();
|
|
225
|
+
this.writeSectionTitle('Module entries');
|
|
226
|
+
this.writeModuleEntries(model);
|
|
227
|
+
}
|
|
228
|
+
writeSectionTitle(title) {
|
|
229
|
+
this.logger.raw(title);
|
|
230
|
+
}
|
|
231
|
+
writePackageSeparator() {
|
|
232
|
+
this.logger.raw(this.logger.colors.gray(packageSeparator));
|
|
233
|
+
}
|
|
234
|
+
writeModuleEntries(model) {
|
|
235
|
+
if (!model.moduleEntries.length) {
|
|
236
|
+
this.logger.empty(model.details.modules
|
|
237
|
+
? this.logger.colors.gray('No module style entries found.')
|
|
238
|
+
: this.logger.colors.gray('Module output is disabled.'));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
for (const [index, entry] of model.moduleEntries.entries()) {
|
|
242
|
+
if (index > 0)
|
|
243
|
+
this.logger.newline();
|
|
244
|
+
this.logger.rows({
|
|
245
|
+
title: this.formatSource(entry.sourceDir),
|
|
246
|
+
columns: this.formatColumns(['type', 'file']),
|
|
247
|
+
rows: [
|
|
248
|
+
...this.createModuleEntryRows('own style', entry.ownStyles, (value) => this.formatOwnStyle(value)),
|
|
249
|
+
...this.createModuleEntryRows('dependency', entry.imports, (value) => this.formatDependency(value)),
|
|
250
|
+
],
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
createModuleEntryRows(title, values, format) {
|
|
255
|
+
if (!values.length) {
|
|
256
|
+
return [
|
|
257
|
+
[this.logger.colors.gray(title), this.logger.colors.gray('none')],
|
|
258
|
+
];
|
|
259
|
+
}
|
|
260
|
+
return values.map((value) => [
|
|
261
|
+
this.logger.colors.gray(title),
|
|
262
|
+
format(value),
|
|
263
|
+
]);
|
|
264
|
+
}
|
|
265
|
+
formatColumns(columns) {
|
|
266
|
+
return columns.map((column) => this.logger.colors.gray(column));
|
|
267
|
+
}
|
|
268
|
+
formatEntryParts(parts) {
|
|
269
|
+
return parts.flatMap((part, index) => [
|
|
270
|
+
...(index > 0 ? [this.logger.colors.gray(' | ')] : []),
|
|
271
|
+
this.formatEntryPart(part),
|
|
272
|
+
]);
|
|
273
|
+
}
|
|
274
|
+
formatEntryPart(part) {
|
|
275
|
+
if (part.startsWith('dependencies:')) {
|
|
276
|
+
return this.logger.colors.yellow(part);
|
|
277
|
+
}
|
|
278
|
+
if (part.startsWith('themes:') || part.startsWith('theme:')) {
|
|
279
|
+
return this.logger.colors.hex('#7c3aed')(part);
|
|
280
|
+
}
|
|
281
|
+
if (part === 'module')
|
|
282
|
+
return this.logger.colors.green(part);
|
|
283
|
+
return this.logger.colors.gray(part);
|
|
284
|
+
}
|
|
285
|
+
formatSource(value) {
|
|
286
|
+
return this.logger.colors.bold(this.logger.colors.cyan(value));
|
|
287
|
+
}
|
|
288
|
+
formatDependency(value) {
|
|
289
|
+
return this.logger.colors.yellow(value);
|
|
290
|
+
}
|
|
291
|
+
formatOwnStyle(value) {
|
|
292
|
+
return this.logger.colors.green(value);
|
|
293
|
+
}
|
|
294
|
+
formatTheme(value) {
|
|
295
|
+
return this.logger.colors.bold(this.logger.colors.hex('#7c3aed')(value));
|
|
296
|
+
}
|
|
297
|
+
formatPackage(value) {
|
|
298
|
+
return this.logger.colors.bold(this.logger.colors.hex('#5b21b6')(value));
|
|
299
|
+
}
|
|
300
|
+
formatValue(value) {
|
|
301
|
+
return this.logger.colors.bold(this.logger.colors.cyan(String(value)));
|
|
302
|
+
}
|
|
303
|
+
}
|
package/dist/css/vite/hmr.js
CHANGED
|
@@ -2,13 +2,6 @@ import path from 'node:path';
|
|
|
2
2
|
import { isString } from 'aidly';
|
|
3
3
|
import { normalizeFileKey } from '#auklet/utils';
|
|
4
4
|
import { createScopedAukletLogger } from '#auklet/logger';
|
|
5
|
-
// package CSS 的 HMR 不能直接走 Vite 原生 CSS 文件链路:
|
|
6
|
-
// 1. 浏览器 import 的是 auklet-css:* 虚拟 CSS 模块,不是真实的
|
|
7
|
-
// packages/*/src/**/*.css 文件,所以真实 CSS 变化时 Vite 的 modules 可能为空。
|
|
8
|
-
// 2. Vite dev 会把 CSS 转成自接受的 JS 模块,重新执行模块里的 updateStyle()
|
|
9
|
-
// 才能更新样式,因此这里手动发送 js-update,而不是 css-update。
|
|
10
|
-
// 3. @tailwindcss/vite 会在相关 CSS 变化时主动发 full-reload。package CSS 已由
|
|
11
|
-
// 这个插件接管 HMR 时,需要在一个很短的窗口内吞掉这次 reload。
|
|
12
5
|
const FULL_RELOAD_SUPPRESS_MS = 100;
|
|
13
6
|
const DUPLICATE_UPDATE_IGNORE_MS = 500;
|
|
14
7
|
const logger = createScopedAukletLogger('css:vite');
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
+
import { type AukletLogger } from '#auklet/logger';
|
|
1
2
|
import type { ModuleStyleBuildConfig, ModuleStyleBuildContext } from '#auklet/types';
|
|
3
|
+
type ModuleStyleWatcherLogger = Pick<AukletLogger, 'error'>;
|
|
2
4
|
export declare class ModuleStyleWatcher {
|
|
3
|
-
private readonly config;
|
|
4
5
|
private readonly context;
|
|
6
|
+
private readonly config;
|
|
7
|
+
private readonly logger;
|
|
5
8
|
private timer;
|
|
9
|
+
private closed;
|
|
6
10
|
private isBuilding;
|
|
7
11
|
private shouldRebuild;
|
|
8
12
|
private watcher;
|
|
9
|
-
|
|
13
|
+
private readonly lastErrorLogTimes;
|
|
14
|
+
constructor(context?: ModuleStyleBuildContext, config?: ModuleStyleBuildConfig, logger?: ModuleStyleWatcherLogger | null);
|
|
10
15
|
watch(): Promise<void>;
|
|
11
16
|
private rebuild;
|
|
12
17
|
private refreshWatcher;
|
|
18
|
+
private logError;
|
|
13
19
|
private scheduleBuild;
|
|
14
20
|
private shouldRebuildForFile;
|
|
15
21
|
close(): Promise<void>;
|
|
16
22
|
}
|
|
23
|
+
export {};
|
|
@@ -3,69 +3,112 @@ import path from 'node:path';
|
|
|
3
3
|
import chokidar from 'chokidar';
|
|
4
4
|
import { isString } from 'aidly';
|
|
5
5
|
import { aukletConfigFiles, aukletDefaultOptions, isAukletConfigFile, } from '#auklet/config';
|
|
6
|
-
import { moduleStyleBuildConfig } from '#auklet/css/config';
|
|
7
6
|
import { SOURCE_MODULE_RE } from '#auklet/css/constants';
|
|
7
|
+
import { moduleStyleBuildConfig } from '#auklet/css/config';
|
|
8
8
|
import { ModuleStyleBuilder } from '#auklet/css/production/builder';
|
|
9
|
+
import { createAukletLogger } from '#auklet/logger';
|
|
10
|
+
const errorLogInterval = 2_000;
|
|
9
11
|
export class ModuleStyleWatcher {
|
|
10
|
-
config;
|
|
11
12
|
context;
|
|
13
|
+
config;
|
|
14
|
+
logger;
|
|
12
15
|
timer = null;
|
|
16
|
+
closed = false;
|
|
13
17
|
isBuilding = false;
|
|
14
18
|
shouldRebuild = false;
|
|
15
19
|
watcher = null;
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
lastErrorLogTimes = new Map();
|
|
21
|
+
constructor(context = {}, config = moduleStyleBuildConfig, logger = null) {
|
|
18
22
|
this.context = {
|
|
19
23
|
packageRoot: process.cwd(),
|
|
20
24
|
...context,
|
|
21
25
|
};
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.logger = logger ?? createAukletLogger({ scope: 'css' });
|
|
22
28
|
}
|
|
23
29
|
async watch() {
|
|
30
|
+
if (this.closed)
|
|
31
|
+
return;
|
|
24
32
|
await this.rebuild();
|
|
25
33
|
}
|
|
26
34
|
async rebuild() {
|
|
35
|
+
if (this.closed)
|
|
36
|
+
return;
|
|
27
37
|
if (this.isBuilding) {
|
|
28
38
|
this.shouldRebuild = true;
|
|
29
39
|
return;
|
|
30
40
|
}
|
|
31
41
|
this.isBuilding = true;
|
|
32
42
|
try {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
try {
|
|
44
|
+
const builder = new ModuleStyleBuilder(this.context, this.config);
|
|
45
|
+
await builder.build();
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
this.logError('build', 'CSS build failed; waiting for changes.', error);
|
|
49
|
+
}
|
|
50
|
+
if (!this.closed) {
|
|
51
|
+
try {
|
|
52
|
+
await this.refreshWatcher();
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
this.logError('watch-refresh', 'CSS watcher failed; waiting for changes.', error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
39
58
|
}
|
|
40
59
|
finally {
|
|
41
60
|
this.isBuilding = false;
|
|
42
|
-
if (this.shouldRebuild) {
|
|
61
|
+
if (this.shouldRebuild && !this.closed) {
|
|
43
62
|
this.shouldRebuild = false;
|
|
44
63
|
this.scheduleBuild();
|
|
45
64
|
}
|
|
46
65
|
}
|
|
47
66
|
}
|
|
48
67
|
async refreshWatcher() {
|
|
68
|
+
if (this.closed)
|
|
69
|
+
return;
|
|
49
70
|
const aukletConfig = this.context.aukletConfig ?? {};
|
|
50
71
|
const sourceDir = this.context.source ?? aukletConfig.source ?? aukletDefaultOptions.source;
|
|
51
72
|
const sourceRoot = path.join(this.context.packageRoot, sourceDir);
|
|
52
73
|
const configPaths = aukletConfigFiles.map((file) => path.join(this.context.packageRoot, file));
|
|
53
74
|
const watchPaths = [sourceRoot, ...configPaths].filter((file) => fs.existsSync(file));
|
|
54
|
-
|
|
75
|
+
const previousWatcher = this.watcher;
|
|
76
|
+
this.watcher = null;
|
|
77
|
+
await previousWatcher?.close();
|
|
78
|
+
if (this.closed)
|
|
79
|
+
return;
|
|
55
80
|
this.watcher = chokidar.watch(watchPaths, {
|
|
56
81
|
ignoreInitial: true,
|
|
57
82
|
interval: 300,
|
|
58
83
|
usePolling: true,
|
|
59
84
|
});
|
|
60
85
|
this.watcher.on('all', (_event, file) => {
|
|
86
|
+
if (this.closed)
|
|
87
|
+
return;
|
|
61
88
|
if (isString(file) && !this.shouldRebuildForFile(file)) {
|
|
62
89
|
return;
|
|
63
90
|
}
|
|
64
91
|
this.scheduleBuild();
|
|
65
92
|
});
|
|
66
|
-
this.watcher.on('error', () =>
|
|
93
|
+
this.watcher.on('error', (error) => {
|
|
94
|
+
if (this.closed)
|
|
95
|
+
return;
|
|
96
|
+
this.logError('watch-event', 'CSS watcher error; waiting for changes.', error);
|
|
97
|
+
this.scheduleBuild();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
logError(kind, message, error) {
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
const lastLogTime = this.lastErrorLogTimes.get(kind) ?? 0;
|
|
103
|
+
if (now - lastLogTime < errorLogInterval)
|
|
104
|
+
return;
|
|
105
|
+
this.lastErrorLogTimes.set(kind, now);
|
|
106
|
+
this.logger.error(message);
|
|
107
|
+
this.logger.error(error);
|
|
67
108
|
}
|
|
68
109
|
scheduleBuild() {
|
|
110
|
+
if (this.closed)
|
|
111
|
+
return;
|
|
69
112
|
if (this.timer)
|
|
70
113
|
clearTimeout(this.timer);
|
|
71
114
|
this.timer = setTimeout(() => {
|
|
@@ -81,8 +124,14 @@ export class ModuleStyleWatcher {
|
|
|
81
124
|
return this.config.styleExtensions.includes(path.extname(file));
|
|
82
125
|
}
|
|
83
126
|
async close() {
|
|
84
|
-
|
|
127
|
+
this.closed = true;
|
|
128
|
+
this.shouldRebuild = false;
|
|
129
|
+
if (this.timer) {
|
|
85
130
|
clearTimeout(this.timer);
|
|
86
|
-
|
|
131
|
+
this.timer = null;
|
|
132
|
+
}
|
|
133
|
+
const watcher = this.watcher;
|
|
134
|
+
this.watcher = null;
|
|
135
|
+
await watcher?.close();
|
|
87
136
|
}
|
|
88
137
|
}
|