eslint-plugin-no-server-imports 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,10 @@
1
1
  # eslint-plugin-no-server-imports
2
2
 
3
- Modern frameworks cram server and client files together. You flip between them fast, review a PR, feel confident…and then the bundle explodes because someone `import prisma from '@prisma/client'` in a component. Builds take minutes. CI nags later. Users see the error first. Meanwhile you're diffing stack traces wondering where your day went.
3
+ Server and client code sit side by side in modern frameworks, so it is easy to `import { PrismaClient } from '@prisma/client'` in a component and never notice. The build fails minutes later, or the bundle ships and breaks in someone's browser. This plugin flags that import in your editor the moment you write it.
4
4
 
5
- This plugin shortens the feedback loop to zero:
6
-
7
- - **Write code see error immediately** - ESLint surfaces violations as you type, not minutes later in a build
8
- - **Stay in flow** - Fix happens in the same editor where you're working. No context switching, no waiting for bundlers
9
- - **Builds become boring** - Errors are caught in dev mode, so `npm run build` confirms what you already know instead of surprising you
10
- - **Productive dev loop** - Write, see feedback, fix, move on. The way it should be.
5
+ - You see the error as you type, not minutes later in a build.
6
+ - You fix it in the editor you are already in, with no context switch.
7
+ - `npm run build` stops surprising you, because the errors are gone before you run it.
11
8
 
12
9
  ## TL;DR
13
10
 
@@ -39,7 +36,8 @@ Done. Blocks `fs`, `prisma`, `pino`, and 100+ server-only modules in client code
39
36
 
40
37
  ```bash
41
38
  pnpm add -D eslint-plugin-no-server-imports @typescript-eslint/utils
42
- # npm/yarn/bun work too - ESLint 9+ is the only peer dependency.
39
+ # npm, yarn, and bun work too. Peers: ESLint 9 or 10, plus @typescript-eslint/utils.
40
+ # The package ships ESM only, which flat config (eslint.config.mjs) loads natively.
43
41
  ```
44
42
 
