Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.playwright-cli/
.serena/
.tmp/
.wb/
__generated__/
@willbooster/
dist/
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
"prepare": "lefthook install || true",
"release": "yarn multi-semantic-release --debug",
"test": "CI=1 FORCE_COLOR=3 yarn workspaces foreach --all --verbose run test",
"typecheck": "yarn workspaces foreach --all --parallel --verbose run typecheck",
"verify-code": "yarn workspace @willbooster/wb start --working-dir \"$INIT_CWD\" verify-code",
"verify-code-with-tests": "yarn verify-code && yarn test"
"typecheck": "yarn workspaces foreach --all --parallel --verbose run typecheck"
},
"devDependencies": {
"@anolilab/multi-semantic-release": "4.4.1",
Expand Down
1 change: 1 addition & 0 deletions packages/shared-lib-blitz-next/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.playwright-cli/
.serena/
.tmp/
.wb/
__generated__/
@willbooster/
dist/
Expand Down
4 changes: 1 addition & 3 deletions packages/shared-lib-blitz-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@
"lint": "oxlint --no-error-on-unmatched-pattern .",
"lint-fix": "yarn lint --fix",
"test": "vitest",
"typecheck": "tsgo --noEmit",
"verify-code": "yarn workspace @willbooster/wb start --working-dir \"$INIT_CWD\" verify-code",
"verify-code-with-tests": "yarn verify-code && yarn test"
"typecheck": "tsgo --noEmit"
},
"devDependencies": {
"@tsconfig/node-lts": "24.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/shared-lib-next/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.playwright-cli/
.serena/
.tmp/
.wb/
__generated__/
@willbooster/
dist/
Expand Down
4 changes: 1 addition & 3 deletions packages/shared-lib-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@
"lint": "oxlint --no-error-on-unmatched-pattern .",
"lint-fix": "yarn lint --fix",
"test": "vitest",
"typecheck": "tsgo --noEmit",
"verify-code": "yarn workspace @willbooster/wb start --working-dir \"$INIT_CWD\" verify-code",
"verify-code-with-tests": "yarn verify-code && yarn test"
"typecheck": "tsgo --noEmit"
},
"devDependencies": {
"@tsconfig/node-lts": "24.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/shared-lib-node/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.playwright-cli/
.serena/
.tmp/
.wb/
__generated__/
@willbooster/
dist/
Expand Down
4 changes: 1 addition & 3 deletions packages/shared-lib-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@
"lint": "oxlint --no-error-on-unmatched-pattern .",
"lint-fix": "yarn lint --fix",
"test": "vitest test/",
"typecheck": "tsgo --noEmit",
"verify-code": "yarn workspace @willbooster/wb start --working-dir \"$INIT_CWD\" verify-code",
"verify-code-with-tests": "yarn verify-code && yarn test"
"typecheck": "tsgo --noEmit"
},
"dependencies": {
"dotenv": "17.4.2",
Expand Down
1 change: 1 addition & 0 deletions packages/shared-lib-react/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.playwright-cli/
.serena/
.tmp/
.wb/
__generated__/
@willbooster/
dist/
Expand Down
4 changes: 1 addition & 3 deletions packages/shared-lib-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@
"lint-fix": "yarn lint --fix",
"storybook": "start-storybook -p 6006",
"test/ci": "yarn build-storybook",
"typecheck": "tsgo --noEmit",
"verify-code": "yarn workspace @willbooster/wb start --working-dir \"$INIT_CWD\" verify-code",
"verify-code-with-tests": "yarn verify-code && yarn test"
"typecheck": "tsgo --noEmit"
},
"devDependencies": {
"@babel/core": "7.29.0",
Expand Down
1 change: 1 addition & 0 deletions packages/shared-lib/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.playwright-cli/
.serena/
.tmp/
.wb/
__generated__/
@willbooster/
dist/
Expand Down
4 changes: 1 addition & 3 deletions packages/shared-lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@
"lint": "oxlint --no-error-on-unmatched-pattern .",
"lint-fix": "yarn lint --fix",
"test": "vitest",
"typecheck": "tsgo --noEmit",
"verify-code": "yarn workspace @willbooster/wb start --working-dir \"$INIT_CWD\" verify-code",
"verify-code-with-tests": "yarn verify-code && yarn test"
"typecheck": "tsgo --noEmit"
},
"devDependencies": {
"@tsconfig/node-lts": "24.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/wb/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.playwright-cli/
.serena/
.tmp/
.wb/
__generated__/
@willbooster/
dist/
Expand Down
32 changes: 9 additions & 23 deletions packages/wb/src/commands/optimizeForDockerBuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import chalk from 'chalk';
import type { PackageJson } from 'type-fest';
import type { CommandModule, InferredOptionTypes } from 'yargs';

import { findDescendantProjects, type Project } from '../project.js';
import { findDescendantProjects } from '../project.js';
import { packageManager } from '../utils/runtime.js';

import { prepareForRunningCommand } from './commandUtils.js';

// These tools are declared as devDependencies in source repos, but optimized Docker
// package.json files still need them for in-image codegen/build steps.
const runtimeDevDependencies = ['@willbooster/wb', 'build-ts'];

const builder = {
Expand Down Expand Up @@ -39,6 +41,8 @@ export const optimizeForDockerBuildCommand: CommandModule<unknown, InferredOptio
const deps = packageJson[key] ?? {};
for (const [name, value] of Object.entries(deps)) {
if (value?.startsWith('git@github.com:')) {
// Docker builds cannot access private SSH URLs unless credentials are forwarded.
// The Dockerfile copies those workspace packages into the image instead.
deps[name] = `./${name}`;
}
}
Expand All @@ -48,8 +52,6 @@ export const optimizeForDockerBuildCommand: CommandModule<unknown, InferredOptio

optimizeScripts(packageJson);

optimizeDockerInstallPrepareScript(argv, project, packageJson);

optimizeRootProps(packageJson);

if (argv.dryRun) continue;
Expand All @@ -70,10 +72,13 @@ export const optimizeForDockerBuildCommand: CommandModule<unknown, InferredOptio
function optimizeDevDependencies(argv: InferredOptionTypes<typeof builder>, packageJson: PackageJson): void {
promoteRuntimeDevDependencies(packageJson);
if (argv.outside) {
// Outside optimization writes dist/package.json before Docker builds the app.
// Keep build-time packages for that later in-image build and remove only known non-build tooling.
removeUnnecessaryDevDependenciesForOutsideDockerBuild(packageJson);
return;
}

// Inside Docker, codegen/build has already finished, so production install should not see dev tooling.
delete packageJson.devDependencies;
console.info('Removed all devDependencies.');
}
Expand Down Expand Up @@ -105,6 +110,7 @@ function removeUnnecessaryDevDependenciesForOutsideDockerBuild(packageJson: Pack
for (const name of Object.keys(devDeps)) {
if (
nameWordsToBeRemoved.some((word) => name.includes(word)) ||
// Shared config packages are needed only for lint/format/test commands, not Docker builds.
(name.includes('willbooster') && name.includes('config'))
) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
Expand Down Expand Up @@ -153,26 +159,6 @@ function optimizeScripts(packageJson: PackageJson): void {
console.info('Removed scripts:', removedScripts.join(', ') || 'none');
}

function optimizeDockerInstallPrepareScript(
argv: InferredOptionTypes<typeof builder>,
project: Project,
packageJson: PackageJson
): void {
// The published wb binary may run under Node even when invoked by a Bun project script.
// Use the target project instead of the current CLI runtime when deciding Docker install steps.
if (!argv.outside || !project.isBunAvailable) return;

const devDependencyNames = Object.keys(packageJson.devDependencies ?? {});
if (devDependencyNames.length === 0) return;

// Bun validates the lockfile even with --production. This script lets Docker rewrite
// the image-local lockfile after --outside pruning, without hard-coding packages in app Dockerfiles.
const scripts = packageJson.scripts ?? {};
scripts['docker/install/prepare'] = `bun remove ${devDependencyNames.join(' ')}`;
packageJson.scripts = scripts;
console.info('Added docker/install/prepare script.');
}

function optimizeRootProps(packageJson: PackageJson): void {
delete packageJson.private;
delete packageJson.publishConfig;
Expand Down
1 change: 1 addition & 0 deletions packages/wbfy/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.playwright-cli/
.serena/
.tmp/
.wb/
__generated__/
@willbooster/
dist/
Expand Down
25 changes: 17 additions & 8 deletions packages/wbfy/src/generators/oxfmtConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,26 @@ import type { PackageConfig } from '../packageConfig.js';
import { fsUtil } from '../utils/fsUtil.js';
import { promisePool } from '../utils/promisePool.js';

import { generateToolConfigContent, normalizeToolConfigContent } from './toolConfigContent.js';

export async function generateOxfmtConfig(config: PackageConfig): Promise<void> {
return logger.functionIgnoringException('generateOxfmtConfig', async () => {
const legacyConfigPath = path.resolve(config.dirPath, '.oxfmtrc.json');
const legacyJsonConfigPath = path.resolve(config.dirPath, '.oxfmtrc.json');
const filePath = path.resolve(config.dirPath, 'oxfmt.config.ts');
await promisePool.run(() => fs.promises.rm(legacyConfigPath, { force: true }));
if (fs.existsSync(filePath)) return;
await promisePool.run(() => fsUtil.generateFile(filePath, configContent));
const existingContent = await fsUtil.readFileIgnoringError(filePath);
const desiredContent = getConfigContent(config);
const promises = [promisePool.run(() => fs.promises.rm(legacyJsonConfigPath, { force: true }))];
if (normalizeToolConfigContent(existingContent) !== normalizeToolConfigContent(desiredContent)) {
promises.push(promisePool.run(() => fsUtil.generateFile(filePath, desiredContent)));
}
await Promise.all(promises);
});
}

const configContent = `import config from '@willbooster/oxfmt-config';

export default config;
`;
function getConfigContent(config: PackageConfig): string {
return generateToolConfigContent(config, {
commonJsVariableName: 'oxfmtConfig',
packageName: '@willbooster/oxfmt-config',
toolName: 'Oxfmt',
});
}
21 changes: 14 additions & 7 deletions packages/wbfy/src/generators/oxlintConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ import { fsUtil } from '../utils/fsUtil.js';
import { promisePool } from '../utils/promisePool.js';
import { isPublishedWillboosterConfigsPackage } from '../utils/willboosterConfigsUtil.js';

import { generateToolConfigContent, normalizeToolConfigContent } from './toolConfigContent.js';

export async function generateOxlintConfig(config: PackageConfig, _rootConfig: PackageConfig): Promise<void> {
return logger.functionIgnoringException('generateOxlintConfig', async () => {
// willbooster-configs publishes config files as product code, so migration
// must not remove package-provided linter settings.
const shouldPreservePublishedLinterConfig = isPublishedWillboosterConfigsPackage(config);
const filePath = path.resolve(config.dirPath, 'oxlint.config.ts');
const existingContent = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : undefined;
const existingContent = await fsUtil.readFileIgnoringError(filePath);
const desiredContent =
shouldPreservePublishedLinterConfig && existingContent ? existingContent : getConfigContent(config);

const promises: Promise<void>[] = [];
if (!shouldPreservePublishedLinterConfig) {
Expand All @@ -33,14 +37,17 @@ export async function generateOxlintConfig(config: PackageConfig, _rootConfig: P
promisePool.run(() => fs.promises.rm(path.resolve(config.dirPath, 'eslint.config.ts'), { force: true }))
);
}
if (!existingContent) {
promises.push(promisePool.run(() => fsUtil.generateFile(filePath, configContent)));
if (normalizeToolConfigContent(existingContent) !== normalizeToolConfigContent(desiredContent)) {
promises.push(promisePool.run(() => fsUtil.generateFile(filePath, desiredContent)));
}
await Promise.all(promises);
});
}

const configContent = `import config from '@willbooster/oxlint-config';

export default config;
`;
function getConfigContent(config: PackageConfig): string {
return generateToolConfigContent(config, {
commonJsVariableName: 'oxlintConfig',
packageName: '@willbooster/oxlint-config',
toolName: 'Oxlint',
});
}
26 changes: 26 additions & 0 deletions packages/wbfy/src/generators/toolConfigContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { PackageConfig } from '../packageConfig.js';

interface ToolConfigContentOptions {
commonJsVariableName: string;
packageName: string;
toolName: string;
}

export function generateToolConfigContent(config: PackageConfig, options: ToolConfigContentOptions): string {
if (config.isEsmPackage) {
return `import config from '${options.packageName}';

export default config;
`;
}

return `// oxlint-disable unicorn/prefer-module -- ${options.toolName} only auto-discovers .ts config files, and CommonJS avoids Node typeless ESM warnings.
const ${options.commonJsVariableName} = require('${options.packageName}');

module.exports = ${options.commonJsVariableName}.default ?? ${options.commonJsVariableName};
`;
}

export function normalizeToolConfigContent(content: string | undefined): string | undefined {
return content?.trim();
}
Loading