chore: migrate to pnpm

NPM refuses to acknowledge their limitations when working with monorepos

Signed-off-by: Fernando Fernández <ferferga@hotmail.com>
This commit is contained in:
Fernando Fernández
2026-04-07 18:58:12 +02:00
parent bd0809953b
commit f00e60fcd3
26 changed files with 7031 additions and 10522 deletions
+1 -1
View File
@@ -23,7 +23,7 @@
},
"postCreateCommand": {
"tauri-deps": "install_packages $(cat packaging/tauri/apt_packages)",
"npm": "npm ci --no-audit",
"pnpm": "corepack pnpm install --frozen-lockfile",
"unshallow": "git fetch --unshallow || true"
},
"postAttachCommand": {
-1
View File
@@ -70,7 +70,6 @@
]
},
"ignoreDeps": [
"npm",
"node",
"vuetify"
],
+2 -2
View File
@@ -75,7 +75,7 @@ jobs:
cache-workspaces: ${{ env.WORKING_DIR }}
- name: Install npm dependencies 📦
run: npm ci --no-audit
run: corepack pnpm install --frozen-lockfile
- name: Install Linux dependencies 📦🐧
if: ${{ matrix.platform == 'ubuntu' }}
@@ -84,7 +84,7 @@ jobs:
sudo apt install -y --no-install-recommends $(cat apt_packages)
- name: Build application 🛠️
run: npm run build
run: corepack pnpm build
- name: Upload built application artifact ⬆️🐧🍎🪟
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+2 -2
View File
@@ -51,10 +51,10 @@ jobs:
check-latest: true
- name: Install dependencies 📦
run: npm ci --no-audit
run: corepack pnpm install --frozen-lockfile
- name: Run ${{ matrix.command }} ⚙️
run: npm run ${{ matrix.command }}
run: corepack pnpm ${{ matrix.command }}
commits_checks:
name: Commit linting 💬✅
-14
View File
@@ -1,14 +0,0 @@
save-exact=true
engine-strict=true
ignore-scripts=true
# Workspace options
prefer-dedupe=true
include=prod
include=dev
include=optional
include=peer
if-present=true
## Fix timeout errors in CI
fetch-retries=15
+16 -15
View File
@@ -22,52 +22,53 @@
"lint:fix": "eslint . --fix",
"lint:inspect": "eslint-config-inspector",
"build": "vite build --configLoader runner",
"check": "npm run lint && npm run check:types",
"check": "pnpm lint && pnpm check:types",
"check:types": "vue-tsc",
"start": "vite --configLoader runner",
"serve": "vite preview --configLoader runner",
"prod": "npm run build && npm run serve",
"prod": "pnpm build && pnpm serve",
"clean": "git clean -fxd",
"storybook": "storybook dev -p 6006 --config-dir storybook --no-open"
},
"dependencies": {
"@iconify/json": "2.2.456",
"@fontsource-variable/figtree": "5.2.10",
"@jellyfin-vue/i18n": "*",
"@jellyfin-vue/shared": "*",
"@jellyfin-vue/ui-toolkit": "*",
"@jellyfin-vue/i18n": "workspace:*",
"@jellyfin-vue/shared": "workspace:*",
"@jellyfin-vue/ui-toolkit": "workspace:*",
"@jellyfin/sdk": "0.13.0",
"@vueuse/core": "14.2.1",
"@vueuse/core": "catalog:",
"assjs": "0.1.5",
"audiomotion-analyzer": "4.5.4",
"axios": "1.14.0",
"blurhash": "2.0.5",
"comlink": "4.4.2",
"date-fns": "4.1.0",
"comlink": "catalog:",
"date-fns": "catalog:",
"defu": "6.1.5",
"destr": "2.0.5",
"dexie": "4.4.1",
"fast-equals": "6.0.0",
"hls.js": "1.6.15",
"i18next": "26.0.2",
"i18next-vue": "5.4.0",
"i18next": "catalog:",
"i18next-vue": "catalog:",
"libpgs": "0.8.1",
"sortablejs": "1.15.7",
"swiper": "12.1.3",
"uuid": "13.0.0",
"vue-router": "5.0.4",
"vuetify": "3.11.3"
"vuetify": "catalog:",
"vue": "catalog:"
},
"devDependencies": {
"@iconify/json": "2.2.456",
"@jellyfin-vue/configs": "*",
"@jellyfin-vue/vite-plugins": "*",
"@jellyfin-vue/configs": "workspace:*",
"@jellyfin-vue/vite-plugins": "workspace:*",
"@rollup/plugin-virtual": "3.0.2",
"@types/sortablejs": "1.15.9",
"@unocss/reset": "66.6.7",
"@vitejs/plugin-vue": "6.0.5",
"browserslist": "4.28.1",
"lightningcss": "1.32.0",
"unplugin-vue-components": "31.1.0",
"unplugin-vue-components": "catalog:",
"vite-plugin-vue-devtools": "8.1.1"
}
}
+1 -1
View File
@@ -70,7 +70,7 @@ export default defineConfig({
polyfill: false
},
reportCompressedSize: false,
rollupOptions: {
rolldownOptions: {
input: {
splashscreen: resolve(import.meta.dirname, 'src/splashscreen.ts'),
main: resolve(import.meta.dirname, 'src/main.ts'),
-10378
View File
File diff suppressed because it is too large Load Diff
+12 -36
View File
@@ -1,55 +1,31 @@
{
"name": "jellyfin-vue",
"version": "0.3.1",
"private": true,
"type": "module",
"homepage": "https://jellyfin.org/",
"bugs": {
"url": "https://github.com/jellyfin/jellyfin-vue/issues"
},
"packageManager": "npm@11.6.1",
"repository": {
"type": "git",
"url": "https://github.com/jellyfin/jellyfin-vue/"
},
"license": "GPL-3.0-only",
"author": "jellyfin-vue Contributors (https://github.com/jellyfin/jellyfin-vue/graphs/contributors)",
"workspaces": [
"frontend",
"packaging/tauri",
"packages/*"
],
"type": "module",
"scripts": {
"analyze:cycles": "pnpm -r --if-present --no-bail analyze:cycles",
"check:types": "pnpm -r --if-present --no-bail check:types",
"lint": "pnpm -r --if-present --no-bail lint",
"lint:fix": "pnpm -r --if-present --no-bail lint:fix",
"test": "pnpm -r --if-present --no-bail test"
},
"packageManager": "pnpm@10.33.0",
"engines": {
"node": ">=24.11.0 <25.0.0",
"npm": ">=11.6.1"
},
"scripts": {
"lint": "npm run lint -ws --include-workspace-root=false",
"lint:fix": "npm run lint:fix -ws --include-workspace-root=false",
"check:types": "npm run check:types -ws --include-workspace-root=false",
"analyze:cycles": "npm run analyze:cycles -ws --include-workspace-root=false",
"test": "npm run test -ws --include-workspace-root=false"
},
"dependencies": {
"vue": "3.5.31"
"pnpm": ">=10.33.0"
},
"devDependencies": {
"@chromatic-com/storybook": "5.1.1",
"@eslint/config-inspector": "1.5.0",
"@storybook/addon-a11y": "10.3.3",
"@storybook/vue3": "10.3.3",
"@storybook/vue3-vite": "10.3.3",
"@types/node": "25.5.0",
"eslint": "9.39.4",
"jiti": "2.6.1",
"storybook": "10.3.3",
"type-fest": "5.5.0",
"typescript": "6.0.2",
"unocss": "66.6.7",
"vite": "8.0.3",
"vitest": "4.1.2",
"vue-tsc": "3.2.6"
},
"peerDependencies": {
"@vue/shared": "*"
"pnpm": "10.33.0"
}
}
+18 -3
View File
@@ -18,7 +18,23 @@
"@eslint/css": "0.14.1",
"@eslint/js": "9.39.4",
"@eslint/json": "0.14.0",
"@jellyfin-vue/shared": "*",
"globals": "17.4.0",
"@chromatic-com/storybook": "5.1.1",
"@eslint/config-inspector": "1.5.0",
"@storybook/addon-a11y": "10.3.3",
"@storybook/vue3": "10.3.3",
"@storybook/vue3-vite": "10.3.3",
"@types/node": "25.5.0",
"eslint": "9.39.4",
"jiti": "2.6.1",
"storybook": "10.3.3",
"type-fest": "5.5.0",
"typescript": "6.0.2",
"unocss": "66.6.7",
"vite": "8.0.3",
"vitest": "4.1.2",
"vue-tsc": "3.2.6",
"@jellyfin-vue/shared": "workspace:*",
"@stylistic/eslint-plugin": "5.10.0",
"@unocss/eslint-config": "66.6.7",
"eslint-config-flat-gitignore": "2.3.0",
@@ -33,8 +49,7 @@
"eslint-plugin-unicorn": "62.0.0",
"eslint-plugin-vue": "10.8.0",
"eslint-plugin-vue-scoped-css": "3.0.0",
"find-up-simple": "1.0.1",
"globals": "17.4.0",
"find-up-simple": "catalog:",
"typescript-eslint": "8.58.0",
"vue-eslint-parser": "10.4.0"
}
+1 -1
View File
@@ -172,7 +172,7 @@ export function getBaseConfig(packageName: string, forceCache = !CI_environment,
{
...json.configs.recommended,
files,
ignores: [...ignoresForOtherLangs, 'package-lock.json', ...files.map(file => `!${file}`)],
ignores: [...ignoresForOtherLangs, 'pnpm-lock.yaml', ...files.map(file => `!${file}`)],
language: `json/${lang}`,
name: `(@jellyfin-vue/configs/lint/base - ${lang}) Extended config from plugin`
}];
+7 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@jellyfin-vue/i18n",
"type": "module",
"description": "All internacionalization files for Jellyfin Vue",
"description": "All internationalization files for Jellyfin Vue",
"exports": {
".": {
"import": "./src/index.ts",
@@ -17,12 +17,13 @@
"check:types": "vue-tsc"
},
"devDependencies": {
"@jellyfin-vue/configs": "*",
"@jellyfin-vue/configs": "workspace:*",
"knitwork": "1.3.0"
},
"peerDependencies": {
"date-fns": "*",
"i18next": "*",
"vuetify": "*"
"dependencies": {
"@vue/shared": "catalog:",
"date-fns": "catalog:",
"i18next": "catalog:",
"vuetify": "catalog:"
}
}
+3 -1
View File
@@ -14,9 +14,11 @@
"test": "vitest run"
},
"devDependencies": {
"@jellyfin-vue/configs": "*"
"@jellyfin-vue/configs": "workspace:*",
"find-up-simple": "catalog:"
},
"dependencies": {
"@vue/shared": "catalog:",
"dompurify": "3.3.3",
"marked": "17.0.5"
}
+15 -15
View File
@@ -1,24 +1,24 @@
import { execSync } from 'node:child_process';
import { globSync, readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { findUpSync } from 'find-up-simple';
import type { LiteralUnion } from 'type-fest';
const encoding = 'utf8';
const workspaceManifest = findUpSync('pnpm-workspace.yaml', { type: 'file' });
const monorepoRoot = workspaceManifest ? dirname(workspaceManifest) : process.cwd();
// eslint-disable-next-line sonarjs/no-os-command-from-path
const monorepoRoot = execSync('npm prefix', {
encoding
}).trim();
const packagePaths = (() => {
// eslint-disable-next-line sonarjs/no-os-command-from-path
const listing = JSON.parse(execSync('npm query .workspace', {
encoding,
cwd: monorepoRoot
}));
const relation = new Map<string, string>();
const packageJsonPaths = [
join(monorepoRoot, 'frontend/package.json'),
join(monorepoRoot, 'packaging/tauri/package.json'),
...globSync(join(monorepoRoot, 'packages/*/package.json'))
];
for (const list of listing) {
if (list.path && list.name) {
relation.set(list.name, list.path);
for (const packageJsonPath of packageJsonPaths) {
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { name?: string };
if (packageJson.name) {
relation.set(packageJson.name, dirname(packageJsonPath));
}
}
+4 -4
View File
@@ -12,18 +12,18 @@
"lint:fix": "eslint . --fix",
"lint:inspect": "eslint-config-inspector",
"build": "vite build --configLoader runner",
"check": "npm run lint && npm run check:types",
"check": "pnpm lint && pnpm check:types",
"check:types": "vue-tsc",
"start": "vite --configLoader runner",
"serve": "vite preview --configLoader runner",
"prod": "npm run build && npm run serve",
"prod": "pnpm build && pnpm serve",
"clean": "git clean -fxd"
},
"devDependencies": {
"@jellyfin-vue/configs": "*"
"@jellyfin-vue/configs": "workspace:*"
},
"dependencies": {
"@jellyfin-vue/frontend": "*",
"@jellyfin-vue/frontend": "workspace:*",
"@tauri-apps/api": "2.10.1"
}
}
+9 -17
View File
@@ -19,25 +19,17 @@
"storybook": "storybook dev -p 6006 --config-dir storybook --no-open"
},
"dependencies": {
"@jellyfin-vue/shared": "*",
"@jellyfin-vue/i18n": "workspace:*",
"@jellyfin-vue/shared": "workspace:*",
"@vueuse/core": "catalog:",
"comlink": "catalog:",
"@skirtle/vue-vnode-utils": "0.2.0",
"color": "5.0.3"
"i18next-vue": "catalog:",
"color": "5.0.3",
"vuetify": "catalog:"
},
"devDependencies": {
"@jellyfin-vue/configs": "*"
},
"peerDependencies": {
"@jellyfin-vue/i18n": "*",
"@vueuse/core": "*",
"comlink": "*",
"i18next-vue": "*",
"unplugin-vue-components": "*",
"vue": "*",
"vuetify": "*"
},
"peerDependenciesMeta": {
"unplugin-vue-components": {
"optional": true
}
"@jellyfin-vue/configs": "workspace:*",
"unplugin-vue-components": "catalog:"
}
}
+2 -2
View File
@@ -10,8 +10,8 @@
"check:types": "vue-tsc"
},
"devDependencies": {
"@jellyfin-vue/configs": "*",
"find-up-simple": "1.0.1",
"@jellyfin-vue/configs": "workspace:*",
"find-up-simple": "catalog:",
"pretty-bytes": "7.1.0",
"sonda": "0.11.1"
}
+15 -6
View File
@@ -2,10 +2,9 @@ import { basename, resolve, join } from 'node:path';
import { globSync } from 'node:fs';
import { lstat, rename, rm } from 'node:fs/promises';
import type { LiteralUnion } from 'type-fest';
import type { RollupLog } from 'rollup';
import prettyBytes from 'pretty-bytes';
import Sonda from 'sonda/rollup';
import { normalizePath, preview, type Plugin } from 'vite';
import { normalizePath, preview, type Plugin, type Rolldown } from 'vite';
/**
* TODO: Track https://github.com/vitejs/vite/pull/19005 so we can pull Vite's default config instead
@@ -18,7 +17,7 @@ const defaultConfig = { build: { outDir: 'dist' } };
*/
export function JBundleAnalysis(): Plugin {
let mode: LiteralUnion<'analyze:bundle' | 'analyze:cycles', string>;
const warnings: RollupLog[] = [];
const warnings: Rolldown.RolldownLog = [];
return {
name: 'Jellyfin_Vue:bundle_analysis',
@@ -110,11 +109,21 @@ export function JBundleChunking(): Plugin {
* Split each vendor in its own chunk
*/
name: (id) => {
const match = /node_modules\/([^/]+)/.exec(id)?.[1];
const normalizedId = id.replaceAll('\\', '/');
const nodeModulesPrefix = 'node_modules/';
const nodeModulesIndex = normalizedId.lastIndexOf(nodeModulesPrefix);
if (match) {
return `vendor/${match.replace('@', '')}`;
if (nodeModulesIndex === -1) {
return;
}
const packageName = normalizedId.slice(nodeModulesIndex + nodeModulesPrefix.length).split('/')[0];
if (!packageName) {
return;
}
return `vendor/${packageName.replace('@', '')}`;
},
priority: 10
},
+2 -3
View File
@@ -1,6 +1,5 @@
import { extname, join } from 'node:path';
import type { Plugin } from 'vite';
import type { InputOptions } from 'rollup';
import type { Plugin, Rolldown } from 'vite';
import { findUpSync } from 'find-up-simple';
/**
@@ -13,7 +12,7 @@ import { findUpSync } from 'find-up-simple';
* @param inputAttrs - Additional attributes to provide for specific inputs
*/
export function JMonorepo(path: string, inputAttrs: Record<string, Record<string, string>>): Plugin {
let resolvedInputs: NonNullable<InputOptions['input']> = {};
let resolvedInputs: NonNullable<Rolldown.InputOptions['input']> = {};
return {
name: 'Jellyfin_Vue:monorepo_setup',
-1
View File
@@ -6,4 +6,3 @@ dist/
frontend
package-lock.json
package.json
.npmrc
+7 -6
View File
@@ -11,16 +11,17 @@ override_dh_auto_test:
override_dh_clistrip:
override_dh_auto_build:
cp -ra root/{package.json,package-lock.json,.npmrc,frontend} $(CURDIR)/
npm ci --no-audit -w frontend
npm run build -w frontend
cp -ra root/{package.json,pnpm-workspace.yaml,pnpm-lock.yaml,frontend,packages} $(CURDIR)/
corepack pnpm install --frozen-lockfile
cd frontend && corepack pnpm build
mv $(CURDIR)/frontend/dist $(CURDIR)/dist
rm -rf $(CURDIR)/frontend rm -rf $(CURDIR)/node_modules $(CURDIR)/package.json $(CURDIR)/package-lock.json $(CURDIR)/.npmrc
rm -rf $(CURDIR)/frontend $(CURDIR)/packages $(CURDIR)/node_modules $(CURDIR)/package.json $(CURDIR)/pnpm-lock.yaml $(CURDIR)/pnpm-workspace.yaml
override_dh_auto_clean:
test -d $(CURDIR)/frontend && rm -rf '$(CURDIR)/frontend' || true
test -d $(CURDIR)/packages && rm -rf '$(CURDIR)/packages' || true
test -d $(CURDIR)/dist && rm -rf '$(CURDIR)/dist' || true
test -d $(CURDIR)/node_modules && rm -rf '$(CURDIR)/node_modules' || true
test -d $(CURDIR)/package.json && rm -rf '$(CURDIR)/package.json' || true
test -d $(CURDIR)/package-lock.json && rm -rf '$(CURDIR)/package-lock.json' || true
test -d $(CURDIR)/.npmrc && rm -rf '$(CURDIR)/.npmrc' || true
test -d $(CURDIR)/pnpm-lock.yaml && rm -rf '$(CURDIR)/pnpm-lock.yaml' || true
test -d $(CURDIR)/pnpm-workspace.yaml && rm -rf '$(CURDIR)/pnpm-workspace.yaml' || true
+2 -2
View File
@@ -10,13 +10,13 @@ ARG COMMIT_HASH
ENV IS_STABLE=$IS_STABLE
ENV COMMIT_HASH=$COMMIT_HASH
COPY package.json package-lock.json .npmrc /app/
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml /app/
COPY frontend /app/frontend
COPY packages /app/packages
WORKDIR /app/frontend
# Build client
RUN npm ci --no-audit && npm run build
RUN corepack pnpm install --frozen-lockfile && corepack pnpm build
# Deploy built distribution to nginx
FROM ghcr.io/nginxinc/nginx-unprivileged:stable-alpine-slim
+3 -3
View File
@@ -2,15 +2,15 @@
"name": "@jellyfin-vue/tauri-packaging",
"private": true,
"scripts": {
"start": "npm run gen-icon && tauri dev",
"start": "pnpm gen-icon && tauri dev",
"gen-icon": "tauri icon ../../frontend/public/icon.svg",
"build": "npm run gen-icon && tauri build",
"build": "pnpm gen-icon && tauri build",
"clean": "git clean -fxd"
},
"devDependencies": {
"@tauri-apps/cli": "2.10.1"
},
"dependencies": {
"@jellyfin-vue/tauri-runtime": "*"
"@jellyfin-vue/tauri-runtime": "workspace:*"
}
}
+2 -2
View File
@@ -19,9 +19,9 @@
}
},
"build": {
"beforeBuildCommand": "npm run build -w @jellyfin-vue/tauri-runtime",
"beforeBuildCommand": "corepack pnpm --filter @jellyfin-vue/tauri-runtime build",
"frontendDist": "../../packages/tauri-runtime/dist",
"beforeDevCommand": "npm start -w @jellyfin-vue/tauri-runtime",
"beforeDevCommand": "corepack pnpm --filter @jellyfin-vue/tauri-runtime start",
"devUrl": "http://127.0.0.1:3000"
},
"productName": "jellyfin-vue",
+6881
View File
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
packages:
- frontend
- packaging/tauri
- packages/*
saveExact: true
engineStrict: true
ignoreDepScripts: true
blockExoticSubdeps: true
packageImportMethod: hardlink
lockfileIncludeTarballUrl: true
linkWorkspacePackages: deep
injectWorkspacePackages: true
fetchRetries: 15
catalog:
vue: 3.5.31
'@vue/shared': 3.5.31
'@vueuse/core': 14.2.1
comlink: 4.4.2
date-fns: 4.1.0
find-up-simple: 1.0.1
i18next: 26.0.2
i18next-vue: 5.4.0
unplugin-vue-components: 31.1.0
vuetify: 3.11.3