
oxlintでimportして良いパッケージを制限する
こんばんは、情報システム室の夏目です。
Cloudflare WorkersでWebフロントとAPIを組んでいるのですが、Workerでしか使わないライブラリ、Webフロントでしか使わないライブラリ、これらがpackage.jsonのdependenciesにあります。
今回は間違えて使わないようにoxlintを使って間違えてimportしたらlintでエラーが出るようにします。
1. 準備
まずある程度のコードを準備します。
結論だけ見たい場合はスキップして 2. まで進んでください。
1-1. プロジェクトの雛型を作る
まずViteでReactのプロジェクトを作成します。
$ npm create vite@latest
Need to install the following packages:
create-vite@9.2.0
Ok to proceed? (y) y
npm notice run npx
npm notice run 'create-vite'
│
◇ Project name:
│ trial-import-linting
│
◇ Select a framework:
│ React
│
◇ Select a variant:
│ TypeScript + React Compiler
│
◇ Which linter to use?
│ Oxlint
│
◇ Install with npm and start now?
│ No
│
◇ Scaffolding project in /Users/natsume.yuta/spaces/work/blog/017_import_limiting/trial-import-linting...
│
└ Done. Now run:
cd trial-import-linting
npm install
npm run dev
作成されたファイルは次のようになっています。
$ cd trial-import-linting
$ eza -la --time-style=long-iso -F
.rw-r--r--@ 253 natsume.yuta 2026-09-09 13:57 .gitignore
.rw-r--r--@ 245 natsume.yuta 2026-09-09 13:57 .oxlintrc.json
.rw-r--r--@ 372 natsume.yuta 2026-09-09 13:57 index.html
.rw-r--r--@ 692 natsume.yuta 2026-09-09 13:57 package.json
drwxr-xr-x@ - natsume.yuta 2026-09-09 13:57 public/
.rw-r--r--@ 1.5k natsume.yuta 2026-09-09 13:57 README.md
drwxr-xr-x@ - natsume.yuta 2026-09-09 13:57 src/
.rw-r--r--@ 655 natsume.yuta 2026-09-09 13:57 tsconfig.app.json
.rw-r--r--@ 119 natsume.yuta 2026-09-09 13:57 tsconfig.json
.rw-r--r--@ 558 natsume.yuta 2026-09-09 13:57 tsconfig.node.json
.rw-r--r--@ 286 natsume.yuta 2026-09-09 13:57 vite.config.ts
依存ライブラリをインストールします。
またCloudflare Workers用のViteプラグインもインストールします。
$ mkdir worker
$ npm install
added 72 packages, and audited 73 packages in 18s
13 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
npm warn install-scripts 1 package had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts fsevents@2.3.3 (install: node-gyp rebuild)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
$ npm install -D @cloudflare/vite-plugin
added 33 packages, and audited 106 packages in 6s
20 packages are looking for funding
run `npm fund` for details
4 high severity vulnerabilities
To address all issues, run:
npm audit fix
Run `npm audit` for details.
npm warn install-scripts 3 packages had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts fsevents@2.3.3 (install: (install scripts present))
npm warn install-scripts workerd@1.20260908.1 (postinstall: node install.js)
npm warn install-scripts esbuild@0.28.1 (postinstall: node install.js)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow
次に、Webフロント用のコードにpathsを設定します。
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "es2023",
"lib": ["ES2023", "DOM"],
"module": "esnext",
"types": ["vite/client"],
"allowArbitraryExtensions": true,
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
/* Custom */
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"]
}
vite.config.tsにCloudflare Workers用のpluginを追加し、pathsを使用できるようにします。
import react, { reactCompilerPreset } from '@vitejs/plugin-react'
import babel from '@rolldown/plugin-babel'
import { defineConfig } from 'vite'
import { cloudflare } from '@cloudflare/vite-plugin'
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
babel({ presets: [reactCompilerPreset()] }),
cloudflare()
],
resolve: {
tsconfigPaths: true
}
})
1-2. Worker用のコードを書く
Worker用のコードを置くディレクトリを作成します。
さらにWorkerのルーティング用にHonoを、Worker用の型ファイル生成用にwranglerをインストールします。
$ mkdir -p worker/routes
$ npm install hono
added 1 package, and audited 74 packages in 5s
13 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
npm warn install-scripts 1 package had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts fsevents@2.3.3 (install: (install scripts present))
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
$ npm install -D wrangler
added 32 packages, and audited 106 packages in 8s
20 packages are looking for funding
run `npm fund` for details
3 high severity vulnerabilities
To address all issues, run:
npm audit fix
Run `npm audit` for details.
npm warn install-scripts 3 packages had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts fsevents@2.3.3 (install: (install scripts present))
npm warn install-scripts esbuild@0.28.1 (postinstall: node install.js)
npm warn install-scripts workerd@1.20260908.1 (postinstall: node install.js)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
次にwrangler.jsoncを作成します。
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "trial-import-linting",
"compatibility_date": "2026-09-07",
"main": "worker/index.ts",
"assets": {
"not_found_handling": "single-page-application",
"run_worker_first": ["/api/*"]
},
"observability": {
"enabled": true
}
}
次にWorker用の型定義ファイルを生成します。
$ npx wrangler types
npm notice run trial-import-linting@0.0.0 npx
npm notice run 'wrangler' types
⛅ wrangler 4.130.0
────────────────────
Generating project types...
interface __BaseEnv_Env {
}
declare namespace Cloudflare {
interface Env extends __BaseEnv_Env {}
}
interface Env extends __BaseEnv_Env {}
Generating runtime types...
Runtime types generated.
────────────────────────────────────────────────────────────
✨ Types written to worker-configuration.d.ts
📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.
次にWorker用のtsconfig、 tsconfig.worker.json を作成します。
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2022"],
"module": "esnext",
"moduleResolution": "bundler",
"types": ["./worker-configuration.d.ts"],
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"paths": {
"@worker/*": ["./worker/*"]
}
},
"include": ["worker-configuration.d.ts", "worker"]
}
作成した tsconfig.worker.json を tsconfig.json に追記します。
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.worker.json" }
]
}
次にWorker用のコードを作成します。
export type AppEnv = {
Bindings: Env;
}
import { Hono } from "hono";
import type { AppEnv } from "@worker/app-env"
export const routeHealth = new Hono<AppEnv>();
routeHealth.get("/", (c) => c.json({ ok: true }));
import { Hono } from "hono";
import type { AppEnv } from "@worker/app-env";
import { routeHealth } from "./health";
export const routeApi = new Hono<AppEnv>();
routeApi.route("/health", routeHealth);
import { Hono } from "hono";
import { logger } from "hono/logger";
import type { AppEnv } from "./app-env"
import { routeApi } from "./routes";
const app = new Hono<AppEnv>();
app.use("*", logger());
app.route("/api", routeApi);
app.notFound((c) => c.json({ message: "Not found" }, 404));
app.onError((err, c) => {
console.error(err);
return c.json({ message: "Internal Server Error" }, 500);
});
export default app;
2. oxlintでimportの設定をする
Viteでは雛型の段階でOxlintは次のような設定になっています。
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "typescript", "oxc"],
"rules": {
"react/rules-of-hooks": "error",
"react/only-export-components": ["warn", { "allowConstantExport": true }]
}
}
2-1. oxlintの設定ファイルを.oxlintrc.jsoncにする
oxlintはJSONにコメントがあっても動くのですが、エディターなどのために拡張子を .jsonc にします。
$ mv .oxlintrc.json .oxlintrc.jsonc
2-2. Webフロント用のコードでimportを制限する
Webフロントで使用するコードでimportを制限すると次のようになります。
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "typescript", "oxc"],
"rules": {
"react/rules-of-hooks": "error",
"react/only-export-components": ["warn", { "allowConstantExport": true }]
},
"overrides": [
{
// Browser Code
"files": ["src/**/*.{ts,tsx}"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"message": "This dependency is not allowed in browser code.",
"group": [
// 一旦全てを禁止する
"*",
// ローカルファイルは許可
"!./**",
"!@/**",
// Browser側で使用可能なnpm package
"!react",
"!react-dom/**"
]
}
]
}
]
}
}
]
}
まず、特定のファイルに対して制限をかけるために overrides を使用します。
"files": ["src/**/*.{ts,tsx}"] とすることでViteにおけるWebフロントのコードに対してlintの制限をかけます。
今回はimportの制限なので no-restricted-imports というルールを使用します。
error とすることでlintに引っかかったら終了コードが 1 になるようにしています。
import { useState } from "react"; と書いたときのfromで指定できなくしたいものを groups に書いていきます (この例だと react になる)。
groups に書くとき頭に ! をつけると逆に指定することを許可することになります。
そのため、①一旦全てのimportを禁止する、②その上で許可したいものを列挙する、という書き方をしています。
この groups では !react-dom と書いたとき、
import {} from 'react-dom'は許可されるimport {} from 'react-dom/client'は禁止のまま
ということになります。
そのため groups に !react-dom/** と記載しています。
使用するnpm packageが増えたら書き足していきます。
2-3. Worker用のコードでimportを制限する
同様に、Worker用のコードでimportを制限すると次のようになります。
(overrides で指定するものだけを記載します)
{
// Worker Code
"files": ["worker/**/*.ts"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"message": "This dependency is not allowed in Cloudflare Workers code.",
"group": [
// 一旦全てを禁止する
"*",
// ローカルファイルは許可
"!./**",
"!@worker/**",
// Browser側で使用可能なnpm package
"!hono",
"!hono/**"
]
}
]
}
]
}
}
2-4. .oxlintrc.jsonc の完成形
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "typescript", "oxc"],
"rules": {
"react/rules-of-hooks": "error",
"react/only-export-components": ["warn", { "allowConstantExport": true }]
},
"overrides": [
{
// Browser Code
"files": ["src/**/*.{ts,tsx}"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"message": "This dependency is not allowed in browser code.",
"group": [
// 一旦全てを禁止する
"*",
// ローカルファイルは許可
"!./**",
"!@/**",
// Browser側で使用可能なnpm package
"!react",
"!react-dom/**"
]
}
]
}
]
}
},
{
// Worker Code
"files": ["worker/**/*.ts"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"message": "This dependency is not allowed in Cloudflare Workers code.",
"group": [
// 一旦全てを禁止する
"*",
// ローカルファイルは許可
"!./**",
"!@worker/**",
// Browser側で使用可能なnpm package
"!hono",
"!hono/**"
]
}
]
}
]
}
}
]
}
まとめ
以上、oxlintを使ってWebフロント用のコードとWorker用コードでimportして良いパッケージを制限する話でした。
oxlintでlintをするときにエラーになるだけでビルドそのものは通ってしまいますが、間違いを減らすことはできると思います。
何かのお役に立てたら幸いです。








