Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve output capabilities of cli #2927

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions packages/cli/src/build-single-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { CLIDiagnostic } from './report-diagnostics';
import { errorMessages } from './messages';
import type { ModuleFormats } from './types';
import { fileToDataUri } from './file-to-data-uri';
import type { Root } from 'postcss';

export interface BuildCommonOptions {
fullOutDir: string;
Expand Down Expand Up @@ -142,15 +143,21 @@ export function buildSingleFile({
);
}
// st.css.js
const ast = includeCSSInJS
? tryRun(
() => inlineAssetsForJsModule(res, stylable, fs),
`Inline assets failed for: ${filePath}`
)
: res.meta.targetAst!;
const hasCssInJsFormat = moduleFormats.find(
([format]) => format === 'cjs+css' || format === 'esm+css'
);

let astForCssInJs: Root;
if (includeCSSInJS || hasCssInJsFormat) {
astForCssInJs = tryRun(
() => inlineAssetsForJsModule(res, stylable, fs),
`Inline assets failed for: ${filePath}`
);
}

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

const moduleCssImports = collectImportsWithSideEffects(res, stylable, ext);
const cssDepth = res.meta.transformCssDepth?.cssDepth ?? 1;
Expand All @@ -161,22 +168,22 @@ export function buildSingleFile({
const code = generateStylableJSModuleSource(
{
jsExports: res.exports,
moduleType: format,
moduleType,
namespace: res.meta.namespace,
varType: 'var',
imports: moduleCssImports,
runtimeRequest: resolveRuntimeRequest(targetFilePath, format),
runtimeRequest: resolveRuntimeRequest(targetFilePath, moduleType),
},
includeCSSInJS
includeCSSInJS || injectCssInJs
? {
css: ast.toString(),
css: astForCssInJs.toString(),
depth: cssDepth,
id: res.meta.namespace,
runtimeId: format,
}
: undefined
);
const outFilePath = targetFilePath + ext;
const outFilePath = targetFilePath + (injectCssInJs ? '.inject' : '') + ext;
generated.add(outFilePath);
tryRun(() => fs.writeFileSync(outFilePath, code), `Write File Error: ${outFilePath}`);
});
Expand Down Expand Up @@ -206,6 +213,7 @@ export function buildSingleFile({
relative,
dirname,
isAbsolute,
ensureDirectorySync: (path) => ensureDirectory(path, fs),
});
}

