eslint-plugin-no-server-imports 1.0.0

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 ADDED
@@ -0,0 +1,397 @@
1
+ # eslint-plugin-no-server-imports
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.
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.
11
+
12
+ ## TL;DR
13
+
14
+ ```bash
15
+ pnpm add -D eslint-plugin-no-server-imports @typescript-eslint/utils
16
+ ```
17
+
18
+ ```ts
19
+ // eslint.config.mjs
20
+ import noServerImports from 'eslint-plugin-no-server-imports';
21
+ export default [noServerImports.configs['recommended-next']]; // or 'recommended-astro' / 'recommended-sveltekit'
22
+ ```
23
+
24
+ **What it catches:**
25
+
26
+ ```ts
27
+ // ❌ This triggers an error in your editor:
28
+ import fs from 'fs';
29
+ import { PrismaClient } from '@prisma/client';
30
+ import pino from 'pino';
31
+
32
+ // ✅ This is safe:
33
+ import type { User } from '@prisma/client';
34
+ ```
35
+
36
+ Done. Blocks `fs`, `prisma`, `pino`, and 100+ server-only modules in client code. Type-only imports are always safe. [Full config options →](#configuration)
37
+
38
+ ## Quick start
39
+
40
+ ```bash
41
+ pnpm add -D eslint-plugin-no-server-imports @typescript-eslint/utils
42
+ # npm/yarn/bun work too - ESLint 9+ is the only peer dependency.
43
+ ```
44
+
45
+ ```ts
46
+ // eslint.config.mjs
47
+ import tseslint from 'typescript-eslint';
48
+ import noServerImports from 'eslint-plugin-no-server-imports';
49
+
50
+ export default [
51
+ ...tseslint.configs.recommended,
52
+ {
53
+ files: ['**/*.ts', '**/*.tsx'],
54
+ plugins: { 'no-server-imports': noServerImports },
55
+ rules: {
56
+ 'no-server-imports/no-server-imports': 'error',
57
+ },
58
+ },
59
+ ];
60
+ ```
61
+
62
+ Using plain JS? Drop the `files` filter. Already on a flat ESLint config? Just keep the `plugins` + `rules` block.
63
+
64
+ ### Framework presets (smarter defaults)
65
+
66
+ ```ts
67
+ import noServerImports from 'eslint-plugin-no-server-imports';
68
+
69
+ export default [
70
+ noServerImports.configs['recommended-next'],
71
+ // or: noServerImports.configs['recommended-astro']
72
+ // or: noServerImports.configs['recommended-sveltekit']
73
+ ];
74
+ ```
75
+
76
+ Each preset ships with tuned `clientFilePatterns` + `serverFilePatterns` for that framework. If you keep `app/` at the repo root in Next.js, add `'**/app/**'` yourself - the default intentionally sticks to `src/app/**` so it doesn't match `myapp/src/...` by accident.
77
+
78
+ ## What actually gets flagged
79
+
80
+ ### Server-only modules (100+ built-ins and packages)
81
+
82
+ Out of the box the rule blocks:
83
+
84
+ - **Node built-ins**: `fs`, `node:fs`, `path`, `crypto`, `child_process`, `worker_threads`, …
85
+ - **Databases**: `prisma`, `@prisma/client`, `drizzle-orm`, `pg`, `mysql2`, `mongodb`, `kysely`, …
86
+ - **Logging & monitoring**: `pino`, `winston`, `bunyan`, `@appsignal/nodejs`, `dd-trace`, …
87
+ - **Security**: `bcrypt`, `argon2`, `oslo`, `@node-rs/*`
88
+ - **Tooling**: `@swc/core`, `postcss`, `typescript`, `jest`, `playwright`, `sharp`, …
89
+
90
+ Need your own aliases like `@/lib/db` or `@company/logger`? Add them via `serverModules`. Full list lives in [the complete server-only modules list](#server-only-modules).
91
+
92
+ ### File awareness (so only the right files are checked)
93
+
94
+ - **Client patterns (default)**: `**/routes/**`, `**/pages/**`, `**/components/**`, `**/islands/**`, `**/src/app/**`
95
+ - **Server patterns (always skipped)**: `**/*.server.ts`, `**/*.server.tsx`, `**/*.server.js`, `**/server/**`, `**/api/**`, `**/_server/**`
96
+
97
+ By default the rule runs in `client-only` mode, meaning "only check paths that look like client code." Flip `mode: 'all-non-server'` if you want every non-server file scanned. `ignoreFiles` beats both modes when you need to silence generated code or test fixtures.
98
+
99
+ ### Imports, re-exports, requires… all of it
100
+
101
+ - Static `import` and `export { ... } from` usage of server modules ✅
102
+ - Side-effect imports like `import 'fs'` ✅
103
+ - CommonJS `require('pg')` ✅ (the rule even tracks destructuring)
104
+ - Re-exports (`export * from 'pino'`) ✅
105
+ - Dynamic imports (`await import('pg')`) stay untouched because they're runtime-only.
106
+
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.
108
+
109
+ ### What remains allowed
110
+
111
+ | Pattern | Why it passes |
112
+ | --- | --- |
113
+ | `import type { Logger } from 'pino'` | Type-only imports vanish during compilation. |
114
+ | `export { type Logger } from 'pino'` | Same deal - types don't hit bundles. |
115
+ | `import 'server-only';` | The "server-only" marker opts the whole file out (configurable via `checkServerOnlyMarker`). |
116
+ | Server function scopes | Imports pulled into callbacks from `createServerFn`/`server$`/`action$` stay server-side. |
117
+ | Dynamic imports inside functions | `const { PrismaClient } = await import('@prisma/client');` runs only when the server code executes. |
118
+
119
+ Quick fixes currently offer to insert `import 'server-only';` above your code when that's the right escape hatch. Prefer to keep unused imports warnings in one place? Set `reportUnusedImports: false` and let `no-unused-vars` handle it.
120
+
121
+ ## Configuration
122
+
123
+ All options are optional and can be fully customized. Here's a complete example with all options:
124
+
125
+ ```ts
126
+ {
127
+ rules: {
128
+ 'no-server-imports/no-server-imports': ['error', {
129
+ // Add custom server-only modules (merged with 100+ defaults)
130
+ serverModules: ['@/lib/logger', 'my-custom-db'],
131
+
132
+ // File patterns for server files (merged with defaults)
133
+ serverFilePatterns: ['**/backend/**', '**/server-utils/**'],
134
+
135
+ // File patterns for client files (replaces defaults if provided)
136
+ clientFilePatterns: ['**/app/**', '**/pages/**', '**/components/**'],
137
+
138
+ // Files to completely ignore
139
+ ignoreFiles: ['**/__tests__/**', '**/*.stories.tsx', '**/generated/**'],
140
+
141
+ // Detection behavior
142
+ checkServerOnlyMarker: true, // Respect 'server-only' import marker
143
+ checkServerFunctions: true, // Allow imports inside server function callbacks
144
+ serverFunctionNames: ['createServerFn', 'server$', 'action$', 'loader$', 'myServerFn'],
145
+
146
+ // Reporting behavior
147
+ reportUnusedImports: true, // Report unused server imports (default: true)
148
+
149
+ // File selection strategy
150
+ mode: 'client-only', // or 'all-non-server' to check all non-server files
151
+
152
+ // Next.js integration
153
+ serverExternalPackages: ['my-native-package'], // Sync with next.config.js
154
+ }],
155
+ },
156
+ }
157
+ ```
158
+
159
+ ### Minimal configuration
160
+
161
+ For most projects, the defaults work out of the box. You only need to configure options that differ from defaults:
162
+
163
+ ```ts
164
+ {
165
+ rules: {
166
+ 'no-server-imports/no-server-imports': ['error', {
167
+ // Only configure what you need to change
168
+ clientFilePatterns: ['**/app/**', '**/pages/**'], // Next.js root app/
169
+ serverModules: ['@/lib/db'], // Your custom modules
170
+ }],
171
+ },
172
+ }
173
+ ```
174
+
175
+ ### Option reference
176
+
177
+ #### `serverModules` (optional)
178
+
179
+ - **Type**: `string[]`
180
+ - **Default**: 100+ built-in server-only modules (see list below)
181
+ - **What it does**: Adds additional server-only modules to the detection list. These modules will trigger errors when imported in client code.
182
+ - **Why it exists**: Your project might use custom server-only packages, internal modules with path aliases (like `@/lib/db`), or packages not in the default list. This option lets you extend the detection to cover your specific stack.
183
+ - **Example**: `serverModules: ['@/lib/logger', 'my-custom-db', '../server/utils']`
184
+ - **Note**: Supports path aliases, relative paths, and subpath imports (e.g., `'@/lib/db'` will also match `'@/lib/db/query'`)
185
+
186
+ #### `serverFilePatterns` (optional)
187
+
188
+ - **Type**: `string[]`
189
+ - **Default**: `['**/*.server.ts', '**/*.server.tsx', '**/*.server.js', '**/server/**', '**/api/**', '**/_server/**']`
190
+ - `**/*.server.*` - Files with `.server.` in the name (Astro convention)
191
+ - `**/server/**` - Files in `server/` directories
192
+ - `**/api/**` - API route directories (Next.js, SvelteKit, etc.)
193
+ - `**/_server/**` - Alternative server directory pattern
194
+ - **What it does**: Defines file path patterns that indicate server-only code. Files matching these patterns are completely ignored by the rule.
195
+ - **Why it exists**: Server files can safely import server-only modules, so we skip checking them entirely. This improves performance and prevents false positives.
196
+ - **Example**: `serverFilePatterns: ['**/backend/**', '**/server/**', '**/*.server.ts']`
197
+ - **Note**: Patterns are **merged** with defaults (not replaced). Use glob patterns compatible with `picomatch`.
198
+
199
+ #### `clientFilePatterns` (optional)
200
+
201
+ - **Type**: `string[]`
202
+ - **Default**: `['**/routes/**', '**/pages/**', '**/components/**', '**/islands/**', '**/src/app/**']`
203
+ - `**/routes/**` - Route files (SvelteKit, Remix)
204
+ - `**/pages/**` - Page files (Next.js pages router, Nuxt, Astro)
205
+ - `**/components/**` - Component files (generic)
206
+ - `**/islands/**` - Island components (Astro)
207
+ - `**/src/app/**` - Next.js app directory (when using `src/` folder)
208
+ - **What it does**: Defines file path patterns that indicate client code. Only files matching these patterns are checked for server-only imports (when `mode: 'client-only'`).
209
+ - **Why it exists**: Different frameworks organize client code differently. This lets you configure the rule to match your project structure.
210
+ - **Example**: `clientFilePatterns: ['**/app/**', '**/pages/**', '**/components/**']` for Next.js root-level `app/`
211
+ - **Note**: If provided, this **replaces** the defaults (doesn't merge). Include all patterns you need. For Next.js root-level `app/`, you must explicitly add `'**/app/**'` because the default only covers `'**/src/app/**'` to avoid false matches.
212
+
213
+ #### `ignoreFiles` (optional)
214
+
215
+ - **Type**: `string[]`
216
+ - **Default**: `[]`
217
+ - **What it does**: File patterns to completely ignore, regardless of whether they match client or server patterns.
218
+ - **Why it exists**: Some files like tests, stories, or generated code might need to import server modules for testing/mocking purposes. This provides a clean way to exclude them.
219
+ - **Example**: `ignoreFiles: ['**/__tests__/**', '**/*.test.ts', '**/*.stories.tsx', '**/generated/**']`
220
+ - **Note**: This takes precedence over both `clientFilePatterns` and `serverFilePatterns`.
221
+
222
+ #### `checkServerOnlyMarker` (optional)
223
+
224
+ - **Type**: `boolean`
225
+ - **Default**: `true`
226
+ - **What it does**: When enabled, if a file contains `import 'server-only'` or `require('server-only')`, the entire file is treated as server-only and all imports are allowed.
227
+ - **Why it exists**: The `server-only` package is a common runtime guard. This option respects that marker as an explicit opt-in to server-only behavior, providing an escape hatch for edge cases.
228
+ - **Example**: Set to `false` if you want stricter checking even with the marker, or if you don't use `server-only` at all.
229
+
230
+ #### `checkServerFunctions` (optional)
231
+
232
+ - **Type**: `boolean`
233
+ - **Default**: `true`
234
+ - **What it does**: When enabled, the rule detects server function calls (like `createServerFn()`, `server$()`, etc.) and allows server-only imports if they're **only** used inside the server function callbacks.
235
+ - **Why it exists**: Modern frameworks use server functions/actions that run server-side. Imports used exclusively inside these callbacks are safe because they never execute on the client. This enables the recommended pattern of importing server modules inside server functions.
236
+ - **Example**: Set to `false` if you want to disallow all server imports in client files, even inside server functions (stricter mode).
237
+
238
+ #### `serverFunctionNames` (optional)
239
+
240
+ - **Type**: `string[]`
241
+ - **Default**: `['createServerFn', 'createIsomorphicFn', 'server$', 'action$', 'loader$']`
242
+ - `createServerFn` - TanStack Start
243
+ - `createIsomorphicFn` - TanStack Start (isomorphic functions)
244
+ - `server$` - SolidStart
245
+ - `action$` - Remix
246
+ - `loader$` - Remix
247
+ - **What it does**: Function names that create server-side execution contexts. The rule tracks callbacks passed to these functions and allows server-only imports used exclusively within those callbacks.
248
+ - **Why it exists**: Different frameworks use different function names for server actions. This lets you configure the rule to recognize your framework's patterns (e.g., Nuxt's `defineEventHandler`, Remix's `action$`/`loader$`).
249
+ - **Example**: `serverFunctionNames: ['createServerFn', 'server$', 'defineEventHandler', 'myCustomServerFn']`
250
+ - **Note**: The rule detects both direct calls (`createServerFn()`) and chained calls (`createServerFn().handler()`). It tracks where imports are **used**, not just where they're declared. If you provide this option, it **replaces** the defaults (doesn't merge), so include all function names you need.
251
+
252
+ #### `reportUnusedImports` (optional)
253
+
254
+ - **Type**: `boolean`
255
+ - **Default**: `true`
256
+ - **What it does**: When `true`, reports server-only imports even if they're never used in the file. When `false`, only reports imports that are actually referenced.
257
+ - **Why it exists**: Some teams prefer to let ESLint's `no-unused-vars` rule handle unused imports. Setting this to `false` avoids duplicate warnings and lets you use `no-unused-vars` for all unused imports consistently.
258
+ - **Example**: Set to `false` if you want `no-unused-vars` to handle unused imports, or `true` if you want this rule to catch unused server imports specifically.
259
+
260
+ #### `mode` (optional)
261
+
262
+ - **Type**: `'client-only' | 'all-non-server'`
263
+ - **Default**: `'client-only'`
264
+ - **What it does**: Controls which files are checked:
265
+ - `'client-only'`: Only files matching `clientFilePatterns` are checked
266
+ - `'all-non-server'`: All files are checked except those matching `serverFilePatterns` or `ignoreFiles`
267
+ - **Why it exists**: Some projects have files that aren't explicitly client code but also shouldn't import server modules (e.g., shared utilities, config files). `'all-non-server'` mode catches server imports in these ambiguous files.
268
+ - **Example**: Use `'all-non-server'` if you want comprehensive checking across your entire codebase, not just known client files.
269
+
270
+ #### `serverExternalPackages` (optional)
271
+
272
+ - **Type**: `string[]`
273
+ - **Default**: `[]`
274
+ - **What it does**: Merges Next.js `serverExternalPackages` configuration into `serverModules`. Packages listed here are treated as server-only.
275
+ - **Why it exists**: Next.js has a `serverExternalPackages` config option that marks packages that shouldn't be bundled for the client. This option lets you sync that configuration with the ESLint rule, ensuring consistency between your Next.js config and linting.
276
+ - **Example**: `serverExternalPackages: ['my-native-package', '@my-org/server-lib']` (typically read from `next.config.js`)
277
+ - **Note**: This is merged with `serverModules`, so you can use both options together. Primarily useful for Next.js projects.
278
+
279
+ ### Common tweaks
280
+
281
+ - **Next.js root `app/`**: `clientFilePatterns: ['**/app/**', '**/pages/**', '**/components/**']`
282
+ - **Next.js with serverExternalPackages**: Use `serverExternalPackages` option to sync with your `next.config.js`
283
+ - **Check all files**: `mode: 'all-non-server'` - checks every file except server patterns
284
+ - **Let `no-unused-vars` handle unused imports**: `reportUnusedImports: false`
285
+ - **Astro**: `clientFilePatterns: ['**/pages/**', '**/components/**', '**/islands/**']`, `serverFilePatterns: ['**/*.server.ts', '**/server/**']`
286
+ - **SvelteKit**: Check out the monorepo examples - we've got working configs for all three frameworks.
287
+ - **Custom infra**: add in-house modules to `serverModules` (supports aliases like `@/lib/db` and subpaths).
288
+
289
+ ### Next.js integration
290
+
291
+ If you're using Next.js's `serverExternalPackages` in `next.config.js`, you can sync it with this rule:
292
+
293
+ ```ts
294
+ // eslint.config.mjs
295
+ import nextConfig from './next.config.js';
296
+
297
+ export default [
298
+ {
299
+ rules: {
300
+ 'no-server-imports/no-server-imports': ['error', {
301
+ serverExternalPackages: nextConfig.serverExternalPackages || [],
302
+ clientFilePatterns: ['**/app/**', '**/pages/**', '**/components/**'],
303
+ }],
304
+ },
305
+ },
306
+ ];
307
+ ```
308
+
309
+ ## Server-only modules
310
+
311
+ Complete list of server-only modules detected by default:
312
+
313
+ - **Logging**: `pino`, `pino-pretty`, `pino-roll`, `winston`, `bunyan`
314
+ - **Databases**: `better-sqlite3`, `pg`, `mysql2`, `mongodb`, `mongoose`, `prisma`, `@prisma/client`, `drizzle-orm`, `kysely`, `@libsql/client`, `libsql`, `@mikro-orm/core`, `@mikro-orm/knex`, `sqlite3`, `ravendb`
315
+ - **Node.js built-ins**: `fs`, `node:fs`, `fs/promises`, `node:fs/promises`, `path`, `node:path`, `crypto`, `node:crypto`, `child_process`, `node:child_process`, `os`, `node:os`, `net`, `node:net`, `dns`, `node:dns`, `cluster`, `node:cluster`, `worker_threads`, `node:worker_threads`
316
+ - **Authentication & Security**: `argon2`, `@node-rs/argon2`, `bcrypt`, `@node-rs/bcrypt`, `oslo`
317
+ - **AWS SDK**: `@aws-sdk/client-s3`, `@aws-sdk/s3-presigned-post`, `aws-crt`
318
+ - **Monitoring & Observability**: `@appsignal/nodejs`, `@highlight-run/node`, `@sentry/profiling-node`, `dd-trace`, `newrelic`, `@statsig/statsig-node-core`
319
+ - **AI & ML**: `@huggingface/transformers`, `@xenova/transformers`, `chromadb-default-embed`, `onnxruntime-node`
320
+ - **Blockchain**: `@blockfrost/blockfrost-js`, `@jpg-store/lucid-cardano`
321
+ - **Build Tools & Compilers**: `@swc/core`, `autoprefixer`, `postcss`, `prettier`, `typescript`, `ts-node`, `ts-morph`, `webpack`, `eslint`
322
+ - **Testing**: `cypress`, `jest`, `playwright`, `playwright-core`, `puppeteer`, `puppeteer-core`
323
+ - **Browser Automation**: `@sparticuz/chromium`, `@sparticuz/chromium-min`
324
+ - **Content & Document Generation**: `@react-pdf/renderer`, `mdx-bundler`, `next-mdx-remote`, `next-seo`, `shiki`, `vscode-oniguruma`
325
+ - **Image Processing**: `canvas`, `sharp`
326
+ - **Utilities**: `config`, `keyv`, `node-cron`, `rimraf`, `thread-stream`
327
+ - **Runtime & Framework**: `@alinea/generated`, `@zenstackhq/runtime`, `express`, `firebase-admin`, `htmlrewriter`
328
+ - **Native Node.js addons**: `cpu-features`, `isolated-vm`, `node-pty`, `node-web-audio-api`, `websocket`, `zeromq`
329
+ - **Module System Patchers**: `import-in-the-middle`, `require-in-the-middle`
330
+ - **DOM & Browser APIs**: `jsdom`
331
+
332
+ The rule also detects subpath imports (e.g., `fs/promises` matches `fs`, `@prisma/client/query` matches `@prisma/client`).
333
+
334
+ ## Behavioral summary
335
+
336
+ Quick reference for what triggers what:
337
+
338
+ | Import style | Bundled? | Rule result |
339
+ | --- | --- | --- |
340
+ | `import pino from 'pino'` | Yes | ❌ error|
341
+ | `const fs = require('fs')` | Yes | ❌ error |
342
+ | `export { default } from 'pino'` | Yes | ❌ error |
343
+ | `import type { Logger } from 'pino'` | No | ✅ allowed |
344
+ | `import { type Logger } from 'pino'` | No | ✅ allowed |
345
+ | `export { type Logger } from 'pino'` | No | ✅ allowed |
346
+ | `await import('pino')` inside function | Lazy | ✅ allowed |
347
+
348
+ ## Quick fix suggestions
349
+
350
+ When the rule detects a violation, it can offer to insert `import 'server-only';` at the top of the file. That keeps the current file marked as server-only without touching any other logic. If you'd rather restructure things (move the code, switch to a server action, or wrap it in an `await import(...)`), decline the suggestion and do it manually - ESLint simply points to the exact import and lets you pick the right pattern.
351
+
352
+ > **Note**: Suggestions rely on ESLint's `hasSuggestions` API, so they're opt-in. Nothing changes until you accept the fix.
353
+
354
+ ## VS Code extension
355
+
356
+ For an enhanced experience, install the companion VS Code extension:
357
+
358
+ ```bash
359
+ code --install-extension jagreehal.vscode-no-server-imports
360
+ ```
361
+
362
+ The extension provides:
363
+
364
+ - **Status bar indicator** - Shows detected framework (Next.js, Astro, SvelteKit) with icon
365
+ - **Show Status command** - Displays framework info and quick links to config/docs
366
+ - **Detect Framework command** - Re-scans the workspace for framework detection
367
+ - **Open Documentation command** - Opens framework-specific documentation
368
+
369
+ The extension works alongside the [ESLint VS Code extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint), which handles the actual linting.
370
+
371
+ ## FAQ
372
+
373
+ **Does this replace the `server-only` runtime guard?**
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.
376
+
377
+ **Will it slow down ESLint?**
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.
380
+
381
+ **How do I allow a specific file?**
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.
384
+
385
+ **What if my framework isn't supported?**
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.
388
+
389
+ ## Contributing & support
390
+
391
+ Issues and feature requests live at [GitHub Issues](https://github.com/jagreehal/eslint-plugin-no-server-imports/issues). Feel free to open a PR if your framework uses a different server function name - we're happy to add sensible defaults.
392
+
393
+ Want to see it in action? Check out the [monorepo examples](../../README.md) with working Next.js, Astro, and SvelteKit setups.
394
+
395
+ ---
396
+
397
+ Stop finding server imports during deploys. Catch them in the editor instead.
@@ -0,0 +1,139 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+
3
+ /**
4
+ * Framework Auto-Detection
5
+ * ========================
6
+ * Automatically detects the frontend framework being used and provides
7
+ * optimal default configurations for the no-server-imports rule.
8
+ */
9
+ type DetectedFramework = 'next' | 'astro' | 'sveltekit' | 'unknown';
10
+ interface FrameworkDefaults {
11
+ clientFilePatterns: string[];
12
+ serverFilePatterns: string[];
13
+ }
14
+ /**
15
+ * Framework-specific default configurations
16
+ */
17
+ declare const FRAMEWORK_DEFAULTS: Record<DetectedFramework, FrameworkDefaults>;
18
+ /**
19
+ * Detects the framework being used in the project.
20
+ *
21
+ * Detection priority:
22
+ * 1. Config files (most reliable): next.config.*, astro.config.*, svelte.config.*
23
+ * 2. Package.json dependencies: "next", "astro", "@sveltejs/kit"
24
+ *
25
+ * @param filePath - Path to a file or directory in the project (used to find project root)
26
+ * @returns The detected framework or 'unknown'
27
+ */
28
+ declare function detectFramework(filePath?: string): DetectedFramework;
29
+ /**
30
+ * Gets the default configuration for the detected framework.
31
+ *
32
+ * @param filePath - Path to a file in the project (used for detection)
33
+ * @returns Framework-specific defaults
34
+ */
35
+ declare function getFrameworkDefaults(filePath?: string): FrameworkDefaults;
36
+ /**
37
+ * Clears the cached framework detection (useful for testing)
38
+ */
39
+ 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
+
51
+ /** Configuration options for the no-server-imports rule */
52
+ 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[];
73
+ }
74
+ type MessageIds = 'serverOnlyImport' | 'serverOnlyRequire' | 'suggestServerOnlyMarker';
75
+ type Options = [RuleOptions?];
76
+ declare const rule: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
77
+
78
+ /** Plugin configuration */
79
+ declare const plugin: {
80
+ readonly rules: {
81
+ readonly 'no-server-imports': ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
82
+ };
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
+ };
133
+ };
134
+ readonly meta: {
135
+ readonly name: "eslint-plugin-no-server-imports";
136
+ };
137
+ };
138
+
139
+ export { type DetectedFramework, FRAMEWORK_DEFAULTS, type FrameworkDefaults, type RuleOptions, clearFrameworkCache, plugin as default, detectFramework, getFrameworkDefaults, rule };
@@ -0,0 +1,139 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+
3
+ /**
4
+ * Framework Auto-Detection
5
+ * ========================
6
+ * Automatically detects the frontend framework being used and provides
7
+ * optimal default configurations for the no-server-imports rule.
8
+ */
9
+ type DetectedFramework = 'next' | 'astro' | 'sveltekit' | 'unknown';
10
+ interface FrameworkDefaults {
11
+ clientFilePatterns: string[];
12
+ serverFilePatterns: string[];
13
+ }
14
+ /**
15
+ * Framework-specific default configurations
16
+ */
17
+ declare const FRAMEWORK_DEFAULTS: Record<DetectedFramework, FrameworkDefaults>;
18
+ /**
19
+ * Detects the framework being used in the project.
20
+ *
21
+ * Detection priority:
22
+ * 1. Config files (most reliable): next.config.*, astro.config.*, svelte.config.*
23
+ * 2. Package.json dependencies: "next", "astro", "@sveltejs/kit"
24
+ *
25
+ * @param filePath - Path to a file or directory in the project (used to find project root)
26
+ * @returns The detected framework or 'unknown'
27
+ */
28
+ declare function detectFramework(filePath?: string): DetectedFramework;
29
+ /**
30
+ * Gets the default configuration for the detected framework.
31
+ *
32
+ * @param filePath - Path to a file in the project (used for detection)
33
+ * @returns Framework-specific defaults
34
+ */
35
+ declare function getFrameworkDefaults(filePath?: string): FrameworkDefaults;
36
+ /**
37
+ * Clears the cached framework detection (useful for testing)
38
+ */
39
+ 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
+
51
+ /** Configuration options for the no-server-imports rule */
52
+ 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[];
73
+ }
74
+ type MessageIds = 'serverOnlyImport' | 'serverOnlyRequire' | 'suggestServerOnlyMarker';
75
+ type Options = [RuleOptions?];
76
+ declare const rule: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
77
+
78
+ /** Plugin configuration */
79
+ declare const plugin: {
80
+ readonly rules: {
81
+ readonly 'no-server-imports': ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
82
+ };
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
+ };
133
+ };
134
+ readonly meta: {
135
+ readonly name: "eslint-plugin-no-server-imports";
136
+ };
137
+ };
138
+
139
+ export { type DetectedFramework, FRAMEWORK_DEFAULTS, type FrameworkDefaults, type RuleOptions, clearFrameworkCache, plugin as default, detectFramework, getFrameworkDefaults, rule };