feat: package manager (and bun)
This commit is contained in:
parent
7198ad998e
commit
16934d55c9
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -117,6 +117,8 @@ dist
|
||||||
|
|
||||||
# local
|
# local
|
||||||
/yarn.lock
|
/yarn.lock
|
||||||
|
/bun.lockb
|
||||||
|
|
||||||
# package-locals
|
# package-locals
|
||||||
/packages/*/yarn.lock
|
/packages/*/yarn.lock
|
||||||
|
/packages/*/bun.lockb
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "NODE_PATH=./node_modules webpack --config ./build/webpack.config.js --mode production",
|
"build": "NODE_PATH=./node_modules webpack --config ./build/webpack.config.js --mode production",
|
||||||
"clean": "rm -rf dist node_modules yarn.lock && yarn",
|
"clean": "rm -rf dist bun.lockb && bun install",
|
||||||
"lint": "NODE_PATH=./node_modules eslint --config ./build/eslint.config.js .",
|
"lint": "NODE_PATH=./node_modules eslint --config ./build/eslint.config.js .",
|
||||||
"postversion": "cp package.json dist",
|
"postversion": "cp package.json dist",
|
||||||
"test": "npm run build && mocha -t 10000 --colors ./dist/test.js"
|
"test": "npm run build && mocha -t 10000 --colors ./dist/test.js"
|
||||||
|
|
|
@ -17,7 +17,7 @@ const debug = D('@flecks/core/commands');
|
||||||
const debugSilly = debug.extend('silly');
|
const debugSilly = debug.extend('silly');
|
||||||
const flecksRoot = normalize(FLECKS_CORE_ROOT);
|
const flecksRoot = normalize(FLECKS_CORE_ROOT);
|
||||||
|
|
||||||
export {Argument};
|
export {Argument, Option, program} from 'commander';
|
||||||
|
|
||||||
export const processCode = (child) => new Promise((resolve, reject) => {
|
export const processCode = (child) => new Promise((resolve, reject) => {
|
||||||
child.on('error', reject);
|
child.on('error', reject);
|
||||||
|
@ -45,45 +45,46 @@ export const spawnWith = (cmd, opts = {}) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (program, flecks) => {
|
export default (program, flecks) => {
|
||||||
|
const {packageManager} = flecks.get('@flecks/core/server');
|
||||||
const commands = {
|
const commands = {
|
||||||
add: {
|
add: {
|
||||||
args: [
|
args: [
|
||||||
new Argument('<fleck>>', 'fleck'),
|
new Argument('<fleck>', 'fleck'),
|
||||||
],
|
],
|
||||||
description: 'add a fleck to your application',
|
description: 'add a fleck to your application',
|
||||||
action: async (fleck, opts) => {
|
action: async (fleck, opts) => {
|
||||||
const {
|
const args = [];
|
||||||
noYarn,
|
if ('yarn' === packageManager) {
|
||||||
} = opts;
|
args.push('yarn', ['add', fleck]);
|
||||||
await processCode(
|
}
|
||||||
noYarn
|
else {
|
||||||
? spawn('npm', ['install', fleck], {stdio: 'inherit'})
|
args.push(packageManager, ['install', fleck]);
|
||||||
: spawn('yarn', ['add', fleck], {stdio: 'inherit'}),
|
}
|
||||||
);
|
args.push({stdio: 'inherit'});
|
||||||
|
await processCode(spawn(...args));
|
||||||
await Flecks.addFleckToYml(fleck);
|
await Flecks.addFleckToYml(fleck);
|
||||||
},
|
},
|
||||||
options: [
|
|
||||||
['--no-yarn', 'use npm instead of yarn'],
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
clean: {
|
clean: {
|
||||||
description: 'remove node_modules, lock file, build artifacts, then reinstall',
|
description: 'remove node_modules, lock file, build artifacts, then reinstall',
|
||||||
action: (opts) => {
|
action: (opts) => {
|
||||||
const {
|
|
||||||
noYarn,
|
|
||||||
} = opts;
|
|
||||||
rimraf.sync(join(flecksRoot, 'dist'));
|
rimraf.sync(join(flecksRoot, 'dist'));
|
||||||
rimraf.sync(join(flecksRoot, 'node_modules'));
|
rimraf.sync(join(flecksRoot, 'node_modules'));
|
||||||
if (noYarn) {
|
switch (packageManager) {
|
||||||
rimraf.sync(join(flecksRoot, 'package-lock.json'));
|
case 'yarn':
|
||||||
return spawn('npm', ['install'], {stdio: 'inherit'});
|
|
||||||
}
|
|
||||||
rimraf.sync(join(flecksRoot, 'yarn.lock'));
|
rimraf.sync(join(flecksRoot, 'yarn.lock'));
|
||||||
return spawn('yarn', [], {stdio: 'inherit'});
|
break;
|
||||||
|
case 'bun':
|
||||||
|
rimraf.sync(join(flecksRoot, 'bun.lockb'));
|
||||||
|
break;
|
||||||
|
case 'npm':
|
||||||
|
rimraf.sync(join(flecksRoot, 'package-lock.json'));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return spawn(packageManager, ['install'], {stdio: 'inherit'});
|
||||||
},
|
},
|
||||||
options: [
|
|
||||||
['--no-yarn', 'use npm instead of yarn'],
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const targets = flatten(flecks.invokeFlat('@flecks/core.targets'));
|
const targets = flatten(flecks.invokeFlat('@flecks/core.targets'));
|
||||||
|
|
|
@ -21,7 +21,9 @@ export {dump as dumpYml, load as loadYml} from 'js-yaml';
|
||||||
export {
|
export {
|
||||||
Argument,
|
Argument,
|
||||||
default as commands,
|
default as commands,
|
||||||
|
Option,
|
||||||
processCode,
|
processCode,
|
||||||
|
program,
|
||||||
spawnWith,
|
spawnWith,
|
||||||
} from './commands';
|
} from './commands';
|
||||||
export {default as Flecks} from './flecks';
|
export {default as Flecks} from './flecks';
|
||||||
|
@ -101,6 +103,10 @@ export const hooks = {
|
||||||
* Build targets to exclude from ESLint.
|
* Build targets to exclude from ESLint.
|
||||||
*/
|
*/
|
||||||
'eslint.exclude': [],
|
'eslint.exclude': [],
|
||||||
|
/**
|
||||||
|
* The package manager used for tasks.
|
||||||
|
*/
|
||||||
|
packageManager: 'npm',
|
||||||
/**
|
/**
|
||||||
* Build targets to profile with `webpack.debug.ProfilingPlugin`.
|
* Build targets to profile with `webpack.debug.ProfilingPlugin`.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import {processCode, spawnWith} from '@flecks/core/server';
|
import {processCode, spawnWith} from '@flecks/core/server';
|
||||||
|
|
||||||
export default async (cwd) => {
|
export default async (packageManager, cwd) => {
|
||||||
const code = await processCode(spawnWith(['yarn'], {cwd}));
|
const code = await processCode(spawnWith([packageManager, 'install'], {cwd}));
|
||||||
if (0 !== code) {
|
if (0 !== code) {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
return processCode(spawnWith(['yarn', 'build'], {cwd}));
|
return processCode(spawnWith([packageManager, 'run', 'build'], {cwd}));
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,39 +1,72 @@
|
||||||
import {join, normalize} from 'path';
|
import {join} from 'path';
|
||||||
|
|
||||||
import {Flecks} from '@flecks/core/server';
|
import {
|
||||||
|
dumpYml,
|
||||||
|
Flecks,
|
||||||
|
loadYml,
|
||||||
|
Option,
|
||||||
|
program,
|
||||||
|
transform,
|
||||||
|
} from '@flecks/core/server';
|
||||||
import validate from 'validate-npm-package-name';
|
import validate from 'validate-npm-package-name';
|
||||||
|
|
||||||
import build from './build';
|
import build from './build';
|
||||||
import move from './move';
|
import move, {testDestination} from './move';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
const cwd = normalize(FLECKS_CORE_ROOT);
|
(async () => {
|
||||||
|
program.argument('<app>', 'name of the app to create');
|
||||||
const create = async (flecks) => {
|
program.addOption(
|
||||||
let name = process.argv[2];
|
new Option('--package-manager <binary>', 'package manager binary')
|
||||||
const {errors} = validate(name);
|
.choices(['npm', 'bun', 'yarn'])
|
||||||
|
.default('npm'),
|
||||||
|
);
|
||||||
|
program.action(async (app, {packageManager}) => {
|
||||||
|
const flecks = await Flecks.bootstrap({
|
||||||
|
config: {
|
||||||
|
'@flecks/core': {},
|
||||||
|
'@flecks/core/server': {packageManager},
|
||||||
|
'@flecks/create-app': {},
|
||||||
|
'@flecks/fleck': {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const {errors} = validate(app);
|
||||||
if (errors) {
|
if (errors) {
|
||||||
throw new Error(`@flecks/create-app: invalid app name: ${errors.join(', ')}`);
|
throw new Error(`@flecks/create-app: invalid app name: ${errors.join(', ')}`);
|
||||||
}
|
}
|
||||||
const destination = join(cwd, name);
|
const destination = join(FLECKS_CORE_ROOT, app);
|
||||||
if (!name.startsWith('@')) {
|
if (!app.startsWith('@')) {
|
||||||
name = `@${name}/monorepo`;
|
app = `@${app}/monorepo`;
|
||||||
}
|
}
|
||||||
await move(name, join(__dirname, 'template'), destination, 'app', flecks);
|
if (!await testDestination(destination)) {
|
||||||
await build(destination);
|
const error = new Error(
|
||||||
};
|
`@flecks/create-app: destination '${destination} already exists: aborting`,
|
||||||
|
);
|
||||||
(async () => {
|
error.code = 129;
|
||||||
const flecks = await Flecks.bootstrap();
|
throw error;
|
||||||
try {
|
}
|
||||||
await create(flecks);
|
const fileTree = await move(app, join(__dirname, 'template'), 'app', flecks);
|
||||||
|
fileTree.pipe(
|
||||||
|
'build/flecks.yml',
|
||||||
|
transform((chunk, encoding, done, stream) => {
|
||||||
|
const yml = loadYml(chunk);
|
||||||
|
yml['@flecks/core/server'] = {packageManager};
|
||||||
|
stream.push(dumpYml(yml, {sortKeys: true}));
|
||||||
|
done();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
// Write the tree.
|
||||||
|
await fileTree.writeTo(destination);
|
||||||
|
await build(packageManager, destination);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(error.message);
|
console.error(error);
|
||||||
process.exitCode = 1;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
await program.parseAsync(process.argv);
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -3,11 +3,14 @@ import {
|
||||||
} from 'fs/promises';
|
} from 'fs/promises';
|
||||||
import {basename, dirname, join} from 'path';
|
import {basename, dirname, join} from 'path';
|
||||||
|
|
||||||
import {JsonStream, transform} from '@flecks/core/server';
|
import {
|
||||||
|
JsonStream,
|
||||||
|
transform,
|
||||||
|
} from '@flecks/core/server';
|
||||||
|
|
||||||
import FileTree from './tree';
|
import FileTree from './tree';
|
||||||
|
|
||||||
const testDestination = async (destination) => {
|
export const testDestination = async (destination) => {
|
||||||
try {
|
try {
|
||||||
await stat(destination);
|
await stat(destination);
|
||||||
return false;
|
return false;
|
||||||
|
@ -20,14 +23,7 @@ const testDestination = async (destination) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async (name, source, destination, type, flecks) => {
|
export default async (name, source, type, flecks) => {
|
||||||
if (!await testDestination(destination)) {
|
|
||||||
const error = new Error(
|
|
||||||
`@flecks/create-fleck: destination '${destination} already exists: aborting`,
|
|
||||||
);
|
|
||||||
error.code = 129;
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
const fileTree = await FileTree.loadFrom(source);
|
const fileTree = await FileTree.loadFrom(source);
|
||||||
// Renamed to avoid conflicts.
|
// Renamed to avoid conflicts.
|
||||||
const {files} = fileTree;
|
const {files} = fileTree;
|
||||||
|
@ -56,6 +52,5 @@ export default async (name, source, destination, type, flecks) => {
|
||||||
.forEach((path) => {
|
.forEach((path) => {
|
||||||
fileTree.pipe(path, new JsonStream.PrettyPrint());
|
fileTree.pipe(path, new JsonStream.PrettyPrint());
|
||||||
});
|
});
|
||||||
// Write the tree.
|
return fileTree;
|
||||||
await fileTree.writeTo(destination);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export {default as validate} from 'validate-npm-package-name';
|
export {default as validate} from 'validate-npm-package-name';
|
||||||
|
|
||||||
export {default as build} from './build';
|
export {default as build} from './build';
|
||||||
export {default as move} from './move';
|
export {default as move, testDestination} from './move';
|
||||||
export {default as FileTree} from './tree';
|
export {default as FileTree} from './tree';
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flecks/core": "^2.0.3",
|
"@flecks/core": "^2.0.3",
|
||||||
"@flecks/create-app": "^2.0.3",
|
"@flecks/create-app": "^2.0.3"
|
||||||
"@inquirer/prompts": "^3.3.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flecks/fleck": "^2.0.3"
|
"@flecks/fleck": "^2.0.3"
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
import {stat} from 'fs/promises';
|
import {stat} from 'fs/promises';
|
||||||
import {join, normalize} from 'path';
|
import {join} from 'path';
|
||||||
|
|
||||||
import {build, move, validate} from '@flecks/create-app/server';
|
import {
|
||||||
import {Flecks} from '@flecks/core/server';
|
build,
|
||||||
import {confirm} from '@inquirer/prompts';
|
move,
|
||||||
|
testDestination,
|
||||||
|
validate,
|
||||||
|
} from '@flecks/create-app/server';
|
||||||
|
import {Flecks, program} from '@flecks/core/server';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
const cwd = normalize(FLECKS_CORE_ROOT);
|
const checkIsMonorepo = async () => {
|
||||||
|
|
||||||
const checkIsMonorepo = async (cwd) => {
|
|
||||||
try {
|
try {
|
||||||
await stat(join(cwd, 'packages'));
|
await stat(join(FLECKS_CORE_ROOT, 'packages'));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
|
@ -24,9 +26,9 @@ const checkIsMonorepo = async (cwd) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const monorepoScope = async (cwd) => {
|
const monorepoScope = async () => {
|
||||||
try {
|
try {
|
||||||
const {name} = __non_webpack_require__(join(cwd, 'package.json'));
|
const {name} = __non_webpack_require__(join(FLECKS_CORE_ROOT, 'package.json'));
|
||||||
const [scope] = name.split('/');
|
const [scope] = name.split('/');
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
@ -38,45 +40,57 @@ const monorepoScope = async (cwd) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const target = async (name) => {
|
const target = async (fleck) => {
|
||||||
const {errors} = validate(name);
|
const {errors} = validate(fleck);
|
||||||
if (errors) {
|
if (errors) {
|
||||||
throw new Error(`@flecks/create-fleck: invalid fleck name: ${errors.join(', ')}`);
|
throw new Error(`@flecks/create-fleck: invalid fleck name: ${errors.join(', ')}`);
|
||||||
}
|
}
|
||||||
const parts = name.split('/');
|
const parts = fleck.split('/');
|
||||||
let pkg;
|
let pkg;
|
||||||
let scope;
|
let scope;
|
||||||
if (1 === parts.length) {
|
if (1 === parts.length) {
|
||||||
pkg = name;
|
pkg = fleck;
|
||||||
if (await checkIsMonorepo(cwd)) {
|
if (await checkIsMonorepo()) {
|
||||||
scope = await monorepoScope(cwd);
|
scope = await monorepoScope();
|
||||||
}
|
}
|
||||||
return [scope, pkg];
|
return [scope, pkg];
|
||||||
}
|
}
|
||||||
return parts;
|
return parts;
|
||||||
};
|
};
|
||||||
|
|
||||||
const create = async (flecks) => {
|
(async () => {
|
||||||
const isMonorepo = await checkIsMonorepo(cwd);
|
program.argument('<fleck>', 'name of the fleck to create');
|
||||||
const [scope, pkg] = await target(process.argv[2]);
|
program.option('--no-add', 'do not add an entry to `build/flecks.yml`');
|
||||||
const path = scope && isMonorepo ? join(cwd, 'packages') : cwd;
|
program.action(async (fleck, {add}) => {
|
||||||
|
try {
|
||||||
|
const flecks = await Flecks.bootstrap();
|
||||||
|
const {packageManager} = flecks.get('@flecks/core/server');
|
||||||
|
const isMonorepo = await checkIsMonorepo();
|
||||||
|
const [scope, pkg] = await target(fleck);
|
||||||
const name = [scope, pkg].filter((e) => !!e).join('/');
|
const name = [scope, pkg].filter((e) => !!e).join('/');
|
||||||
const destination = join(path, pkg);
|
const destination = join(
|
||||||
await move(name, join(__dirname, 'template'), destination, 'fleck', flecks);
|
join(...[FLECKS_CORE_ROOT].concat(isMonorepo ? ['packages'] : [])),
|
||||||
await build(destination);
|
pkg,
|
||||||
if (isMonorepo && await confirm({message: 'Add fleck to `build/flecks.yml`?'})) {
|
);
|
||||||
|
if (!await testDestination(destination)) {
|
||||||
|
const error = new Error(
|
||||||
|
`@flecks/create-fleck: destination '${destination} already exists: aborting`,
|
||||||
|
);
|
||||||
|
error.code = 129;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
const fileTree = await move(name, join(__dirname, 'template'), 'fleck', flecks);
|
||||||
|
// Write the tree.
|
||||||
|
await fileTree.writeTo(destination);
|
||||||
|
await build(packageManager, destination);
|
||||||
|
if (isMonorepo && add) {
|
||||||
await Flecks.addFleckToYml(name, pkg);
|
await Flecks.addFleckToYml(name, pkg);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const flecks = await Flecks.bootstrap();
|
|
||||||
try {
|
|
||||||
await create(flecks);
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(error.message);
|
console.error('Creation failed:', error);
|
||||||
process.exitCode = 1;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
await program.parseAsync(process.argv);
|
||||||
})();
|
})();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user