feat(eslint): relax frontend imports for nfs

allow frontend plugins to import from other frontend plugins with same
plugin id to allow plugin overrides without unnecessary eslint warning.

relates to #31372

Signed-off-by: Hellgren Heikki <heikki.hellgren@op.fi>
This commit is contained in:
Hellgren Heikki
2025-10-09 15:11:17 +03:00
parent 9f6f46d234
commit a1dae7180d
7 changed files with 65 additions and 4 deletions
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/eslint-plugin': patch
---
Allow frontend plugin to import from another frontend plugin with same plugin id.
This prevents the ESLint rule from incorrectly flagging these imports in the new frontend system
where plugin override requires cross-plugin imports.
@@ -1,6 +1,25 @@
# @backstage/no-mixed-plugin-imports
Disallow mixed imports between backstage plugins.
This rule ensures that imports between Backstage plugins are consistent with their intended usage.
The rule checks the `backstage.role` field in the `package.json` of both the importing and target packages to determine if they are compatible.
Plugin roles include:
- `frontend-plugin` (or `frontend` for short)
- `backend-plugin` (or `backend` for short)
- `web-library` (or `react` for short)
- `node-library` (or `node` for short)
- `common-library` (or `common` for short)
Prohibited imports include:
- A `frontend` plugin importing directly from another `frontend`, `backend`, or `node` package. Instead, it should import from the corresponding `react` or `common` package.
- With an exception with the new frontend system where frontend plugins with the same plugin id are allowed to import from each other.
- A `backend` plugin importing directly from another `backend`, `frontend`, or `react` package. Instead, it should import from the corresponding `node` or `common` package.
- A `react` package importing from `frontend`, `backend`, or `node` packages.
- A `node` package importing from `frontend`, `backend`, or `react` packages
- A `common` package importing directly from any other plugin package.
## Usage
+1 -1
View File
@@ -21,7 +21,7 @@ const manypkg = require('@manypkg/get-packages');
/**
* @typedef ExtendedPackage
* @type {import('@manypkg/get-packages').Package & { packageJson: { exports?: Record<string, string>, files?: Array<string>, backstage?: { inline?: boolean, role?: string } }}} packageJson
* @type {import('@manypkg/get-packages').Package & { packageJson: { exports?: Record<string, string>, files?: Array<string>, backstage?: { inline?: boolean, role?: string, pluginId?: string } }}} packageJson
*/
/**
@@ -146,11 +146,24 @@ module.exports = {
}
const sourceRole = pkg.packageJson.backstage?.role;
const sourcePluginId = pkg.packageJson.backstage?.pluginId;
const targetRole = targetPackage.packageJson.backstage?.role;
const targetPluginId = targetPackage.packageJson.backstage?.pluginId;
if (!sourceRole || !targetRole) {
return;
}
// Allow frontend plugins to import from other frontend plugins with the same pluginId for NFS
if (
sourceRole === 'frontend-plugin' &&
targetRole === 'frontend-plugin' &&
sourcePluginId &&
targetPluginId &&
sourcePluginId === targetPluginId
) {
return;
}
if (
roleRules.some(
rule =>
@@ -0,0 +1,19 @@
{
"name": "@internal/bar-override",
"backstage": {
"role": "frontend-plugin",
"pluginId": "bar"
},
"exports": {
".": "./src/index.ts",
"./BarPage": "./src/components/Bar.tsx",
"./package.json": "./package.json"
},
"dependencies": {
"inline-dep": "*",
"react-router": "*"
},
"devDependencies": {
"react-router-dom": "*"
}
}
@@ -1,7 +1,8 @@
{
"name": "@internal/bar",
"backstage": {
"role": "frontend-plugin"
"role": "frontend-plugin",
"pluginId": "bar"
},
"exports": {
".": "./src/index.ts",
@@ -1,7 +1,8 @@
{
"name": "@internal/foo",
"backstage": {
"role": "frontend-plugin"
"role": "frontend-plugin",
"pluginId": "foo"
},
"files": [
"dist",