45
43
  ```ts
@@ -104,7 +102,9 @@ By default the rule runs in `client-only` mode, meaning "only check paths that l
104
102
  - Re-exports (`export * from 'pino'`) ✅
105
103
  - Dynamic imports (`await import('pg')`) stay untouched because they're runtime-only.
106
104
 
107
- The rule also understands server function scopes. If every reference to a value import stays inside a callback passed to functions like `createServerFn`, `createIsomorphicFn`, `server$`, `action$`, or `loader$`, it's considered safe. Configure `serverFunctionNames` to teach it your own helpers (Nuxt's `defineEventHandler`, Remix loaders, etc.). Next.js Server Actions aren't special-cased - keep the imports inside the `'use server'` function via `await import(...)` and you're good.
105
+ The rule also understands server function scopes. If every reference to a value import stays inside a callback passed to functions like `createServerFn`, `createIsomorphicFn`, `server$`, `action$`, or `loader$`, the rule treats it as safe. Configure `serverFunctionNames` to teach it your own helpers, such as Nuxt's `defineEventHandler` or Remix loaders. Next.js Server Actions are not special-cased: keep the import inside the `'use server'` function via `await import(...)` and the rule stays quiet.
106
+
107
+ One thing the rule does **not** do: ban one file from importing another by path. It flags named server-only *modules* (`pino`, `node:fs`, your own `serverModules` entries), not local imports. So in TanStack Start a client route can `import { listUsers } from '../server/users'` to call a `createServerFn` over RPC, and the rule leaves it alone. To catch a genuine leak, add the Node-only package a component should never touch (a database client, a telemetry provider) to `serverModules`, or keep that code under a `serverFilePatterns` path. See the [TanStack Start example](../../apps/tanstack-start-example) for a working setup.
108
108
 
109
109
  ### What remains allowed
110
110
 
@@ -372,19 +372,19 @@ The extension works alongside the [ESLint VS Code extension](https://marketplace
372
372
 
373
373
  **Does this replace the `server-only` runtime guard?**
374
374
 
375
- No - keep it for defense in depth. This rule stops mistakes earlier; the runtime guard still protects you if someone bypasses linting. Think of it like wearing both a seatbelt and having airbags.
375
+ No. Keep the runtime guard for defense in depth. This rule catches the mistake earlier, in the editor; the runtime guard still protects you if someone bypasses linting.
376
376
 
377
377
  **Will it slow down ESLint?**
378
378
 
379
- Nope. The rule only inspects files whose path matches the client patterns, and the AST work is limited to imports/exports/server-function calls. Expect negligible overhead compared to `typescript-eslint` itself. We're pretty efficient about this.
379
+ No. The rule inspects only files whose path matches the client patterns, and the AST work covers imports, exports, and server-function calls. Overhead is negligible next to `typescript-eslint` itself.
380
380
 
381
381
  **How do I allow a specific file?**
382
382
 
383
- Use `ignoreFiles` with any glob, or drop a `/* eslint-disable no-server-imports/no-server-imports */` pragma if you absolutely must. But really, try to fix the underlying issue first - that's usually the better path.
383
+ Use `ignoreFiles` with any glob, or add a `/* eslint-disable no-server-imports/no-server-imports */` pragma. Fix the underlying import first when you can.
384
384
 
385
385
  **What if my framework isn't supported?**
386
386
 
387
- We've got defaults for Next.js, Astro, SvelteKit, TanStack Start, Remix, and SolidStart. If your framework uses different patterns, just configure `clientFilePatterns` and `serverFilePatterns` to match your setup. It's pretty flexible.
387
+ The rule ships defaults for Next.js, Astro, SvelteKit, TanStack Start, Remix, and SolidStart. For anything else, set `clientFilePatterns` and `serverFilePatterns` to match your layout and `serverFunctionNames` to match your server helpers.
388
388
 
389
389
  ## Contributing & support
390
390
 
package/dist/index.d.mts CHANGED
@@ -1,15 +1,16 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
1
+ import { ESLintUtils } from "@typescript-eslint/utils";
2
2
 
3
+ //#region src/framework-detection.d.ts
3
4
  /**
4
5
  * Framework Auto-Detection
5
6
  * ========================
6
7
  * Automatically detects the frontend framework being used and provides
7
8
  * optimal default configurations for the no-server-imports rule.
8
9
  */
9
- type DetectedFramework = 'next' | 'astro' | 'sveltekit' | 'unknown';
10
+ type DetectedFramework = 'next' | 'astro' | 'sveltekit' | 'tanstack-start' | 'unknown';
10
11
  interface FrameworkDefaults {
11
- clientFilePatterns: string[];
12
- serverFilePatterns: string[];
12
+ clientFilePatterns: string[];
13
+ serverFilePatterns: string[];
13
14
  }
14
15
  /**
15
16
  * Framework-specific default configurations
@@ -37,103 +38,113 @@ declare function getFrameworkDefaults(filePath?: string): FrameworkDefaults;
37
38
  * Clears the cached framework detection (useful for testing)
38
39
  */
39
40
  declare function clearFrameworkCache(): void;
40
-
41
- /**
42
- * ESLint Plugin: eslint-plugin-no-server-imports
43
- * ===============================================
44
- * Prevents server-only module imports in client code.
45
- * Catches bundling issues in your editor instead of at build time.
46
- *
47
- * @author Jag Reehal [@jagreehal] <jag@jagreehal.com>
48
- * @license MIT
49
- */
50
-
41
+ //#endregion
42
+ //#region src/index.d.ts
51
43
  /** Configuration options for the no-server-imports rule */
52
44
  interface RuleOptions {
53
- /** Additional server-only modules to check (merged with defaults) */
54
- serverModules?: string[];
55
- /** Additional server-only file patterns to check (merged with defaults) */
56
- serverFilePatterns?: string[];
57
- /** File patterns that indicate client code (overrides defaults if provided) */
58
- clientFilePatterns?: string[];
59
- /** File patterns to completely ignore */
60
- ignoreFiles?: string[];
61
- /** Whether to check for 'server-only' import marker */
62
- checkServerOnlyMarker?: boolean;
63
- /** Whether to check for server function usage (createServerFn, etc.) */
64
- checkServerFunctions?: boolean;
65
- /** Server function names to check for */
66
- serverFunctionNames?: string[];
67
- /** Whether to report unused server-only imports (default: true) */
68
- reportUnusedImports?: boolean;
69
- /** File selection mode: 'client-only' checks only clientFilePatterns, 'all-non-server' checks all except server files */
70
- mode?: 'client-only' | 'all-non-server';
71
- /** Next.js serverExternalPackages - merged into serverModules (for Next.js projects) */
72
- serverExternalPackages?: string[];
45
+ /** Additional server-only modules to check (merged with defaults) */
46
+ serverModules?: string[];
47
+ /** Additional server-only file patterns to check (merged with defaults) */
48
+ serverFilePatterns?: string[];
49
+ /** File patterns that indicate client code (overrides defaults if provided) */
50
+ clientFilePatterns?: string[];
51
+ /** File patterns to completely ignore */
52
+ ignoreFiles?: string[];
53
+ /** Whether to check for 'server-only' import marker */
54
+ checkServerOnlyMarker?: boolean;
55
+ /** Whether to check for server function usage (createServerFn, etc.) */
56
+ checkServerFunctions?: boolean;
57
+ /** Server function names to check for */
58
+ serverFunctionNames?: string[];
59
+ /** Whether to report unused server-only imports (default: true) */
60
+ reportUnusedImports?: boolean;
61
+ /** File selection mode: 'client-only' checks only clientFilePatterns, 'all-non-server' checks all except server files */
62
+ mode?: 'client-only' | 'all-non-server';
63
+ /** Next.js serverExternalPackages - merged into serverModules (for Next.js projects) */
64
+ serverExternalPackages?: string[];
73
65
  }
74
66
  type MessageIds = 'serverOnlyImport' | 'serverOnlyRequire' | 'suggestServerOnlyMarker';
75
67
  type Options = [RuleOptions?];
76
- declare const rule: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
77
-
68
+ declare const rule: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener> & {
69
+ name: string;
70
+ };
78
71
  /** Plugin configuration */
79
72
  declare const plugin: {
80
- readonly rules: {
81
- readonly 'no-server-imports': ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
73
+ readonly rules: {
74
+ readonly 'no-server-imports': ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener> & {
75
+ name: string;
76
+ };
77
+ };
78
+ readonly configs: {
79
+ /**
80
+ * Recommended config - uses sensible defaults that work across frameworks.
81
+ * For framework-specific optimizations, use one of the framework presets.
82
+ */
83
+ readonly recommended: {
84
+ readonly plugins: readonly ["no-server-imports"];
85
+ readonly rules: {
86
+ readonly 'no-server-imports/no-server-imports': "error";
87
+ };
88
+ };
89
+ /**
90
+ * Next.js optimized configuration.
91
+ * Best for Next.js App Router and Pages Router projects.
92
+ */
93
+ readonly 'recommended-next': {
94
+ readonly plugins: readonly ["no-server-imports"];
95
+ readonly rules: {
96
+ readonly 'no-server-imports/no-server-imports': readonly ["error", {
97
+ readonly clientFilePatterns: string[];
98
+ readonly serverFilePatterns: string[];
99
+ }];
100
+ };
82
101
  };
83
- readonly configs: {
84
- /**
85
- * Recommended config - uses sensible defaults that work across frameworks.
86
- * For framework-specific optimizations, use one of the framework presets.
87
- */
88
- readonly recommended: {
89
- readonly plugins: readonly ["no-server-imports"];
90
- readonly rules: {
91
- readonly 'no-server-imports/no-server-imports': "error";
92
- };
93
- };
94
- /**
95
- * Next.js optimized configuration.
96
- * Best for Next.js App Router and Pages Router projects.
97
- */
98
- readonly 'recommended-next': {
99
- readonly plugins: readonly ["no-server-imports"];
100
- readonly rules: {
101
- readonly 'no-server-imports/no-server-imports': readonly ["error", {
102
- readonly clientFilePatterns: string[];
103
- readonly serverFilePatterns: string[];
104
- }];
105
- };
106
- };
107
- /**
108
- * Astro optimized configuration.
109
- * Best for Astro projects with islands architecture.
110
- */
111
- readonly 'recommended-astro': {
112
- readonly plugins: readonly ["no-server-imports"];
113
- readonly rules: {
114
- readonly 'no-server-imports/no-server-imports': readonly ["error", {
115
- readonly clientFilePatterns: string[];
116
- readonly serverFilePatterns: string[];
117
- }];
118
- };
119
- };
120
- /**
121
- * SvelteKit optimized configuration.
122
- * Best for SvelteKit projects.
123
- */
124
- readonly 'recommended-sveltekit': {
125
- readonly plugins: readonly ["no-server-imports"];
126
- readonly rules: {
127
- readonly 'no-server-imports/no-server-imports': readonly ["error", {
128
- readonly clientFilePatterns: string[];
129
- readonly serverFilePatterns: string[];
130
- }];
131
- };
132
- };
102
+ /**
103
+ * Astro optimized configuration.
104
+ * Best for Astro projects with islands architecture.
105
+ */
106
+ readonly 'recommended-astro': {
107
+ readonly plugins: readonly ["no-server-imports"];
108
+ readonly rules: {
109
+ readonly 'no-server-imports/no-server-imports': readonly ["error", {
110
+ readonly clientFilePatterns: string[];
111
+ readonly serverFilePatterns: string[];
112
+ }];
113
+ };
133
114
  };
134
- readonly meta: {
135
- readonly name: "eslint-plugin-no-server-imports";
115
+ /**
116
+ * SvelteKit optimized configuration.
117
+ * Best for SvelteKit projects.
118
+ */
119
+ readonly 'recommended-sveltekit': {
120
+ readonly plugins: readonly ["no-server-imports"];
121
+ readonly rules: {
122
+ readonly 'no-server-imports/no-server-imports': readonly ["error", {
123
+ readonly clientFilePatterns: string[];
124
+ readonly serverFilePatterns: string[];
125
+ }];
126
+ };
136
127
  };
128
+ /**
129
+ * TanStack Start optimized configuration.
130
+ * Best for TanStack Start projects using createServerFn.
131
+ */
132
+ readonly 'recommended-tanstack-start': {
133
+ readonly plugins: readonly ["no-server-imports"];
134
+ readonly rules: {
135
+ readonly 'no-server-imports/no-server-imports': readonly ["error", {
136
+ readonly clientFilePatterns: string[];
137
+ readonly serverFilePatterns: string[];
138
+ readonly checkServerFunctions: true;
139
+ readonly serverFunctionNames: readonly ["createServerFn", "createIsomorphicFn", "createServerOnlyFn"];
140
+ }];
141
+ };
142
+ };
143
+ };
144
+ readonly meta: {
145
+ readonly name: "eslint-plugin-no-server-imports";
146
+ };
137
147
  };
138
-
139
- export { type DetectedFramework, FRAMEWORK_DEFAULTS, type FrameworkDefaults, type RuleOptions, clearFrameworkCache, plugin as default, detectFramework, getFrameworkDefaults, rule };
148
+ //#endregion
149
+ export { type DetectedFramework, FRAMEWORK_DEFAULTS, type FrameworkDefaults, RuleOptions, clearFrameworkCache, plugin as default, detectFramework, getFrameworkDefaults, rule };
150
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/framework-detection.ts","../src/index.ts"],"mappings":";;;;;;AAUA;;;KAAY,iBAAA;AAAA,UAEK,iBAAA;EACf,kBAAA;EACA,kBAAkB;AAAA;;AAAA;AAMpB;cAAa,kBAAA,EAAoB,MAAA,CAAO,iBAAA,EAAmB,iBAAA;;;;;;;;;;;iBA4L3C,eAAA,CAAgB,QAAA,YAAoB,iBAAiB;AAArE;;;;AAAqE;AAuCrE;AAvCA,iBAuCgB,oBAAA,CAAqB,QAAA,YAAoB,iBAAiB;;;AAAA;iBAQ1D,mBAAA;;;;UC5FC,WAAA;EDrJG;ECuJlB,aAAA;EDzED;EC2EC,kBAAA;EDnJsC;ECqJtC,kBAAA;EDrJ+B;ECuJ/B,WAAA;EDvJqC;ECyJrC,qBAAA;EDzJsC;EC2JtC,oBAAA;ED3J0E;EC6J1E,mBAAA;ED+Bc;EC7Bd,mBAAA;;EAEA,IAAA;ED2BmE;ECzBnE,sBAAA;AAAA;AAAA,KAGG,UAAA;AAAA,KAIA,OAAA,IAAW,WAAW;AAAA,cAkPd,IAAA,EAAI,WAAA,CAAA,UAAA,CAAA,UAAA,EAAA,OAAA,WAAA,WAAA,CAAA,YAAA;;;ADjLkB;AAAA,cC8tB7B,MAAA;EAAA;;;;;;;;;;;;;;;;IAtzBJ;;;;IAAA;;;;;;;;;IAmBa;;AAAA;AAAA;IAAA;;;;;;;;;IAsPE;;;;IAAA;;;;;;;;;IA6iBX;;;;IAAA"}