Skip to content

Commit

Permalink
Build packages with tsup (#2120)
Browse files Browse the repository at this point in the history
This changes all packages to be built with `tsup`, instead of SWC.
`tsup` uses `esbuild` under the hood, so performance should be
comparable.

More context here: MetaMask/utils#144.
  • Loading branch information
Mrtenz committed Feb 23, 2024
1 parent df74d38 commit b4b8bc0
Show file tree
Hide file tree
Showing 80 changed files with 1,660 additions and 956 deletions.
90 changes: 11 additions & 79 deletions .github/workflows/build-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,43 +37,14 @@ jobs:
id: workspace-package-names
run: |
{
echo "test-workspace-package-names=$(yarn workspaces filter --include 'packages/*' --exclude 'packages/examples' --json)"
echo "e2e-workspace-package-names=$(yarn workspaces filter --include 'packages/examples/packages/**' --exclude 'packages/examples/packages/invoke-snap' --json)"
echo "all-workspace-package-names=$(yarn workspaces filter --include '{.,packages/**}' --exclude 'packages/snaps-cli/test/snap' --json)"
echo "test-workspace-package-names=$(yarn workspaces filter list --include 'packages/*' --exclude 'packages/examples' --json)"
echo "e2e-workspace-package-names=$(yarn workspaces filter list --include 'packages/examples/packages/**' --exclude 'packages/examples/packages/invoke-snap' --json)"
echo "all-workspace-package-names=$(yarn workspaces filter list --include '{.,packages/**}' --exclude 'packages/snaps-cli/test/snap' --json)"
} >> "$GITHUB_OUTPUT"
shell: bash

build-source:
name: Build source
runs-on: ubuntu-latest
needs: prepare
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
cache: yarn
- run: yarn --immutable --immutable-cache
- name: Build source
run: yarn build:source
- name: Cache build files
uses: actions/cache@v3
with:
path: |
packages/*/dist/esm
packages/*/dist/cjs
key: build-source-${{ runner.os }}-${{ github.sha }}
- name: Require clean working directory
shell: bash
run: |
if ! git diff --exit-code; then
echo "Working tree dirty at end of job"
exit 1
fi
build-types:
name: Build types
build:
name: Build
runs-on: ubuntu-latest
needs: prepare
steps:
Expand All @@ -84,14 +55,16 @@ jobs:
node-version-file: '.nvmrc'
cache: yarn
- run: yarn --immutable --immutable-cache
- name: Build
run: yarn build:ci
- name: Build types
run: yarn build:types
- name: Cache build files
uses: actions/cache@v3
with:
path: |
packages/*/dist/types
key: build-types-${{ runner.os }}-${{ github.sha }}
packages/*/dist
key: build-source-${{ runner.os }}-${{ github.sha }}
- name: Require clean working directory
shell: bash
run: |
Expand All @@ -100,38 +73,6 @@ jobs:
exit 1
fi
post-build:
name: Post-build
runs-on: ubuntu-latest
needs:
- build-source
- build-types
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
cache: yarn
- run: yarn --immutable --immutable-cache
- name: Restore build files
uses: actions/cache@v3
with:
path: |
packages/*/dist/esm
packages/*/dist/cjs
key: build-source-${{ runner.os }}-${{ github.sha }}
fail-on-cache-miss: true
- name: Restore types files
uses: actions/cache@v3
with:
path: |
packages/*/dist/types
key: build-types-${{ runner.os }}-${{ github.sha }}
fail-on-cache-miss: true
- name: Post-build
run: yarn build:post-tsc:ci

build-simulator:
name: Build "@metamask/snaps-simulator"
runs-on: ubuntu-latest
Expand Down Expand Up @@ -318,8 +259,7 @@ jobs:
runs-on: ubuntu-latest
needs:
- prepare
- build-source
- build-types
- build
strategy:
fail-fast: false
matrix:
Expand All @@ -343,17 +283,9 @@ jobs:
uses: actions/cache@v3
with:
path: |
packages/*/dist/esm
packages/*/dist/cjs
packages/*/dist
key: build-source-${{ runner.os }}-${{ github.sha }}
fail-on-cache-miss: true
- name: Restore types files
uses: actions/cache@v3
with:
path: |
packages/*/dist/types
key: build-types-${{ runner.os }}-${{ github.sha }}
fail-on-cache-miss: true
- run: yarn --immutable --immutable-cache
- name: Build snap
run: yarn workspace ${{ matrix.package-name }} run build
Expand Down
184 changes: 156 additions & 28 deletions .yarn/plugins/local/plugin-workspaces-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ module.exports = {
const { Command, Option, UsageError } = require('clipanion');
const { isString, isBoolean } = require('typanion');

class FilterCommand extends BaseCommand {
static paths = [['workspaces', 'filter']];
class FilterListCommand extends BaseCommand {
static paths = [['workspaces', 'filter', 'list']];

static usage = Command.Usage({
description: 'Filter workspaces',
Expand All @@ -18,11 +18,11 @@ module.exports = {
examples: [
[
`List workspaces based on a glob pattern`,
`yarn workspaces filter --include "packages/*"`,
`yarn workspaces filter list --include "packages/*"`,
],
[
'Exclude workspaces based on a glob pattern',
`yarn workspaces filter --exclude "packages/*/foo"`,
`yarn workspaces filter list --exclude "packages/*/foo"`,
],
],
});
Expand All @@ -42,6 +42,34 @@ module.exports = {
validator: isBoolean,
});

