Skip to content

Commit 5461f68

Browse files
committed
refine emit dts
1 parent 53040d7 commit 5461f68

File tree

4 files changed

+65
-38
lines changed

4 files changed

+65
-38
lines changed

index.d.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ declare interface BuildOptions {
55
force?: boolean;
66
/** inline images imported in css as data url even if `bundle` is false */
77
forceInlineImages?: boolean;
8-
emitDeclarationFile?: boolean;
8+
/**
9+
* emit typescript declaration file for css modules class names
10+
* - `.css.d.ts` : emit `xxx.css.d.ts`
11+
* - `.d.css.ts` : emit `xxx.d.css.ts` (from typescript@5, see https://www.typescriptlang.org/tsconfig#allowArbitraryExtensions)
12+
* - `true` : emit both `xxx.css.d.ts` and `xxx.d.css.ts`
13+
*/
14+
emitDeclarationFile?: boolean | '.d.css.ts' | '.css.d.ts';
915
inject?: boolean | string | ((css: string, digest: string) => string);
1016
filter?: RegExp;
1117
/**
@@ -52,8 +58,8 @@ declare interface BuildOptions {
5258
declare function CssModulesPlugin(options?: BuildOptions): Plugin;
5359

5460
declare namespace CssModulesPlugin {
55-
export interface Options extends BuildOptions {};
56-
61+
export interface Options extends BuildOptions {}
62+
5763
export interface BuildContext {
5864
options: Options;
5965
buildId: string;

index.js

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
validateOptions
1515
} from './lib/utils.js';
1616
import { compact } from 'lodash-es';
17-
import { readFile, writeFile } from 'node:fs/promises';
17+
import { readFile, rename, writeFile } from 'node:fs/promises';
1818
import { patchContext } from './lib/context.js';
1919

2020
/**
@@ -39,7 +39,7 @@ export const setup = (build, _options) => {
3939
const jsLoader = patchedBuild.initialOptions.loader?.['.js'] ?? 'js';
4040
const outJsExt = patchedBuild.initialOptions.outExtension?.['.js'] ?? '.js';
4141
const forceInlineImages = !!options.forceInlineImages;
42-
const emitDts = !!options.emitDeclarationFile;
42+
const emitDts = options.emitDeclarationFile;
4343

4444
patchedBuild.onLoad({ filter: /.+/, namespace: pluginCssNamespace }, (args) => {
4545
const { path } = args;
@@ -85,42 +85,52 @@ export const setup = (build, _options) => {
8585
);
8686

8787
patchedBuild.onLoad({ filter: modulesCssRegExp, namespace: 'file' }, async (args) => {
88+
if (!emitDts && !bundle && !forceBuild) {
89+
return undefined;
90+
}
91+
8892
log('[file] on load:', args);
8993
const { path } = args;
9094
const rpath = relative(buildRoot, path);
91-
9295
const prefix = basename(rpath, extname(path))
9396
.replace(/[^a-zA-Z0-9]/g, '-')
9497
.replace(/^\-*/, '');
9598
const suffix = patchedBuild.context.packageVersion?.replace(/[^a-zA-Z0-9]/g, '') ?? '';
96-
CSSTransformer.getInstance(patchedBuild).bundle(path, {
99+
100+
const buildResult = CSSTransformer.getInstance(patchedBuild).bundle(path, {
97101
prefix,
98102
suffix,
99103
forceInlineImages,
100-
emitDeclarationFile: emitDts
104+
emitDeclarationFile: !!emitDts
101105
});
102106

103-
if (!bundle && !forceBuild) {
104-
return undefined;
105-
} else if (!bundle && forceBuild) {
106-
log('force build modules css:', rpath);
107-
const buildResult = CSSTransformer.getInstance(patchedBuild).getCachedResult(path);
108-
109-
if (emitDts) {
110-
const outdir = resolve(buildRoot, patchedBuild.initialOptions.outdir ?? '');
111-
const outbase = patchedBuild.initialOptions.outbase;
112-
let outDtsfile = resolve(outdir, rpath) + '.d.ts';
107+
if (emitDts) {
108+
const dtsExts = [];
109+
if (emitDts === '.d.css.ts' || emitDts === '.css.d.ts') {
110+
dtsExts.push(emitDts);
111+
} else {
112+
dtsExts.push('.d.css.ts', '.css.d.ts');
113+
}
114+
const outdir = resolve(buildRoot, patchedBuild.initialOptions.outdir ?? '');
115+
const outbase = patchedBuild.initialOptions.outbase;
116+
dtsExts.forEach(async (dtsExt) => {
117+
let outDtsfile = resolve(outdir, rpath).replace(/\.css$/i, dtsExt);
113118
if (outbase) {
114119
let normalized = normalize(outbase);
115120
if (normalized.endsWith(sep)) {
116121
normalized = compact(normalized.split(sep)).join(sep);
117122
}
118-
outDtsfile = resolve(outDtsfile.replace(normalized, ''));
123+
if (normalized !== '.') {
124+
outDtsfile = resolve(outDtsfile.replace(normalized, ''));
125+
}
119126
}
127+
log(`emit typescript declarations file:`, patchedBuild.context.relative(outDtsfile));
128+
await ensureFile(outDtsfile, buildResult?.dts ?? '');
129+
});
130+
}
120131

121-
ensureFile(outDtsfile, buildResult?.dts ?? '');
122-
}
123-
132+
if (!bundle && forceBuild) {
133+
log('force build modules css:', rpath);
124134
if (injectCss) {
125135
const anotherBuildOptions = { ...patchedBuild.initialOptions };
126136
delete anotherBuildOptions.entryPoints;
@@ -192,11 +202,10 @@ export const setup = (build, _options) => {
192202
};
193203
}
194204
} else if (bundle) {
195-
const bundleResult = CSSTransformer.getInstance(patchedBuild).getCachedResult(path);
196205
return {
197-
contents: bundleResult?.js,
206+
contents: buildResult?.js,
198207
loader: jsLoader,
199-
watchFiles: [path, ...(bundleResult?.composedFiles ?? [])],
208+
watchFiles: [path, ...(buildResult?.composedFiles ?? [])],
200209
resolveDir: dirname(path),
201210
pluginData: {
202211
originCssPath: path
@@ -214,17 +223,22 @@ export const setup = (build, _options) => {
214223
if (!bundle && forceBuild) {
215224
/** @type {[string, Record<string, string>][]} */
216225
const jsFiles = [];
217-
/** @type {Record<string, string>} */
226+
/** @type {[string, string][]} */
227+
const moduleJsFiles = [];
228+
218229
Object.entries(r.metafile?.outputs ?? {}).forEach(([js, meta]) => {
230+
if (meta.entryPoint && modulesCssRegExp.test(meta.entryPoint)) {
231+
moduleJsFiles.push([meta.entryPoint, js]);
232+
}
233+
219234
if (meta.entryPoint && !modulesCssRegExp.test(meta.entryPoint)) {
220235
let shouldPush = false;
221236
/** @type {Record<string, string>} */
222237
const defines = {};
223238
meta.imports?.forEach((imp) => {
224239
if (modulesCssRegExp.test(imp.path)) {
225240
shouldPush = true;
226-
const impExt = extname(imp.path);
227-
defines[imp.path] = imp.path.replace(new RegExp(`${impExt}$`), `${outJsExt}`);
241+
defines[imp.path] = imp.path + outJsExt;
228242
}
229243
});
230244
if (shouldPush) {
@@ -233,8 +247,15 @@ export const setup = (build, _options) => {
233247
}
234248
});
235249

236-
await Promise.all(
237-
jsFiles.map(([js, places]) => {
250+
await Promise.all([
251+
...(moduleJsFiles.map(([src, dist]) => {
252+
const fp = resolve(buildRoot, dist);
253+
const filename = basename(src) + outJsExt;
254+
const finalPath = resolve(dirname(fp), filename);
255+
log(`rename ${dist} to ${filename}`);
256+
return rename(fp, finalPath);
257+
})),
258+
...jsFiles.map(([js, places]) => {
238259
const fulljs = resolve(buildRoot, js);
239260
return readFile(fulljs, { encoding: 'utf8' })
240261
.then((content) => {
@@ -249,7 +270,7 @@ export const setup = (build, _options) => {
249270
return writeFile(fulljs, nc, { encoding: 'utf8' });
250271
});
251272
})
252-
);
273+
]);
253274

254275
return dispose();
255276
}

lib/utils.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { createHash } from 'node:crypto';
33
import { accessSync, constants } from 'node:fs';
44
import { createRequire } from 'node:module';
55
import { omit } from 'lodash-es';
6-
import { appendFile, mkdir } from 'node:fs/promises';
6+
import { writeFile, mkdir } from 'node:fs/promises';
77

88
const require = createRequire(import.meta.url);
99

@@ -213,13 +213,13 @@ const simpleMinifyCss = (
213213
* @param {string} filepath
214214
* @param {string} data
215215
*/
216-
const ensureFile = async (filepath, data) => {
217-
if (!data) {
216+
const ensureFile = async (filepath, data = '') => {
217+
if (!filepath) {
218218
return;
219219
}
220220
const dir = dirname(filepath);
221221
await mkdir(dir, { recursive: true });
222-
await appendFile(filepath, data.trim(), { encoding: 'utf8' });
222+
await writeFile(filepath, `${data}`.trim(), { encoding: 'utf8' });
223223
};
224224

225225
export {

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "esbuild-css-modules-plugin",
3-
"version": "3.0.0-dev.19",
3+
"version": "3.0.0-dev.20",
44
"description": "A esbuild plugin to bundle css modules into js(x)/ts(x).",
55
"main": "./index.cjs",
66
"module": "./index.js",
@@ -34,13 +34,13 @@
3434
"devDependencies": {
3535
"@types/lodash-es": "^4.17.7",
3636
"@types/node": "^17.0.23",
37-
"esbuild": "^0.18.19"
37+
"esbuild": "^0.19.2"
3838
},
3939
"peerDependencies": {
4040
"esbuild": "*"
4141
},
4242
"dependencies": {
43-
"lightningcss": "^1.21.5",
43+
"lightningcss": "^1.21.7",
4444
"lodash": "^4.17.21",
4545
"lodash-es": "^4.17.21"
4646
},

0 commit comments

Comments
 (0)