Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5b9892a
πŸ• Add pack-next (esbuild) bundler and Node 20 compile fixes
jjpaulino Feb 27, 2026
071df6b
πŸ• Add PostCSS 8 CSS, font, template, vendor, and media asset pipeline…
jjpaulino Mar 1, 2026
a68ff0c
πŸ• Extract Vue 2 SFC styles into _kiln-plugins.css on every build
jjpaulino Mar 1, 2026
398e816
πŸ• Suppress per-file rebuild warnings in watch mode to reduce terminal…
jjpaulino Mar 1, 2026
f68def9
πŸ• Orchestrate full asset pipeline, add chokidar watch mode, and gener…
jjpaulino Mar 1, 2026
475562d
πŸ• Move DS/Eventify/Fingerprint2 and process shims into claycli defaults
jjpaulino Mar 1, 2026
c2a0d3a
πŸ• Add browserCompatPlugin and enhance serviceRewritePlugin for Clay e…
jjpaulino Mar 1, 2026
3c564db
πŸ• Rename lib/cmd/pack-next β†’ lib/cmd/build and update CLI command fro…
jjpaulino Mar 1, 2026
dda78a8
πŸ• Fix Node engine requirement: lower from >=22.0.0 to >=20.0.0
jjpaulino Mar 1, 2026
7795380
πŸ• feat(build): add per-step progress display with animated summary line
jjpaulino Mar 1, 2026
d588601
πŸ• feat(build): add test suite, documentation, and backward-compat notes
jjpaulino Mar 1, 2026
a9299e8
πŸ• docs(build): replace ASCII pipeline diagram with Mermaid flowcharts
jjpaulino Mar 1, 2026
d7c3c13
docs(build): redesign pipeline diagram as single side-by-side comparison
jjpaulino Mar 1, 2026
30c8594
docs(build): fix subgraph title overlap in pipeline diagram
jjpaulino Mar 1, 2026
21a0a95
docs(build): fill out delta column in pipeline comparison table
jjpaulino Mar 1, 2026
03fc295
docs(build): correct CSS watch mode comparison β€” clay compile used fu…
jjpaulino Mar 1, 2026
cc1d95d
docs(build): remove redundant 'API called from' row in script resolut…
jjpaulino Mar 1, 2026
439d5e0
docs(build): fix CSS watch timing claim and expand PM section with we…
jjpaulino Mar 1, 2026
8c322f4
docs(build): correct inaccurate claim that clay compile loaded all co…
jjpaulino Mar 1, 2026
a324459
docs(build): comprehensive accuracy sweep and case-strengthening addi…
jjpaulino Mar 1, 2026
43812a8
update readme
jjpaulino Mar 2, 2026
1606c9d
πŸ• Fix export/import when a page has a url property
jjpaulino Mar 5, 2026
bedc829
Update version temporarily
jjpaulino Mar 6, 2026
cc86ab9
make tests more human readable
jjpaulino Mar 7, 2026
ccf2c37
Merge branch 'jordan/fix-url-imports' of github.com:clay/claycli into…
jjpaulino Mar 7, 2026
a84cfc6
not just url but also customUrl
jjpaulino Mar 7, 2026
dbc906d
Merge branch 'jordan/fix-url-imports' of github.com:clay/claycli into…
jjpaulino Mar 7, 2026
760165f
Fix customUrl/url not being remapped when both fields present or when…
jjpaulino Mar 7, 2026
47249ee
Merge branch 'jordan/fix-url-imports' into jordan/yolo-update
jjpaulino Mar 7, 2026
d867c6c
ready for next phase
jjpaulino Mar 7, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ website/build/
website/yarn.lock
website/node_modules
website/i18n/*
*.tgz
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22
810 changes: 810 additions & 0 deletions CLAY-BUILD.md

Large diffs are not rendered by default.

94 changes: 94 additions & 0 deletions cli/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'use strict';

const { build, watch } = require('../lib/cmd/build');
const log = require('./log').setup({ file: __filename });

function builder(yargs) {
return yargs
.usage('Usage: $0 [options]')
.option('watch', {
alias: 'w',
type: 'boolean',
description: 'Watch for file changes and rebuild automatically',
default: false,
})
.option('minify', {
alias: 'm',
type: 'boolean',
description: 'Minify output (also enabled by CLAYCLI_COMPILE_MINIFIED env var)',
default: !!process.env.CLAYCLI_COMPILE_MINIFIED,
})
.option('entry', {
alias: 'e',
type: 'array',
description: 'Additional entry-point file paths (supplements the default component globs)',
default: [],
})
.example('$0', 'Build all component scripts with esbuild')
.example('$0 --watch', 'Rebuild on every file change')
.example('$0 --minify', 'Build and minify for production');
}

async function handler(argv) {
const options = {
minify: argv.minify,
extraEntries: argv.entry || [],
};

if (argv.watch) {
try {
const ctx = await watch({
...options,
onRebuild(errors) {
// In watch mode only surface errors β€” esbuild reports warnings for
// every file it touches on each incremental rebuild, not just the
// changed file, which floods the terminal with irrelevant noise.
// Warnings are still visible in full during `make compile`.
if (errors.length > 0) {
errors.forEach(e => log('error', e.text, { location: e.location }));
} else {
log('info', '[js] Rebuilt successfully');
}
},
});

log('info', 'Watching for changes β€” press Ctrl+C to stop');

process.on('SIGINT', () => {
ctx.dispose().then(() => process.exit(0));
});

process.on('SIGTERM', () => {
ctx.dispose().then(() => process.exit(0));
});
} catch (error) {
log('error', 'Watch setup failed', { error: error.message });
process.exit(1);
}
} else {
try {
const result = await build(options);

if (result.errors.length > 0) {
result.errors.forEach(e => log('error', e.text, { location: e.location }));
process.exit(1);
}

// esbuild warnings are pre-existing code issues (duplicate object keys,
// typeof-null, etc.) that are not actionable build failures. Log a count
// so they are visible without flooding the terminal with full locations.
if (result.warnings.length > 0) {
log('warn', `${result.warnings.length} esbuild warning(s) β€” run with --log-level=verbose to see details`);
}
} catch (error) {
log('error', 'Build failed', { error: error.message });
process.exit(1);
}
}
}

exports.aliases = ['pack-next', 'pn']; // pack-next kept for backward compat with existing Makefiles
exports.builder = builder;
exports.command = 'build';
exports.describe = 'Compile component scripts and assets with esbuild';
exports.handler = handler;
5 changes: 4 additions & 1 deletion cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ const yargs = require('yargs'),
e: 'export',
i: 'import',
l: 'lint',
p: 'pack'
b: 'build',
p: 'pack',
pn: 'build', // legacy alias: pn β†’ build
'pack-next': 'build' // legacy alias: clay pack-next β†’ clay build
},
listCommands = Object.keys(commands).concat(Object.values(commands));

Expand Down
106 changes: 106 additions & 0 deletions lib/cmd/build/fonts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
'use strict';

const path = require('path');
const fs = require('fs-extra');
const { globSync } = require('glob');

const CWD = process.cwd();

const FONT_EXTS = 'css,woff,woff2,otf,ttf';
const FONTS_SRC_GLOB = path.join(CWD, 'styleguides', '*', 'fonts', `*.{${FONT_EXTS}}`);

// Output destinations
const CSS_DEST = path.join(CWD, 'public', 'css');
const BINARY_DEST = path.join(CWD, 'public', 'fonts');

const ASSET_HOST = process.env.CLAYCLI_COMPILE_ASSET_HOST
? process.env.CLAYCLI_COMPILE_ASSET_HOST.replace(/\/$/, '')
: '';
const ASSET_PATH = process.env.CLAYCLI_COMPILE_ASSET_PATH || '';

/**
* Extract the styleguide name from an absolute font file path.
* Expected structure: .../styleguides/{sg}/fonts/{file}
*
* @param {string} srcPath
* @returns {string} styleguide name
*/
function getStyleguide(srcPath) {
const parts = srcPath.split(path.sep);
const sgIdx = parts.lastIndexOf('styleguides');

return parts[sgIdx + 1];
}

