Skip to content

Commit 0656d75

Browse files
committed
feat: add cjs+css and esm+css direct outputs
feat: make copyAssets and generateManifest separated from the generateIndex flow. fix: add ensureDirectorySync to buildDTS
1 parent 2f77914 commit 0656d75

File tree

6 files changed

+131
-47
lines changed

6 files changed

+131
-47
lines changed

packages/cli/src/build-single-file.ts

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type { CLIDiagnostic } from './report-diagnostics';
1616
import { errorMessages } from './messages';
1717
import type { ModuleFormats } from './types';
1818
import { fileToDataUri } from './file-to-data-uri';
19+
import type { Root } from 'postcss';
1920

2021
export interface BuildCommonOptions {
2122
fullOutDir: string;
@@ -142,15 +143,21 @@ export function buildSingleFile({
142143
);
143144
}
144145
// st.css.js
145-
const ast = includeCSSInJS
146-
? tryRun(
147-
() => inlineAssetsForJsModule(res, stylable, fs),
148-
`Inline assets failed for: ${filePath}`
149-
)
150-
: res.meta.targetAst!;
146+
const hasCssInJsFormat = moduleFormats.find(
147+
([format]) => format === 'cjs+css' || format === 'esm+css'
148+
);
149+
150+
let astForCssInJs: Root;
151+
if (includeCSSInJS || hasCssInJsFormat) {
152+
astForCssInJs = tryRun(
153+
() => inlineAssetsForJsModule(res, stylable, fs),
154+
`Inline assets failed for: ${filePath}`
155+
);
156+
}
151157

152158
moduleFormats.forEach(([format, ext]) => {
153159
outputLogs.push(`${format} module`);
160+
const { moduleType, injectCssInJs } = parseFormat(format);
154161

155162
const moduleCssImports = collectImportsWithSideEffects(res, stylable, ext);
156163
const cssDepth = res.meta.transformCssDepth?.cssDepth ?? 1;
@@ -161,22 +168,22 @@ export function buildSingleFile({
161168
const code = generateStylableJSModuleSource(
162169
{
163170
jsExports: res.exports,
164-
moduleType: format,
171+
moduleType,
165172
namespace: res.meta.namespace,
166173
varType: 'var',
167174
imports: moduleCssImports,
168-
runtimeRequest: resolveRuntimeRequest(targetFilePath, format),
175+
runtimeRequest: resolveRuntimeRequest(targetFilePath, moduleType),
169176
},
170-
includeCSSInJS
177+
includeCSSInJS || injectCssInJs
171178
? {
172-
css: ast.toString(),
179+
css: astForCssInJs.toString(),
173180
depth: cssDepth,
174181
id: res.meta.namespace,
175182
runtimeId: format,
176183
}
177184
: undefined
178185
);
179-
const outFilePath = targetFilePath + ext;
186+
const outFilePath = targetFilePath + (injectCssInJs ? '.inject' : '') + ext;
180187
generated.add(outFilePath);
181188
tryRun(() => fs.writeFileSync(outFilePath, code), `Write File Error: ${outFilePath}`);
182189
});
@@ -206,6 +213,7 @@ export function buildSingleFile({
206213
relative,
207214
dirname,
208215
isAbsolute,
216+
ensureDirectorySync: (path) => ensureDirectory(path, fs),
209217
});
210218
}
211219

@@ -268,6 +276,7 @@ export function buildDTS({
268276
relative,
269277
dirname,
270278
isAbsolute,
279+
ensureDirectorySync,
271280
}: {
272281
res: StylableResults;
273282
targetFilePath: string;
@@ -279,22 +288,22 @@ export function buildDTS({
279288
relative: (from: string, to: string) => string;
280289
dirname: (p: string) => string;
281290
isAbsolute: (p: string) => boolean;
291+
ensureDirectorySync?: (path: string) => void;
282292
}) {
283293
const dtsContent = generateDTSContent(res);
284294
const dtsPath = targetFilePath + '.d.ts';
285-
295+
const targetDir = dirname(targetFilePath);
286296
generated.add(dtsPath);
287297
outputLogs.push('output .d.ts');
288-
298+
if (ensureDirectorySync) {
299+
tryRun(() => ensureDirectorySync(targetDir), `Write directory File Error: ${targetDir}`);
300+
}
289301
tryRun(() => writeFileSync(dtsPath, dtsContent), `Write File Error: ${dtsPath}`);
290302

291303
// .d.ts.map
292304
// if not explicitly defined, assumed true with "--dts" parent scope
293305
if (dtsSourceMap !== false) {
294-
const relativeTargetFilePath = relative(
295-
dirname(targetFilePath),
296-
sourceFilePath || targetFilePath
297-
);
306+
const relativeTargetFilePath = relative(targetDir, sourceFilePath || targetFilePath);
298307

299308
const dtsMappingContent = generateDTSSourceMap(
300309
dtsContent,
@@ -396,8 +405,9 @@ export function removeBuildProducts({
396405
}
397406
// st.css.js
398407
moduleFormats.forEach(([format, ext]) => {
408+
const { injectCssInJs } = parseFormat(format);
399409
outputLogs.push(`${format} module`);
400-
const outFilePath = targetFilePath + ext;
410+
const outFilePath = targetFilePath + (injectCssInJs ? '.inject' : '') + ext;
401411
generated.delete(outFilePath);
402412
tryRun(() => fs.unlinkSync(outFilePath), `Unlink File Error: ${outFilePath}`);
403413
});
@@ -447,3 +457,9 @@ export function getAllDiagnostics(res: StylableResults): CLIDiagnostic[] {
447457
return diagnostic;
448458
});
449459
}
460+
461+
function parseFormat(format: ModuleFormats[0][0]) {
462+
const injectCssInJs = format.includes('+css');
463+
const moduleType = format.replace('+css', '') as 'esm' | 'cjs';
464+
return { moduleType, injectCssInJs };
465+
}

packages/cli/src/build.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ export async function build(
2323
IndexGenerator = BaseIndexGenerator,
2424
cjs,
2525
cjsExt,
26+
cjsCss,
2627
esm,
2728
esmExt,
29+
esmCss,
30+
copyAssets,
2831
includeCSSInJS,
2932
outputCSS,
3033
outputCSSNameTemplate,
@@ -74,7 +77,7 @@ export async function build(
7477
const buildGeneratedFiles = new Set<string>();
7578
const sourceFiles = new Set<string>();
7679
const assets = new Set<string>();
77-
const moduleFormats = getModuleFormats({ cjs, esm, esmExt, cjsExt });
80+
const moduleFormats = getModuleFormats({ cjs, esm, cjsCss, esmCss, esmExt, cjsExt });
7881

7982
const { runtimeCjsOutPath, runtimeEsmOutPath } = copyRuntime(
8083
inlineRuntime,
@@ -365,19 +368,30 @@ export async function build(
365368
async function buildAggregatedEntities(affectedFiles: Set<string>, generated: Set<string>) {
366369
if (indexFileGenerator) {
367370
await indexFileGenerator.generateIndexFile(fs);
368-
369371
generated.add(indexFileGenerator.indexFileTargetPath);
370372
outputFiles.set(indexFileGenerator.indexFileTargetPath, affectedFiles);
371-
} else {
373+
}
374+
if (copyAssets) {
372375
const generatedAssets = handleAssets(assets, projectRoot, srcDir, outDir, fs);
373376
for (const generatedAsset of generatedAssets) {
374377
generated.add(generatedAsset);
375378
}
376-
377-
if (manifest) {
378-
generateManifest(projectRoot, sourceFiles, manifest, stylable, mode, log, fs);
379-
generated.add(manifest);
380-
}
379+
}
380+
if (manifest) {
381+
generateManifest(
382+
(absSourcePath) =>
383+
relative(
384+
rootDir,
385+
join(fullOutDir, relative(fullSrcDir, absSourcePath))
386+
).replace(/\\/g, '/'),
387+
sourceFiles,
388+
manifest,
389+
stylable,
390+
mode,
391+
log,
392+
fs
393+
);
394+
generated.add(manifest);
381395
}
382396
}
383397
}
@@ -494,11 +508,15 @@ export function createGenerator(
494508
function getModuleFormats({
495509
esm,
496510
cjs,
511+
cjsCss,
512+
esmCss,
497513
cjsExt,
498514
esmExt,
499515
}: {
500516
esm: boolean | undefined;
501517
cjs: boolean | undefined;
518+
cjsCss: boolean | undefined;
519+
esmCss: boolean | undefined;
502520
cjsExt: '.cjs' | '.js' | undefined;
503521
esmExt: '.mjs' | '.js' | undefined;
504522
}): ModuleFormats {
@@ -509,5 +527,11 @@ function getModuleFormats({
509527
if (cjs) {
510528
formats.push(['cjs', cjsExt || '.js']);
511529
}
530+
if (esmCss) {
531+
formats.push(['esm+css', esmExt || '.mjs']);
532+
}
533+
if (cjsCss) {
534+
formats.push(['cjs+css', cjsExt || '.js']);
535+
}
512536
return formats;
513537
}

packages/cli/src/config/resolve-options.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,26 @@ export function getCliArguments(): Arguments<CliArguments> {
3434
description: 'output esm module (.mjs)',
3535
defaultDescription: String(defaults.esm),
3636
})
37+
.option('esmCss', {
38+
type: 'boolean',
39+
description: 'output esm module (.inject.mjs) with inline css injection',
40+
defaultDescription: String(defaults.esmCss),
41+
})
3742
.option('cjs', {
3843
type: 'boolean',
3944
description: 'output commonjs module (.js)',
4045
defaultDescription: String(defaults.cjs),
4146
})
47+
.option('cjsCss', {
48+
type: 'boolean',
49+
description: 'output commonjs module (.inject.js) with inline css injection',
50+
defaultDescription: String(defaults.cjsCss),
51+
})
52+
.option('copyAssets', {
53+
type: 'boolean',
54+
description: 'emit assets found in css files',
55+
defaultDescription: String(defaults.copyAssets),
56+
})
4257
.option('css', {
4358
type: 'boolean',
4459
description: 'output transpiled css (.css)',
@@ -235,6 +250,9 @@ export function createDefaultOptions(): BuildOptions {
235250
cjs: false,
236251
esm: false,
237252
dts: false,
253+
esmCss: false,
254+
cjsCss: false,
255+
copyAssets: true,
238256
esmExt: '.mjs',
239257
cjsExt: '.js',
240258
injectCSSRequest: false,

packages/cli/src/generate-manifest.ts

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,53 @@
11
import type { Stylable } from '@stylable/core';
2-
import { dirname, relative } from 'path';
32
import { ensureDirectory, tryRun } from './build-tools';
43
import type { Log } from './logger';
4+
import type { IFileSystem } from '@file-services/types';
5+
import { isAbsolute } from 'path';
56

67
export function generateManifest(
7-
rootDir: string,
8+
remapPath: (absPath: string) => string,
89
filesToBuild: Set<string>,
910
manifestOutputPath: string,
1011
stylable: Stylable,
1112
mode: string,
1213
log: Log,
13-
fs: any
14+
fs: IFileSystem
1415
) {
15-
function getBuildNamespace(stylable: Stylable, filePath: string): string {
16-
return stylable.fileProcessor.process(filePath).namespace;
16+
function getExistingMeta(stylable: Stylable, filePath: string) {
17+
// skip fs check since we should not introduce new files
18+
return (
19+
stylable.fileProcessor.cache[filePath]?.value ||
20+
stylable.fileProcessor.process(filePath)
21+
);
1722
}
18-
const manifest = [...filesToBuild].reduce<{
23+
const manifest: {
1924
namespaceMapping: {
2025
[key: string]: string;
2126
};
22-
}>(
23-
(manifest, filePath) => {
24-
manifest.namespaceMapping[relative(rootDir, filePath)] = getBuildNamespace(
25-
stylable,
26-
filePath
27-
);
28-
return manifest;
29-
},
30-
{
31-
namespaceMapping: {},
32-
}
33-
);
34-
log(mode, 'creating manifest file: ');
27+
cssDependencies: {
28+
[key: string]: string[];
29+
};
30+
} = {
31+
namespaceMapping: {},
32+
cssDependencies: {},
33+
};
34+
35+
for (const filePath of filesToBuild) {
36+
const meta = getExistingMeta(stylable, filePath);
37+
38+
const relativePath = remapPath(filePath);
39+
manifest.namespaceMapping[relativePath] = meta.namespace;
40+
const shallowDeps = meta.getImportStatements().map(({ from }) => {
41+
if (isAbsolute(from)) {
42+
return remapPath(from);
43+
}
44+
return from;
45+
});
46+
manifest.cssDependencies[relativePath] = shallowDeps;
47+
}
48+
log(mode, `Creating manifest file at ${manifestOutputPath}`);
3549
tryRun(
36-
() => ensureDirectory(dirname(manifestOutputPath), fs),
50+
() => ensureDirectory(fs.dirname(manifestOutputPath), fs),
3751
`Ensure directory for manifest: ${manifestOutputPath}`
3852
);
3953
tryRun(

packages/cli/src/types.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,14 @@ export interface BuildOptions {
139139
cjs?: boolean;
140140
/** commonjs module extension */
141141
cjsExt?: '.cjs' | '.js';
142+
/** cjs with inline css injection */
143+
cjsCss?: boolean;
142144
/** output esm module (.mjs) */
143145
esm?: boolean;
144146
/** esm module extension */
145147
esmExt?: '.mjs' | '.js';
148+
/** esm with inline css injection */
149+
esmCss?: boolean;
146150
/** template of the css file emitted when using outputCSS */
147151
outputCSSNameTemplate?: string;
148152
/** should include the css in the generated JS module */
@@ -151,6 +155,8 @@ export interface BuildOptions {
151155
outputCSS?: boolean;
152156
/** should output source .st.css file to dist */
153157
outputSources?: boolean;
158+
/** should copy assets to dist */
159+
copyAssets?: boolean;
154160
/** should add namespace reference to the .st.css copy */
155161
useNamespaceReference?: boolean;
156162
/** should inject css import in the JS module for the generated css from outputCSS */
@@ -196,4 +202,9 @@ export interface BuildContext {
196202
diagnosticsManager?: DiagnosticsManager;
197203
}
198204

199-
export type ModuleFormats = Array<['esm', '.js' | '.mjs'] | ['cjs', '.js' | '.cjs']>;
205+
export type ModuleFormats = Array<
206+
| ['esm', '.js' | '.mjs']
207+
| ['esm+css', '.js' | '.mjs']
208+
| ['cjs', '.js' | '.cjs']
209+
| ['cjs+css', '.js' | '.cjs']
210+
>;

packages/esbuild/src/stylable-esbuild-plugin.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ export const stylablePlugin = (initialPluginOptions: ESBuildOptions = {}): Plugi
346346
relative,
347347
dirname,
348348
isAbsolute,
349+
ensureDirectorySync: fs.ensureDirectorySync,
349350
});
350351
}
351352
}

0 commit comments

Comments
 (0)