Files
cloudflare__vinext/vite.config.ts
T
Nathan Nguyen b324cbe04c refactor(utils): dedupe shared helpers and lint redefinitions (#1793)
* refactor(utils): dedupe shared helpers and lint redefinitions

Shared helper logic was being reimplemented across generated entries, runtime modules, and shims. That made small utility semantics easy to drift and gave agents no mechanical feedback when they hand-rolled copies.

Add a local Oxlint rule that discovers exported shared helpers and reports local redefinitions, including helpers embedded in generated source strings. Centralize the existing low-risk duplicates through shared utility modules.

* fix(lint): harden shared utility rule validation

* test(lint): avoid matching oxlint success summary

* fix(lint): make shared utility rule cwd independent

* fix(lint): address bonk review comments

- Drop redundant "default" export conditions in package.json; the
  generated worker template resolves these subpaths via "import" like
  its siblings (request-pipeline, pages-i18n, config-matchers).
- Mask backtick template literals in prefer-shared-utils so an
  apostrophe or comment sequence inside generated template source can
  no longer open string/comment masking and swallow a subsequent
  helper definition (false negative). Template bodies stay scannable.

---------

Co-authored-by: James <james@eli.cx>
2026-06-06 22:56:55 +01:00

257 lines
10 KiB
TypeScript

import path from "node:path";
import { defineConfig } from "vite-plus";
import { randomUUID } from "node:crypto";
const SHIMS_SRC = path.resolve(import.meta.dirname, "packages/vinext/src/shims");
const MSW_SETUP = path.resolve(import.meta.dirname, "tests/_msw/setup.ts");
// Resolve own-workspace sources directly in tests so the vinext <->
// @vinext/cloudflare dependency edge points at source (single module instance,
// no prior build required). Shared by both test projects below.
const WORKSPACE_SRC_ALIAS = {
"vinext/shims": SHIMS_SRC,
"@vinext/cloudflare/cache": path.resolve(import.meta.dirname, "packages/cloudflare/src/cache"),
};
export default defineConfig({
staged: {
"*": "vp check --fix",
},
fmt: {
printWidth: 100,
tabWidth: 2,
useTabs: false,
semi: true,
singleQuote: false,
trailingComma: "all",
ignorePatterns: ["tests/fixtures/ecosystem/**", "examples/**"],
},
lint: {
ignorePatterns: [
"fixtures/ecosystem/**",
"tests/fixtures/**",
"tests/fixtures/ecosystem/**",
"examples/**",
],
options: {
typeAware: true,
typeCheck: true,
denyWarnings: true,
},
plugins: ["typescript", "unicorn", "import", "react"],
jsPlugins: [
"./oxlint-plugins/prefer-import-alias.js",
"./oxlint-plugins/prefer-shared-utils.js",
],
rules: {
"@typescript-eslint/no-explicit-any": "error",
"typescript/consistent-type-definitions": ["error", "type"],
"@typescript-eslint/no-unsafe-function-type": "error",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-redeclare": "error",
"@typescript-eslint/no-implied-eval": "error",
"unicorn/prefer-node-protocol": "error",
"import/first": "error",
"import/no-duplicates": "error",
"no-new-func": "error",
"no-implied-eval": "error",
"arrow-body-style": ["error", "as-needed"],
"react/exhaustive-deps": "error",
"react/no-array-index-key": "error",
"react/rules-of-hooks": "error",
"react/self-closing-comp": "error",
"vinext-utils/prefer-shared-utils": "error",
},
overrides: [
{
files: ["**.spec.ts", "**.test.ts"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-function-type": "off",
"typescript/no-misused-promises": "error",
"typescript/switch-exhaustiveness-check": "error",
"import/no-self-import": "error",
"unicorn/throw-new-error": "error",
"unicorn/error-message": "error",
},
},
{
files: ["packages/vinext/src/**/*.{ts,tsx}"],
rules: {
"typescript/no-misused-promises": "error",
"typescript/switch-exhaustiveness-check": "error",
"typescript/restrict-template-expressions": "error",
"import/no-self-import": "error",
"unicorn/throw-new-error": "error",
"unicorn/error-message": "error",
},
},
{
// Forces relative imports of own-package files inside vinext to use
// the tsconfig path alias (e.g. ../shims/X.js → vinext/shims/X).
// Originally added for #1001 — bare specifiers keep
// @vitejs/plugin-rsc's `packageSources` map populated, which avoids
// the broken absolute-fs-path proxy fallback.
files: ["packages/vinext/**"],
rules: {
"vinext-local/prefer-import-alias": "error",
},
},
],
},
test: {
// GitHub Actions reporter adds inline failure annotations in PR diffs.
// Agent reporter suppresses passing test noise when running inside AI agents.
reporters: process.env.CI ? ["default", "github-actions"] : ["default", "agent"],
// Shared env for all projects.
env: {
// Mirrors the Vite `define` in index.ts that inlines a build-time UUID.
// Setting it here means tests exercise the same code path as production.
__VINEXT_DRAFT_SECRET: randomUUID(),
},
// Coverage activated only via --coverage flag (or CLI/config override).
// Istanbul provider is required because vinext source loads through Vite's
// module runner (helpers.ts:15 imports from packages/vinext/src directly,
// and integration tests start in-process Vite servers via createServer()).
// V8 coverage misses code under that runner.
coverage: {
provider: "istanbul",
include: ["packages/vinext/src/**/*.{ts,tsx}"],
exclude: ["**/*.d.ts", "**/*.test.ts", "**/*.spec.ts"],
reporter: ["text", "html", "json-summary", "lcov"],
reportsDirectory: "coverage",
clean: true,
skipFull: true,
// Always emit the report, even if some test files failed. A failing
// integration test (e.g. timing-sensitive teardown) shouldn't suppress
// coverage data we already collected.
reportOnFailure: true,
},
projects: [
{
resolve: {
alias: WORKSPACE_SRC_ALIAS,
},
test: {
name: "unit",
setupFiles: [MSW_SETUP],
// `scripts/**` covers the release-tooling unit tests
// (scripts/create-changeset.test.ts, scripts/version.test.ts), which
// are pure-logic and have no fixture/server dependencies.
include: ["tests/**/*.test.ts", "scripts/**/*.test.ts"],
exclude: [
"tests/fixtures/**/node_modules/**",
// Integration tests: spin up Vite dev servers against shared fixture
// dirs. Must run serially to avoid Vite deps optimizer cache races
// (node_modules/.vite/*) that produce "outdated pre-bundle" 500s.
// When adding a test that calls startFixtureServer() or createServer(),
// move it here.
"tests/app-router-client-preloading.test.ts",
"tests/app-router-dev-server.test.ts",
"tests/app-router-external-rewrite.test.ts",
"tests/app-router-font-google-prod.test.ts",
"tests/app-router-isr-codegen.test.ts",
"tests/app-router-malformed-url.test.ts",
"tests/app-router-metadata-routes.test.ts",
"tests/app-router-middleware-next-request.test.ts",
"tests/app-router-next-config-codegen.test.ts",
"tests/app-router-next-config-dev.test.ts",
"tests/app-router-origin-check.test.ts",
"tests/app-router-production-build.test.ts",
"tests/app-router-production-server.test.ts",
"tests/app-router-rsc-flight-hint.test.ts",
"tests/app-router-rsc-plugin.test.ts",
"tests/app-router-static-export.test.ts",
"tests/app-router-worker-entry.test.ts",
"tests/api-handler.test.ts",
"tests/cjs.test.ts",
"tests/ecosystem.test.ts",
"tests/entry-templates.test.ts",
"tests/features.test.ts",
"tests/favicon-short-circuit.test.ts",
"tests/image-optimization-parity.test.ts",
"tests/node-modules-css.test.ts",
"tests/pages-i18n-prod.test.ts",
"tests/pages-router-concurrency.test.ts",
"tests/pages-router.test.ts",
"tests/postcss-resolve.test.ts",
"tests/prerender.test.ts",
"tests/static-export.test.ts",
"tests/vite-hmr-websocket.test.ts",
"tests/nextjs-compat/**/*.test.ts",
// Flaky under parallelism due to 1 MiB buffer allocation pressure.
"tests/kv-cache-handler.test.ts",
],
},
},
{
resolve: {
alias: WORKSPACE_SRC_ALIAS,
},
test: {
name: "integration",
// MSW is intentionally NOT installed in the integration project.
// Integration tests spin up in-process HTTP servers and fixture
// dev servers and exercise them via `fetch("http://127.0.0.1:<port>/...")`.
// The @mswjs/interceptors layer interferes with that loopback
// traffic in subtle ways even when handlers `passthrough()`
// (e.g. 5xx response bodies stall, fixture-startup readiness
// probes time out). MSW's value here is mocking external HTTP
// for unit tests of fetch wrappers — integration tests already
// talk to real local servers, not to the network, so the
// unhandled-request guard buys little. If a future integration
// test needs to mock an external fetch, wire MSW per-file with
// `setupServer` rather than reverting this exclusion.
include: [
"tests/app-router-client-preloading.test.ts",
"tests/app-router-dev-server.test.ts",
"tests/app-router-external-rewrite.test.ts",
"tests/app-router-font-google-prod.test.ts",
"tests/app-router-isr-codegen.test.ts",
"tests/app-router-malformed-url.test.ts",
"tests/app-router-metadata-routes.test.ts",
"tests/app-router-middleware-next-request.test.ts",
"tests/app-router-next-config-codegen.test.ts",
"tests/app-router-next-config-dev.test.ts",
"tests/app-router-origin-check.test.ts",
"tests/app-router-production-build.test.ts",
"tests/app-router-production-server.test.ts",
"tests/app-router-rsc-flight-hint.test.ts",
"tests/app-router-rsc-plugin.test.ts",
"tests/app-router-static-export.test.ts",
"tests/app-router-worker-entry.test.ts",
"tests/api-handler.test.ts",
"tests/cjs.test.ts",
"tests/ecosystem.test.ts",
"tests/entry-templates.test.ts",
"tests/favicon-short-circuit.test.ts",
"tests/features.test.ts",
"tests/image-optimization-parity.test.ts",
"tests/kv-cache-handler.test.ts",
"tests/node-modules-css.test.ts",
"tests/pages-i18n-prod.test.ts",
"tests/pages-router-concurrency.test.ts",
"tests/pages-router.test.ts",
"tests/postcss-resolve.test.ts",
"tests/prerender.test.ts",
"tests/static-export.test.ts",
"tests/vite-hmr-websocket.test.ts",
"tests/nextjs-compat/**/*.test.ts",
],
testTimeout: 30000,
// Serial execution prevents Vite deps optimizer cache races when
// multiple test files share the same fixture directory.
fileParallelism: false,
},
},
],
},
});