/**
* List the names of the workspaces. If `--json` is set, the names will be
* printed as a JSON array.
*
* @param {Workspace[]} workspaces
* @param {Configuration} configuration
* @returns {Promise<number>}
*/
async list(workspaces, configuration) {
const report = await StreamReport.start(
{
configuration,
json: this.json,
stdout: this.context.stdout,
},
async (report) => {
for (const workspace of workspaces) {
report.reportInfo(null, workspace.relativeCwd);
}

const result = workspaces.map((workspace) => workspace.manifest.raw.name);
report.reportJson(result);
},
);

return report.exitCode();
}

async execute() {
// Note: We have to import `minimatch` here, because Yarn will always
// load the plugin, even if the command is not used, and `minimatch`
Expand All @@ -61,37 +89,137 @@ module.exports = {
);
}

const report = await StreamReport.start(
{
configuration,
json: this.json,
stdout: this.context.stdout,
},
async (report) => {
const filteredWorkspaces = workspaces.filter((workspace) => {
return (
(!this.include ||
minimatch(workspace.relativeCwd, this.include)) &&
(!this.exclude ||
!minimatch(workspace.relativeCwd, this.exclude))
);
});

for (const workspace of filteredWorkspaces) {
report.reportInfo(null, workspace.relativeCwd);
}
const filteredWorkspaces = workspaces.filter((workspace) => {
return (
(!this.include ||
minimatch(workspace.relativeCwd, this.include)) &&
(!this.exclude ||
!minimatch(workspace.relativeCwd, this.exclude))
);
});

const result = filteredWorkspaces.map((workspace) => workspace.manifest.raw.name);
report.reportJson(result);
},
return await this.list(filteredWorkspaces, configuration);
}
}

class FilterRunCommand extends BaseCommand {
static paths = [['workspaces', 'filter']];

static usage = Command.Usage({
description: 'Filter workspaces',
details: `
This command will run a command in workspaces based on the given
criteria. It's like \`yarn workspaces foreach\` but on steroids.
`,
examples: [
[
`List workspaces based on a glob pattern`,
`yarn workspaces filter --include "packages/*" run build`,
],
[
'Exclude workspaces based on a glob pattern',
`yarn workspaces filter --exclude "packages/*/foo" run build`,
],
],
});

commandName = Option.String({
required: true,
description: `The name of the command to run`,
validator: isString,
});

args = Option.Proxy({
required: false,
});

parallel = Option.Boolean(`--parallel`, {
default: false,
description: `Run the commands in parallel`,
validator: isBoolean,
});

topological = Option.Boolean(`--topological`, false, {
description: `Run the commands in topological order`,
validator: isBoolean,
});

include = Option.String('--include', {
description: `List workspaces based on a glob pattern`,
validator: isString,
});

exclude = Option.String('--exclude', {
description: `Exclude workspaces based on a glob pattern`,
validator: isString,
});

noPrivate = Option.Boolean(`--no-private`, false, {
description: `Exclude private workspaces`,
validator: isBoolean,
});

/**
* Run the given command on the workspaces.
*
* @param workspaces - The workspaces to run the command on.
* @param commandName - The name of the command to run.
* @param args - The arguments to pass to the command.
* @return {Promise<void>}
*/
async run(workspaces, commandName, args) {
let extraArgs = [];
if (this.parallel) {
extraArgs.push('--parallel');
}

if (this.topological) {
extraArgs.push('--topological');
extraArgs.push('--topological-dev');
}

const includes = workspaces.map((workspace) => workspace.manifest.name)
.flatMap(({ scope, name }) => ['--include', `@${scope}/${name}`]);

await this.cli.run(['workspaces', 'foreach', '--verbose', ...includes, ...extraArgs, commandName, ...args], this.context);
}

async execute() {
// Note: We have to import `minimatch` here, because Yarn will always
// load the plugin, even if the command is not used, and `minimatch`
// may not be installed.
const { minimatch } = await import('minimatch');

const configuration = await Configuration.find(
this.context.cwd,
this.context.plugins,
);
const { project } = await Project.find(configuration, this.context.cwd);
const { workspaces } = project;

return report.exitCode();
if (!this.include && !this.exclude) {
throw new UsageError(
`This command requires at least one of --include or --exclude to be specified.`,
);
}

const filteredWorkspaces = workspaces.filter((workspace) => {
return (
(!this.include ||
minimatch(workspace.relativeCwd, this.include)) &&
(!this.exclude ||
!minimatch(workspace.relativeCwd, this.exclude))
);
}).filter((workspace) => {
return !this.noPrivate || !workspace.manifest.private;
});

return await this.run(filteredWorkspaces, this.commandName, this.args);
}
}

return {
commands: [FilterCommand],
commands: [FilterListCommand, FilterRunCommand],
};
},
};
Loading

0 comments on commit b4b8bc0

Please sign in to comment.