-
-
Notifications
You must be signed in to change notification settings - Fork 8
Feat treeshaking: Centralize js dependency management #243
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
base: main
Are you sure you want to change the base?
Changes from all commits
3fddc7e
b62bafd
db4ffd2
c06c110
78eefb1
a499d44
242e3c2
099e292
ada2285
cabc35c
b1f2ae0
7d815a5
a7c769e
fcf8003
c73d27b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,49 @@ | ||
| version: 2 | ||
| updates: | ||
| - package-ecosystem: npm | ||
| directory: "/" | ||
| schedule: | ||
| interval: daily | ||
| time: "03:00" | ||
| open-pull-requests-limit: 10 | ||
| - package-ecosystem: "github-actions" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" | ||
| # Monitor jinks' own dependencies | ||
| - package-ecosystem: "npm" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" | ||
| open-pull-requests-limit: 10 | ||
| labels: | ||
| - "dependencies" | ||
| - "jinks" | ||
| commit-message: | ||
| prefix: "chore" | ||
| include: "scope" | ||
|
|
||
| # Monitor generated-app dependencies in config/ | ||
| - package-ecosystem: "npm" | ||
| directory: "/config" | ||
| schedule: | ||
| interval: "weekly" | ||
| versioning-strategy: increase | ||
| open-pull-requests-limit: 10 | ||
| labels: | ||
| - "dependencies" | ||
| - "generated-apps" | ||
| - "registry" | ||
| commit-message: | ||
| prefix: "chore" | ||
| include: "scope" | ||
| # Group updates for better PR management | ||
| groups: | ||
| ui-frameworks: | ||
| patterns: | ||
| - "@picocss/pico" | ||
| - "@teipublisher/pb-components" | ||
| validation: | ||
| patterns: | ||
| - "ajv*" | ||
| testing: | ||
| patterns: | ||
| - "cypress*" | ||
| pull-request-branch-name: | ||
| separator: "/" | ||
|
|
||
| # Monitor GitHub Actions | ||
| - package-ecosystem: "github-actions" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| name: Sync Dependencies | ||
|
|
||
| on: | ||
| pull_request: | ||
| paths: | ||
| - 'package.json' | ||
| - 'package-lock.json' | ||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| sync: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '24' | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci | ||
|
|
||
| - name: Validate dependencies (check if sync needed) | ||
| id: validate | ||
| continue-on-error: true | ||
| run: npm run validate:dependencies | ||
|
|
||
| - name: Sync shared dependencies | ||
| if: steps.validate.outcome == 'failure' | ||
| run: npm run sync:dependencies | ||
|
|
||
| - name: Update package-lock.json | ||
| if: steps.validate.outcome == 'failure' | ||
| working-directory: config | ||
| run: npm install --package-lock-only | ||
|
|
||
| - name: Check if package.json changed | ||
| id: package_changed | ||
| if: steps.validate.outcome == 'failure' | ||
| run: | | ||
| if ! git diff --quiet config/package.json 2>/dev/null; then | ||
| echo "changed=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "changed=false" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Commit updates | ||
| if: steps.package_changed.outputs.changed == 'true' | ||
| run: | | ||
| git config --local user.email "eeditiones-bot@users.noreply.github.com" | ||
| git config --local user.name "eeditiones-bot" | ||
| git add config/package.json config/package-lock.json | ||
| git commit -m "chore: sync shared dependencies from root package.json" | ||
| git push origin HEAD:${{ github.event.pull_request.head.ref }} | ||
|
|
||
| - name: Validate dependencies (final check) | ||
| run: npm run validate:dependencies |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,241 @@ | ||
| # Generated App Dependencies Registry | ||
|
|
||
| This directory contains the dependency registry for all generated TEI Publisher applications created by jinks. | ||
|
|
||
| ## Purpose | ||
|
|
||
| The `package.json` file in this directory serves as the **single source of truth** for all dependencies used by generated applications. This ensures: | ||
|
|
||
| - ✅ Consistent dependency versions across all generated apps | ||
| - ✅ Automated dependency updates via Dependabot | ||
| - ✅ Centralized management of CDN URLs | ||
| - ✅ Version synchronization with jinks' own dependencies | ||
|
|
||
| ## Structure | ||
|
|
||
| ### `package.json` | ||
|
|
||
| Standard npm `package.json` format with two custom fields: | ||
|
|
||
| #### Standard Fields | ||
|
|
||
| - **`dependencies`**: Production dependencies for generated apps | ||
| - **`devDependencies`**: Development dependencies (testing, validation, etc.) | ||
|
|
||
| #### Custom `jinks` Field | ||
|
|
||
| The `jinks` field contains metadata specific to jinks templating: | ||
|
|
||
| ```json | ||
| { | ||
| "jinks": { | ||
| "cdn": { | ||
| "@jinntec/fore": { | ||
| "base": "https://cdn.jsdelivr.net/npm/@jinntec/fore", | ||
| "bundle": "@{{version}}/dist/fore.js", | ||
| "css": "@{{version}}/resources/fore.css" | ||
| } | ||
| }, | ||
| "overrides": { | ||
| "base10": { | ||
| "@jinntec/fore": "^2.8.0" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| - **`cdn`**: CDN URL templates for packages loaded from CDN. The `{{version}}` placeholder is replaced with the actual version from dependencies (or override if present). Each package can define multiple asset types (e.g., `bundle`, `css`). The CDN map keys are constructed as `{package-name}-{asset-type}`. | ||
| - **`overrides`**: Profile-specific version overrides. When a profile needs a different version than the default, add it here. The generator checks active profiles in order and uses the first matching override. Example: | ||
| ```json | ||
| "overrides": { | ||
| "legacy-forms": { | ||
| "@jinntec/fore": "^2.0.0" | ||
| }, | ||
| "static": { | ||
| "@jinntec/fore": "^2.0.0" | ||
| } | ||
| } | ||
| ``` | ||
| If multiple profiles have overrides for the same package, the first profile in the active profiles list takes precedence. | ||
|
|
||
| ## How It Works | ||
|
|
||
| ### 1. Dependency Loading | ||
|
|
||
| When jinks generates an application: | ||
|
|
||
| 1. `modules/generator.xql` loads `config/package.json` | ||
| 2. CDN URLs are pre-computed using `config:cdn-url()` function | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are these parameterized? So load jinn-tap from http://localhost:5174, jinks from resources/scripts and pb-components from CDN
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, but the current integration with |
||
| 3. Dependencies and CDN URLs are added to the template context as `$dependencies` and `$cdn` | ||
|
|
||
| ### 2. Template Usage | ||
|
|
||
| Templates access dependencies via the context. CDN map keys are constructed as `{package-name}-{asset-type}` (e.g., `@teipublisher/pb-components-bundle`, `fore-bundle`, `swagger-ui-css`). | ||
|
|
||
| **Important**: Always use function call syntax for map key access: `$cdn?('key')` instead of `$cdn?key`. This ensures consistency and works correctly with all key names, including those with special characters. | ||
|
|
||
| ```html | ||
| <!-- Use CDN URL from dependencies --> | ||
| [% if exists($cdn?('fore-bundle')) %] | ||
| <script type="module" src="[[ $cdn?('fore-bundle') ]]"></script> | ||
| [% elif exists($cdn?('@teipublisher/pb-components-bundle')) %] | ||
| <script type="module" src="[[ $cdn?('@teipublisher/pb-components-bundle') ]]"></script> | ||
| [% else %] | ||
| <!-- Fallback to hardcoded URL --> | ||
| <script type="module" src="https://cdn.jsdelivr.net/npm/@jinntec/fore@2.0.0/dist/fore.js"></script> | ||
| [% endif %] | ||
| ``` | ||
|
|
||
| **Styles Array Processing**: The `styles` array in profile `config.json` files is automatically processed to replace hardcoded CDN URLs with templated versions from `config/package.json`. | ||
|
|
||
| ### 3. Version Synchronization | ||
|
|
||
| Shared dependencies (used by both jinks and generated apps) are automatically synced: | ||
|
|
||
| - **Sync Script**: `scripts/sync-dependencies.js` finds shared dependencies and syncs versions from root `package.json` to `config/package.json` | ||
| - **GitHub Action**: `.github/workflows/sync-dependencies.yml` runs the sync script when root `package.json` changes | ||
| - **Dependabot**: Monitors both root and `config/package.json` for updates | ||
|
|
||
| ### 4. Automated Updates | ||
|
|
||
| - **Dependabot** creates PRs for dependency updates in `config/package.json` | ||
| - When a PR updates `config/package.json`, the new versions are automatically used in generated apps | ||
| - CDN URLs in templates automatically use the updated versions | ||
|
|
||
| ## Managing Dependencies | ||
|
|
||
| ### Adding a New Dependency | ||
|
|
||
| 1. Add the package to `config/package.json`: | ||
| ```json | ||
| { | ||
| "dependencies": { | ||
| "new-package": "^1.0.0" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 2. If it's loaded from CDN, add CDN URL template: | ||
| ```json | ||
| { | ||
| "jinks": { | ||
| "cdn": { | ||
| "new-package": { | ||
| "base": "https://cdn.jsdelivr.net/npm/new-package", | ||
| "bundle": "@{{version}}/dist/bundle.js", | ||
| "css": "@{{version}}/dist/styles.css" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 3. Update templates to use the CDN map. The key format is `{package-name}-{asset-type}`. Always use function call syntax for consistency: | ||
| ```html | ||
| [% if exists($cdn?('new-package-bundle')) %] | ||
| <script type="module" src="[[ $cdn?('new-package-bundle') ]]"></script> | ||
| [% endif %] | ||
| ``` | ||
|
|
||
| For packages with special characters (like `@`), also use function call syntax: | ||
| ```html | ||
| [% if exists($cdn?('@scope/package-bundle')) %] | ||
| <script type="module" src="[[ $cdn?('@scope/package-bundle') ]]"></script> | ||
| [% endif %] | ||
| ``` | ||
|
|
||
| 4. The CDN map is automatically built by `modules/generator.xql` from the `jinks.cdn` configuration. | ||
|
|
||
| ### Updating Versions | ||
|
|
||
| - **Manual**: Edit `config/package.json` directly | ||
| - **Automated**: Dependabot will create PRs for updates | ||
| - **Shared deps**: Run `npm run sync:dependencies` to sync from root `package.json` | ||
|
|
||
| ### Profile-Specific Overrides | ||
|
|
||
| If a profile needs a different version than the default: | ||
|
|
||
| 1. Add override to `config/package.json`: | ||
| ```json | ||
| { | ||
| "jinks": { | ||
| "overrides": { | ||
| "profile-name": { | ||
| "package-name": "^different-version" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 2. The generator automatically applies overrides when building CDN URLs and generating `package.json` | ||
|
|
||
| 3. Overrides are checked in profile order - first matching override wins | ||
|
|
||
| 4. When Dependabot updates the base version, overrides are preserved (profiles continue using their specified versions) | ||
|
|
||
| ### Validating Dependencies | ||
|
|
||
| Run the validation script to check for issues: | ||
|
|
||
| ```bash | ||
| npm run validate:dependencies | ||
| ``` | ||
|
|
||
| This checks: | ||
| - Shared dependencies match between root and config | ||
| - All packages exist in npm registry | ||
| - CDN URL templates are valid | ||
|
|
||
| ## Scripts | ||
|
|
||
| - **`npm run sync:dependencies`**: Sync shared dependencies from root `package.json` to `config/package.json` | ||
| - **`npm run validate:dependencies`**: Validate dependency consistency and npm registry existence | ||
|
|
||
| Both scripts automatically detect shared dependencies by comparing the root and config `package.json` files. | ||
|
|
||
| ## Files | ||
|
|
||
| - **`config/package.json`**: Dependency registry with versions and CDN templates | ||
| - **`config/package-lock.json`**: Lock file required by Dependabot (generated with `npm install --package-lock-only`) | ||
| - **`scripts/sync-dependencies.js`**: Script to sync shared dependencies | ||
| - **`scripts/validate-dependencies.js`**: Script to validate dependencies | ||
| - **`.github/dependabot.yml`**: Dependabot configuration for automated updates | ||
| - **`.github/workflows/sync-dependencies.yml`**: GitHub Action to auto-sync on PRs | ||
|
|
||
| ## Creating/Updating package-lock.json | ||
|
|
||
| The `package-lock.json` file is required for Dependabot to work. To create or update it without installing `node_modules`: | ||
|
|
||
| ```bash | ||
| cd config/ | ||
| npm install --package-lock-only | ||
| ``` | ||
|
|
||
| This generates the lock file based on `package.json` without creating a `node_modules` directory, which is ideal since `config/` dependencies are only used for version tracking, not for local installation. | ||
|
|
||
| ## Integration Points | ||
|
|
||
| 1. **Template System** (`modules/generator.xql`): | ||
| - Loads `config/package.json` and makes it available as `$dependencies` | ||
| - Dynamically builds `$cdn` map from `jinks.cdn` configuration | ||
| - Processes `styles` arrays to replace hardcoded CDN URLs with templated versions | ||
| - Auto-populates profile-specific dependencies (e.g., `jinntap` version from `config/package.json`) | ||
|
|
||
| 2. **API Pages** (`modules/api.xql`): Adds dependencies and CDN URLs to context for jinks UI pages | ||
|
|
||
| 3. **Templates**: Use `$cdn` map for CDN URLs instead of hardcoded versions. Always use function call syntax: `$cdn?('key')` | ||
| - Example: `$cdn?('fore-bundle')` | ||
| - Example with special characters: `$cdn?('@teipublisher/pb-components-bundle')` | ||
|
|
||
| 4. **Generated Config** (`profiles/base10/modules/generated-config.tpl.xql`): Derives `$config:webcomponents` from `$dependencies` when available | ||
|
|
||
| ## Benefits | ||
|
|
||
| - **Single Source of Truth**: All dependency versions in one place | ||
| - **Automated Updates**: Dependabot handles version bumps | ||
| - **Consistency**: All generated apps use the same dependency versions | ||
| - **Maintainability**: Easy to update versions across all apps | ||
| - **CDN Management**: Centralized CDN URL templates with version placeholders | ||
Uh oh!
There was an error while loading. Please reload this page.