/**
* Process fonts:
* - CSS files: apply $asset-host / $asset-path substitution, then concatenate
* all per-styleguide CSS into public/css/_linked-fonts.{sg}.css so that
* amphora-html can find and inline the @font-face declarations.
* - Binary files (.woff, .woff2, .otf, .ttf): copy as-is to
* public/fonts/{styleguide}/ for cases where fonts are self-hosted.
*
* @returns {Promise<number>} count of files processed
*/
async function buildFonts() {
const files = globSync(FONTS_SRC_GLOB);

if (files.length === 0) return 0;

// Group by styleguide
const byStyleguide = {};

for (const srcPath of files) {
const sg = getStyleguide(srcPath);

if (!byStyleguide[sg]) {
byStyleguide[sg] = { css: [], binary: [] };
}

const ext = path.extname(srcPath).toLowerCase();

if (ext === '.css') {
byStyleguide[sg].css.push(srcPath);
} else {
byStyleguide[sg].binary.push(srcPath);
}
}

await Promise.all([
fs.ensureDir(CSS_DEST),
fs.ensureDir(BINARY_DEST),
]);

await Promise.all(Object.entries(byStyleguide).map(async ([sg, { css, binary }]) => {
// Write _linked-fonts.{sg}.css β€” amphora-html looks for this file to inject
// @font-face declarations into every page that uses this styleguide.
if (css.length > 0) {
const cssChunks = await Promise.all(css.map(async (srcPath) => {
let content = await fs.readFile(srcPath, 'utf8');

content = content.replace(/\$asset-host/g, ASSET_HOST);
content = content.replace(/\$asset-path/g, ASSET_PATH);

return content;
}));

await fs.writeFile(
path.join(CSS_DEST, `_linked-fonts.${sg}.css`),
cssChunks.join('\n'),
'utf8'
);
}

// Copy binary font files (self-hosted scenarios)
await Promise.all(binary.map(async (srcPath) => {
const destPath = path.join(BINARY_DEST, sg, path.basename(srcPath));

await fs.ensureDir(path.dirname(destPath));
await fs.copy(srcPath, destPath, { overwrite: true });
}));
}));

return files.length;
}

module.exports = { buildFonts, FONTS_SRC_GLOB };
Loading