Expand Down Expand Up @@ -268,6 +276,7 @@ export function buildDTS({
relative,
dirname,
isAbsolute,
ensureDirectorySync,
}: {
res: StylableResults;
targetFilePath: string;
Expand All @@ -279,22 +288,22 @@ export function buildDTS({
relative: (from: string, to: string) => string;
dirname: (p: string) => string;
isAbsolute: (p: string) => boolean;
ensureDirectorySync?: (path: string) => void;
}) {
const dtsContent = generateDTSContent(res);
const dtsPath = targetFilePath + '.d.ts';

const targetDir = dirname(targetFilePath);
generated.add(dtsPath);
outputLogs.push('output .d.ts');

if (ensureDirectorySync) {
tryRun(() => ensureDirectorySync(targetDir), `Write directory File Error: ${targetDir}`);
}
tryRun(() => writeFileSync(dtsPath, dtsContent), `Write File Error: ${dtsPath}`);

// .d.ts.map
// if not explicitly defined, assumed true with "--dts" parent scope
if (dtsSourceMap !== false) {
const relativeTargetFilePath = relative(
dirname(targetFilePath),
sourceFilePath || targetFilePath
);
const relativeTargetFilePath = relative(targetDir, sourceFilePath || targetFilePath);

const dtsMappingContent = generateDTSSourceMap(
dtsContent,
Expand Down Expand Up @@ -396,8 +405,9 @@ export function removeBuildProducts({
}
// st.css.js
moduleFormats.forEach(([format, ext]) => {
const { injectCssInJs } = parseFormat(format);
outputLogs.push(`${format} module`);
const outFilePath = targetFilePath + ext;
const outFilePath = targetFilePath + (injectCssInJs ? '.inject' : '') + ext;
generated.delete(outFilePath);
tryRun(() => fs.unlinkSync(outFilePath), `Unlink File Error: ${outFilePath}`);
});
Expand Down Expand Up @@ -447,3 +457,9 @@ export function getAllDiagnostics(res: StylableResults): CLIDiagnostic[] {
return diagnostic;
});
}

function parseFormat(format: ModuleFormats[0][0]) {
const injectCssInJs = format.includes('+css');
const moduleType = format.replace('+css', '') as 'esm' | 'cjs';
return { moduleType, injectCssInJs };
}
40 changes: 32 additions & 8 deletions packages/cli/src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ export async function build(
IndexGenerator = BaseIndexGenerator,
cjs,
cjsExt,
cjsCss,
esm,
esmExt,
esmCss,
copyAssets,
includeCSSInJS,
outputCSS,
outputCSSNameTemplate,
Expand Down Expand Up @@ -74,7 +77,7 @@ export async function build(
const buildGeneratedFiles = new Set<string>();
const sourceFiles = new Set<string>();
const assets = new Set<string>();
const moduleFormats = getModuleFormats({ cjs, esm, esmExt, cjsExt });
const moduleFormats = getModuleFormats({ cjs, esm, cjsCss, esmCss, esmExt, cjsExt });

const { runtimeCjsOutPath, runtimeEsmOutPath } = copyRuntime(
inlineRuntime,
Expand Down Expand Up @@ -365,19 +368,30 @@ export async function build(
async function buildAggregatedEntities(affectedFiles: Set<string>, generated: Set<string>) {
if (indexFileGenerator) {
await indexFileGenerator.generateIndexFile(fs);

generated.add(indexFileGenerator.indexFileTargetPath);
outputFiles.set(indexFileGenerator.indexFileTargetPath, affectedFiles);
} else {
}
if (copyAssets) {
const generatedAssets = handleAssets(assets, projectRoot, srcDir, outDir, fs);
for (const generatedAsset of generatedAssets) {
generated.add(generatedAsset);
}

if (manifest) {
generateManifest(projectRoot, sourceFiles, manifest, stylable, mode, log, fs);
generated.add(manifest);
}
}
if (manifest) {
generateManifest(
(absSourcePath) =>
relative(
rootDir,
join(fullOutDir, relative(fullSrcDir, absSourcePath))
).replace(/\\/g, '/'),
sourceFiles,
manifest,
stylable,
mode,
log,
fs
);
generated.add(manifest);
}
}
}
Expand Down Expand Up @@ -494,11 +508,15 @@ export function createGenerator(
function getModuleFormats({
esm,
cjs,
cjsCss,
esmCss,
cjsExt,
esmExt,
}: {
esm: boolean | undefined;
cjs: boolean | undefined;
cjsCss: boolean | undefined;
esmCss: boolean | undefined;
cjsExt: '.cjs' | '.js' | undefined;
esmExt: '.mjs' | '.js' | undefined;
}): ModuleFormats {
Expand All @@ -509,5 +527,11 @@ function getModuleFormats({
if (cjs) {
formats.push(['cjs', cjsExt || '.js']);
}
if (esmCss) {
formats.push(['esm+css', esmExt || '.mjs']);
}
if (cjsCss) {
formats.push(['cjs+css', cjsExt || '.js']);
}
return formats;
}
18 changes: 18 additions & 0 deletions packages/cli/src/config/resolve-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,26 @@ export function getCliArguments(): Arguments<CliArguments> {
description: 'output esm module (.mjs)',
defaultDescription: String(defaults.esm),
})
.option('esmCss', {
type: 'boolean',
description: 'output esm module (.inject.mjs) with inline css injection',
defaultDescription: String(defaults.esmCss),
})
.option('cjs', {
type: 'boolean',
description: 'output commonjs module (.js)',
defaultDescription: String(defaults.cjs),
})
.option('cjsCss', {
type: 'boolean',
description: 'output commonjs module (.inject.js) with inline css injection',
defaultDescription: String(defaults.cjsCss),
})
.option('copyAssets', {
type: 'boolean',
description: 'emit assets found in css files',
defaultDescription: String(defaults.copyAssets),
})
.option('css', {
type: 'boolean',
description: 'output transpiled css (.css)',
Expand Down Expand Up @@ -235,6 +250,9 @@ export function createDefaultOptions(): BuildOptions {
cjs: false,
esm: false,
dts: false,
esmCss: false,
cjsCss: false,
copyAssets: true,
esmExt: '.mjs',
cjsExt: '.js',
injectCSSRequest: false,
Expand Down
54 changes: 34 additions & 20 deletions packages/cli/src/generate-manifest.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,53 @@
import type { Stylable } from '@stylable/core';
import { dirname, relative } from 'path';
import { ensureDirectory, tryRun } from './build-tools';
import type { Log } from './logger';
import type { IFileSystem } from '@file-services/types';
import { isAbsolute } from 'path';

export function generateManifest(
rootDir: string,
remapPath: (absPath: string) => string,
filesToBuild: Set<string>,
manifestOutputPath: string,
stylable: Stylable,
mode: string,
log: Log,
fs: any
fs: IFileSystem
) {
function getBuildNamespace(stylable: Stylable, filePath: string): string {
return stylable.fileProcessor.process(filePath).namespace;
function getExistingMeta(stylable: Stylable, filePath: string) {
// skip fs check since we should not introduce new files
return (
stylable.fileProcessor.cache[filePath]?.value ||
stylable.fileProcessor.process(filePath)
);
}
const manifest = [...filesToBuild].reduce<{
const manifest: {
namespaceMapping: {
[key: string]: string;
};
}>(
(manifest, filePath) => {
manifest.namespaceMapping[relative(rootDir, filePath)] = getBuildNamespace(
stylable,
filePath
);
return manifest;
},
{
namespaceMapping: {},
}
);
log(mode, 'creating manifest file: ');
cssDependencies: {
[key: string]: string[];
};
} = {
namespaceMapping: {},
cssDependencies: {},
};

for (const filePath of filesToBuild) {
const meta = getExistingMeta(stylable, filePath);

const relativePath = remapPath(filePath);
manifest.namespaceMapping[relativePath] = meta.namespace;
const shallowDeps = meta.getImportStatements().map(({ from }) => {
if (isAbsolute(from)) {
return remapPath(from);
}
return from;
});
manifest.cssDependencies[relativePath] = shallowDeps;
}
log(mode, `Creating manifest file at ${manifestOutputPath}`);
tryRun(
() => ensureDirectory(dirname(manifestOutputPath), fs),
() => ensureDirectory(fs.dirname(manifestOutputPath), fs),
`Ensure directory for manifest: ${manifestOutputPath}`
);
tryRun(
Expand Down
13 changes: 12 additions & 1 deletion packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,14 @@ export interface BuildOptions {
cjs?: boolean;
/** commonjs module extension */
cjsExt?: '.cjs' | '.js';
/** cjs with inline css injection */
cjsCss?: boolean;
/** output esm module (.mjs) */
esm?: boolean;
/** esm module extension */
esmExt?: '.mjs' | '.js';
/** esm with inline css injection */
esmCss?: boolean;
/** template of the css file emitted when using outputCSS */
outputCSSNameTemplate?: string;
/** should include the css in the generated JS module */
Expand All @@ -151,6 +155,8 @@ export interface BuildOptions {
outputCSS?: boolean;
/** should output source .st.css file to dist */
outputSources?: boolean;
/** should copy assets to dist */
copyAssets?: boolean;
/** should add namespace reference to the .st.css copy */
useNamespaceReference?: boolean;
/** should inject css import in the JS module for the generated css from outputCSS */
Expand Down Expand Up @@ -196,4 +202,9 @@ export interface BuildContext {
diagnosticsManager?: DiagnosticsManager;
}

export type ModuleFormats = Array<['esm', '.js' | '.mjs'] | ['cjs', '.js' | '.cjs']>;
export type ModuleFormats = Array<
| ['esm', '.js' | '.mjs']
| ['esm+css', '.js' | '.mjs']
| ['cjs', '.js' | '.cjs']
| ['cjs+css', '.js' | '.cjs']
>;
1 change: 1 addition & 0 deletions packages/esbuild/src/stylable-esbuild-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ export const stylablePlugin = (initialPluginOptions: ESBuildOptions = {}): Plugi
relative,
dirname,
isAbsolute,
ensureDirectorySync: fs.ensureDirectorySync,
});
}
}
Expand Down
Loading