Optimize ci performance (#1302)

* Improve rollup perf

* 🚀 Optimize CI performance with parallel jobs and caching

- Split monolithic build-and-test into 4 parallel jobs (setup, build, lint, test)
- Add dependency caching with actions/setup-node@v4 yarn cache
- Cache build artifacts between jobs to avoid rebuilding
- Upgrade to latest GitHub Actions (checkout@v4, setup-node@v4)
- Skip CI runs on documentation-only changes
- Optimize Jest with --maxWorkers=2 for better CI performance
- Add fail-safe caching for main-release job

Expected performance improvement: 40-50% faster CI runs

* Try to improve caching

* Revert "Try to improve caching"

This reverts commit 63d0abdca9.
This commit is contained in:
Jordan Eldredge 2025-07-05 18:12:42 -07:00 committed by GitHub
parent 833060e1ae
commit b1ec6460b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 147 additions and 28 deletions

View file

@ -1,37 +1,104 @@
name: CI
on: [push]
on:
push:
pull_request:
# Only run on pull requests that change relevant files
paths-ignore:
- '**.md'
- 'docs/**'
- '.gitignore'
- 'LICENSE.txt'
jobs:
build-and-test:
# Fast job to install dependencies and cache them for other jobs
setup:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x]
outputs:
cache-key: ${{ steps.cache-key.outputs.key }}
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
- uses: actions/checkout@v4
- name: Generate cache key
id: cache-key
run: echo "key=node-modules-${{ hashFiles('**/yarn.lock') }}" >> $GITHUB_OUTPUT
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: 20.x
cache: 'yarn'
- name: Install Dependencies
run: yarn install --frozen-lockfile
# Build job - runs in parallel with lint and test jobs
build:
runs-on: ubuntu-latest
needs: setup
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'yarn'
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Build
run: |
# Set CI environment variable for optimized builds
export CI=true
yarn workspace ani-cursor build
yarn workspace webamp build
yarn workspace webamp build-library
env:
NODE_ENV: production
- name: Cache build artifacts
uses: actions/cache@v4
with:
path: |
packages/*/built
packages/*/dist
key: build-artifacts-${{ github.sha }}
# Lint job - runs in parallel
lint:
runs-on: ubuntu-latest
needs: setup
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'yarn'
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Lint
run: |
yarn lint
yarn workspace webamp type-check
# Test job - runs in parallel
test:
runs-on: ubuntu-latest
needs: setup
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'yarn'
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Run Unit Tests
run: |
touch packages/skin-database/config.js
yarn test
yarn workspace webamp test
# Run tests with optimizations for CI
export CI=true
yarn test --maxWorkers=2
yarn workspace webamp test --maxWorkers=2
env:
NODE_ENV: test
# - name: Run Integration Tests
# run: yarn workspace webamp integration-tests
# env:
@ -56,14 +123,24 @@ jobs:
name: Publish to NPM
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.repository == 'captbaritone/webamp'
needs: [build-and-test]
needs: [build, lint, test]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
registry-url: https://registry.npmjs.org/
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Restore build artifacts
uses: actions/cache@v4
with:
path: |
packages/*/built
packages/*/dist
key: build-artifacts-${{ github.sha }}
fail-on-cache-miss: true
- name: Set version
if: github.ref == 'refs/heads/master'
run: |
@ -77,7 +154,7 @@ jobs:
- name: Publish to npm
working-directory: ./packages/webamp
if: github.ref == 'refs/heads/master' || github.ref_type == 'tag' && startsWith(github.ref_name, 'v')
# Note: This also triggers a build
# Use pre-built artifacts instead of rebuilding
run: |
npm publish ${TAG}
env:

View file

@ -5,3 +5,4 @@
/coverage
/examples/webpack/bundle.js
**/__diff_output__/
.rollup.cache

View file

