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: support pnpm workspaces #160

Merged
merged 7 commits into from
Dec 22, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/rotten-buses-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"bob-the-bundler": minor
---

took workspace from `pnpm-workspace.yaml`
throw an error in case existing both `pnpm-workspace.yaml` and `package.json#workspaces` fields
add `execa` as dependency
cleanup unused deps
n1ru4l marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ You can add a `bob` key to each `package.json`.

**Disable bob for a single package**

```js
```jsonc
{
"name": "graphql-lfg",
"bob": false // exclude a single package from all things bob related
Expand All @@ -33,7 +33,7 @@ You can add a `bob` key to each `package.json`.

**Disable build for a single package**

```js
```json
{
"name": "graphql-lfg",
"bob": {
Expand All @@ -44,7 +44,7 @@ You can add a `bob` key to each `package.json`.

**Disable check for a single package**

```js
```json
{
"name": "graphql-lfg",
"bob": {
Expand All @@ -55,7 +55,7 @@ You can add a `bob` key to each `package.json`.

**Disable check for a single export in a package**

```js
```json
{
"name": "graphql-lfg",
"bob": {
Expand All @@ -69,11 +69,9 @@ You can add a `bob` key to each `package.json`.
## Usage

```bash

$ bob build
$ bob check

# only use this command if you know the secret sauce
$ bob runify

```
16 changes: 4 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,17 @@
"jest-resolver.js"
],
"dependencies": {
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^13.3.0",
"@vercel/ncc": "^0.36.0",
"builtins": "^5.0.1",
"consola": "^2.15.3",
"cross-spawn": "^7.0.3",
"dependency-graph": "^0.11.0",
"execa": "5.1.1",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execa imported and should be present in dependencies

"fs-extra": "^10.1.0",
"globby": "^11.0.0",
"js-yaml": "^4.1.0",
"lodash.get": "^4.4.2",
"minimatch": "^5.1.0",
"mkdirp": "^1.0.4",
"p-limit": "^3.1.0",
"param-case": "^3.0.4",
"resolve.exports": "^1.1.0",
"rollup": "^2.75.6",
"rollup-plugin-generate-package-json": "^3.2.0",
"rollup-plugin-typescript2": "^0.34.0",
Comment on lines -25 to -42
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems bunch of these dependencies were nowhere used

"tslib": "^2.0.0",
"tsup": "^6.5.0",
"yargs": "^17.5.1",
Expand All @@ -55,18 +48,17 @@
},
"devDependencies": {
"@actions/core": "1.9.1",
"@changesets/cli": "2.24.4",
"@changesets/changelog-github": "0.4.6",
"@changesets/cli": "2.24.4",
"@jest/types": "28.1.3",
"@types/cross-spawn": "6.0.2",
"@types/fs-extra": "9.0.13",
"@types/jest": "28.1.8",
"@types/js-yaml": "4.0.5",
"@types/lodash.get": "4.4.7",
"@types/minimatch": "3.0.5",
"@types/mkdirp": "1.0.2",
"@types/node": "16.11.58",
"@types/yargs": "15.0.14",
"execa": "5.1.1",
"jest": "28.1.3",
"rimraf": "3.0.2",
"ts-jest": "28.0.8",
Expand Down
16 changes: 6 additions & 10 deletions src/commands/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const presetFieldsESM = {
},
};

async function applyESMModuleTransform(cwd: string) {
async function applyESMModuleTransform(cwd = process.cwd()) {
const filePaths = await globby("**/*.ts", {
cwd,
absolute: true,
Expand Down Expand Up @@ -108,26 +108,22 @@ export const bootstrapCommand = createCommand<{}, {}>(() => {
return yargs.options({});
},
async handler() {
const cwd = process.cwd();
const rootPackageJSON = await getRootPackageJSON(cwd);
const workspaces = getWorkspaces(rootPackageJSON);
const rootPackageJSON = await getRootPackageJSON();
const workspaces = await getWorkspaces(rootPackageJSON);
const isSinglePackage = workspaces === null;

// Make sure all modules are converted to ESM

if (isSinglePackage) {
await applyESMModuleTransform(cwd);
await applyESMModuleTransform();
await applyPackageJSONPresetConfig(
path.join(cwd, "package.json"),
path.join(process.cwd(), "package.json"),
rootPackageJSON
);
return;
}

const workspacePackagePaths = await getWorkspacePackagePaths(
cwd,
workspaces
);
const workspacePackagePaths = await getWorkspacePackagePaths(workspaces);

await Promise.all(
workspacePackagePaths.map((packagePath) =>
Expand Down
32 changes: 13 additions & 19 deletions src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface PackageInfo {
}

/**
* A list of files that we don't need need within the published package.
* A list of files that we don't need within the published package.
* Also known as test files :)
* This list is derived from scouting various of our repositories.
*/
Expand Down Expand Up @@ -56,17 +56,14 @@ function typeScriptCompilerOptions(
};
}

function compilerOptionsToArgs(
options: Record<string, unknown>
): Array<string> {
const args: Array<string> = [];
for (const [key, value] of Object.entries(options)) {
args.push(`--${key}`, `${value}`);
}
return args;
function compilerOptionsToArgs(options: Record<string, unknown>): string[] {
return Object.entries(options).flatMap(([key, value]) => [
`--${key}`,
`${value}`,
]);
Comment on lines -59 to +63
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just for better readability

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the former has better readability for me 😁

}

function assertTypeScriptBuildResult(result: execa.ExecaReturnValue<string>) {
function assertTypeScriptBuildResult(result: execa.ExecaReturnValue) {
if (result.exitCode !== 0) {
console.log("TypeScript compiler exited with non-zero exit code.");
console.log(result.stdout);
Expand Down Expand Up @@ -121,8 +118,8 @@ export const buildCommand = createCommand<
},
async handler({ incremental }) {
const cwd = process.cwd();
const rootPackageJSON = await getRootPackageJSON(cwd);
const workspaces = getWorkspaces(rootPackageJSON);
const rootPackageJSON = await getRootPackageJSON();
const workspaces = await getWorkspaces(rootPackageJSON);
const isSinglePackage = workspaces === null;

if (isSinglePackage) {
Expand Down Expand Up @@ -151,10 +148,7 @@ export const buildCommand = createCommand<
}

const limit = pLimit(4);
const workspacePackagePaths = await getWorkspacePackagePaths(
cwd,
workspaces
);
const workspacePackagePaths = await getWorkspacePackagePaths(workspaces);

const packageInfoList: PackageInfo[] = await Promise.all(
workspacePackagePaths.map((packagePath) =>
Expand Down Expand Up @@ -392,7 +386,7 @@ function rewritePackageJson(pkg: Record<string, any>, typesOnly: boolean) {
];

fields.forEach((field) => {
if (typeof pkg[field] !== "undefined") {
if (pkg[field] !== undefined) {
newPkg[field] = pkg[field];
}
});
Expand Down Expand Up @@ -461,7 +455,7 @@ export function validatePackageJson(
// If the package has NO binary we need to check the exports map.
// a package should either
// 1. have a bin property
// 2. have a exports property
// 2. have an exports property
// 3. have an exports and bin property
if (Object.keys(pkg.bin ?? {}).length > 0) {
if (opts.includesCommonJS === true) {
Expand Down Expand Up @@ -499,7 +493,7 @@ export function validatePackageJson(
expect("typings", presetFieldsESM.typings);
expect("typescript.definition", presetFieldsESM.typescript.definition);

// For now we enforce a top level exports property
// For now, we enforce a top level exports property
expect("exports['.']", presetFieldsESM.exports["."]);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/commands/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export const checkCommand = createCommand<{}, {}>((api) => {
},
async handler() {
const cwd = process.cwd();
const rootPackageJSON = await getRootPackageJSON(cwd);
const workspaces = getWorkspaces(rootPackageJSON);
const rootPackageJSON = await getRootPackageJSON();
const workspaces = await getWorkspaces(rootPackageJSON);
const isSinglePackage = workspaces === null;

let checkConfigs: Array<{
Expand All @@ -55,7 +55,7 @@ export const checkCommand = createCommand<{}, {}>((api) => {
packageJSON: rootPackageJSON,
});
} else {
const workspacesPaths = await getWorkspacePackagePaths(cwd, workspaces);
const workspacesPaths = await getWorkspacePackagePaths(workspaces);
const limit = pLimit(20);
await Promise.all(
workspacesPaths.map((workspacePath) =>
Expand Down
33 changes: 11 additions & 22 deletions src/commands/runify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ async function compile(
}
: {},
});

return;
}

Expand All @@ -297,25 +296,15 @@ async function compile(
});

await fs.mkdirp(join(cwd, "dist"));
await Promise.all(
[
fs.writeFile(join(cwd, "dist/index.js"), code, {
encoding: "utf-8",
}),
fs.writeFile(join(cwd, "dist/index.js.map"), map, {
encoding: "utf-8",
}),
].concat(
Object.keys(assets).map(async (filepath) => {
if (filepath.endsWith("package.json")) {
return Promise.resolve();
}
await fs.ensureDir(dirname(join(cwd, "dist", filepath)), {});
await fs.writeFile(
join(cwd, "dist", filepath),
assets[filepath].source
);
})
)
);
await Promise.all([
fs.writeFile(join(cwd, "dist/index.js"), code, "utf8"),
fs.writeFile(join(cwd, "dist/index.js.map"), map, "utf8"),
...Object.keys(assets).map(async (filepath) => {
if (filepath.endsWith("package.json")) {
return;
}
await fs.ensureDir(dirname(join(cwd, "dist", filepath)), {});
await fs.writeFile(join(cwd, "dist", filepath), assets[filepath].source);
}),
]);
}
3 changes: 0 additions & 3 deletions src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
declare module 'rollup-plugin-generate-package-json';
declare module 'rollup-plugin-auto-external';
declare module 'builtins';
Comment on lines -1 to -3
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does I was right that they are unused?

declare module '@vercel/ncc';
2 changes: 1 addition & 1 deletion src/utils/get-root-package-json.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import globby from "globby";
import * as fse from "fs-extra";

export async function getRootPackageJSON(cwd: string) {
export async function getRootPackageJSON(cwd = process.cwd()) {
const [rootPackageJSONPath] = await globby("package.json", {
cwd,
absolute: true,
Expand Down
4 changes: 2 additions & 2 deletions src/utils/get-workspace-package-paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import path from "path";
import { buildArtifactDirectories } from "../constants";

export async function getWorkspacePackagePaths(
cwd: string,
workspaces: Array<string>
workspaces: string[],
cwd = process.cwd()
) {
const packageJSONPaths = await globby(
workspaces
Expand Down
24 changes: 21 additions & 3 deletions src/utils/get-workspaces.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import path from "node:path";
import zod from "zod";
import fse from "fs-extra";
import jsYaml from "js-yaml";

const WorkspaceModel = zod.optional(
zod.union([
Expand All @@ -10,10 +13,25 @@ const WorkspaceModel = zod.optional(
])
);

export function getWorkspaces(
export async function getWorkspaces(
packageJSON: Record<string, unknown>
): Array<string> | null {
const result = WorkspaceModel.parse(packageJSON.workspaces);
): Promise<string[] | null> {
let result = WorkspaceModel.parse(packageJSON.workspaces);

const pnpmWorkspacePath = path.join(process.cwd(), "pnpm-workspace.yaml");
const isPnpmWorkspace = await fse.pathExists(pnpmWorkspacePath);

if (isPnpmWorkspace) {
if (result) {
throw new Error(
"Both `pnpm-workspace.yaml` and `package.json#workspaces` are not supported. Remove `package.json#workspaces` field."
);
}

result = jsYaml.load(await fse.readFile(pnpmWorkspacePath, "utf8")) as {
packages?: string[];
};
}
Comment on lines +21 to +34
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here magic happens and I think it is better place to validate it in getWorkspaces than validatePackageJson

if (result == null) {
return null;
}
Expand Down
4 changes: 2 additions & 2 deletions src/utils/rewrite-code-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import * as path from "path";
function isFolderSync(path: string) {
try {
return fse.statSync(path).isDirectory();
} catch (e) {
} catch {
return false;
}
}

function rewriteSourceValue(sourceValue: string, relativeDirname: string) {
if (sourceValue.startsWith(".") && sourceValue.endsWith(".js") === false) {
if (sourceValue.startsWith(".") && !sourceValue.endsWith(".js")) {
const targetPath = path.resolve(relativeDirname, sourceValue);
// If the target path is a folder, we need to import from the index.js file
if (isFolderSync(targetPath)) {
Expand Down