Skip to content

Commit

Permalink
feat: add cjs+css and esm+css direct outputs
Browse files Browse the repository at this point in the history
feat: make copyAssets and generateManifest separated from the generateIndex flow.
fix: add ensureDirectorySync to buildDTS
  • Loading branch information
barak007 committed Nov 26, 2023
1 parent 2f77914 commit 0656d75
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 47 deletions.
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

0 comments on commit 0656d75

Please sign in to comment.