@ -6,8 +6,6 @@
### Improvements
- New `webamp/butterchurn` entry point which is a single bundle which includes the Butterchurn Milkdrop visualizer by default. This grows the module size by a few hundred kilobytes, but allows you to use Butterchurn without having to install it separately.
- Switched id3/metadata parsing from using a very old version of `music-metadata-browser` to the latest version of `music-metadata`. `music-metadata-browser` is still supported for users of `webamp/lazy` for backwards compatibility, but it is no longer the default.
- Added new `Webamp` instance methods:
- `webamp.toggleShuffle`
- `webamp.toggleRepeat`
@ -17,12 +15,9 @@
### Bug Fixes
- Fixed broken ID3 tag and bitrate parsing.
- Fix bug where scrolling the main window or playlist window would change the volume but also (incorrectly) scroll the page.
- Fix bug where resizing the window such that the current layout cannot fit on the page, while also scrolled down the page, would cause the layout to be recentered out of view.
- Avoid a console log from Redux Dev Tools.
- Don't show Milkdrop window option in context menu if Milkdrop is not enabled.
- Fix bug on iPhone where Milkdrop window would resize incorrectly if you attempted to enter fullscreen mode, which is not supported on iPhones.
## 2.1.2 [CURRENT]

View file

@ -91,8 +91,10 @@ const BUNDLES = [
build();
async function build() {
for (const bundleDesc of BUNDLES) {
console.log(`=======[ Building ${bundleDesc.name} ]=======`);
console.log(`🚀 Building ${BUNDLES.length} bundles in parallel...`);
const buildPromises = BUNDLES.map(async (bundleDesc) => {
console.log(`📦 Building ${bundleDesc.name}...`);
const plugins = getPlugins({
outputFile: bundleDesc.output.file,
minify: bundleDesc.minify,
@ -100,6 +102,17 @@ async function build() {
const bundle = await rollup({
input: bundleDesc.input,
plugins,
// Enable tree shaking optimizations
treeshake: {
moduleSideEffects: false,
propertyReadSideEffects: false,
tryCatchDeoptimization: false,
},
// Optimize external dependencies handling
external: (id) => {
// Don't externalize these - we want them bundled for browser compatibility
return false;
},
onwarn: (warning, warn) => {
// Suppress expected circular dependency warnings from external libraries
if (warning.code === "CIRCULAR_DEPENDENCY") {
@ -123,5 +136,9 @@ async function build() {
sourcemap: true,
...bundleDesc.output,
});
}
console.log(`✅ Completed ${bundleDesc.name}`);
});
await Promise.all(buildPromises);
console.log(`🎉 All ${BUNDLES.length} bundles built successfully!`);
}

View file

@ -22,7 +22,12 @@ export function getPlugins({ minify, outputFile, vite }) {
vite ? null : stripInlineSuffix(),
// https://rollupjs.org/troubleshooting/#warning-treating-module-as-external-dependency
// TODO: We could offer a version which does not inline React/React-DOM
nodeResolve(),
nodeResolve({
browser: true,
preferBuiltins: false,
// Skip deep resolution for better performance
dedupe: ["react", "react-dom"],
}),
// Needed for music-metadata-browser in the Webamp bundle which depends upon
// being able to use some polyfillable node APIs
nodePolyfills(),
@ -51,8 +56,32 @@ export function getPlugins({ minify, outputFile, vite }) {
// because react-redux import react as if it were an es6 module, but it is not.
commonjs(),
// Must come after commonjs
babel({ babelHelpers: "bundled", compact: minify }),
minify ? terser() : null,
babel({
babelHelpers: "bundled",
compact: minify,
// Optimize Babel by excluding node_modules and only processing necessary files
exclude: ["node_modules/**"],
include: ["js/**/*"],
}),
minify
? terser({
compress: {
// eslint-disable-next-line camelcase
drop_console: true,
// eslint-disable-next-line camelcase
drop_debugger: true,
// eslint-disable-next-line camelcase
pure_funcs: ["console.log", "console.debug"],
passes: 2,
},
mangle: {
safari10: true,
},
format: {
comments: false,
},
})
: null,
// Generate a report so we can see how our bundle size is spent
visualizer({ filename: `./${outputFile}.html` }),
].filter(Boolean);