Repository: tatethurston/nextjs-routes
Pull request #72 (2022-09-27 22:53:40)

Breaking change: next.config.js integration


Patch:
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 3084af5..e7f6609 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -1,7 +1,7 @@
 // eslint-disable-next-line no-undef
 module.exports = {
   root: true,
-  ignorePatterns: ["dist", "examples", "e2e"],
+  ignorePatterns: ["dist", "examples", "e2e", "coverage"],
   plugins: ["@typescript-eslint"],
   extends: [
     "eslint:recommended",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9d2c23f..5f11877 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,33 @@
 # Changelog
 
+## 0.1.0
+
+This release contains a breaking change, indicated by the minor version bump to 0.1.0. `nextjs-routes` has not yet reached v1, but will follow semantic versioning once it does. Until then, minor version changes will be used to help flag breaking changes.
+
+- Breaking change: the `withRoutes` import path and invocation has changed to better align with the general pattern in the Nextjs plugin ecosystem and to support configuration options, notably the new `outDir` option. It also now includes an ESM export to support usage in `next.config.mjs`.
+
+```diff
+- const { withRoutes } = require("nextjs-routes/next-config.cjs");
++ const withRoutes = require("nextjs-routes/config")();
+
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ reactStrictMode: true,
+};
+
+module.exports = withRoutes(nextConfig);
+```
+
+Note the import path has changed and the import itself has changed to function that is invoked with any configuration options. This provides better ergonomics for configuration options:
+
+```js
+const withRoutes = require("nextjs-routes/config")({ outDir: "types" });
+```
+
+- The type `RoutedQuery` has been added to retrieve the `Query` for a given `Route`. This is useful as the context type parameter inside `getStaticProps` and `getServerSideProps`. Thanks [@MariaSolOs](https://github.com/MariaSolOs) for the contribution!
+
+- `withRoutes` now accepts `outDir` as a configuration option to dictate where `nextjs-routes.d.ts` is generated. Thanks [@MariaSolOs](https://github.com/MariaSolOs) for the contribution!
+
 ## 0.0.22
 
 - Deprecate direct invocation of nextjs-routes in favor of automatic regeneration via [withRoutes](https://github.com/tatethurston/nextjs-routes#installation--usage-). See [#63](https://github.com/tatethurston/nextjs-routes/issues/63) for the motivation behind this change or to voice any concerns.
diff --git a/README.md b/README.md
index 1aa7716..9457052 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,18 @@
 
 A code generation tool to make `next/link` and `next/router` routes type safe with zero runtime overhead. `nextjs-routes` scans your `pages` directory and generates a `nextjs-routes.d.ts` file with type definitions for all your routes.
 
+## Highlights
+
+🦄 Zero config
+
+💨 Types only -- zero runtime
+
+🛠 No more broken links
+
+🪄 Route autocompletion
+
+🔗 Supports all Next.js route types: static, dynamic, catch all and optional catch all
+
 ## Installation & Usage 📦
 
 1. Add this package to your project:
@@ -37,7 +49,7 @@ A code generation tool to make `next/link` and `next/router` routes type safe wi
 2. Update your `next.config.js`:
 
    ```diff
-   + const { withRoutes } = require("nextjs-routes/next-config.cjs");
+   + const withRoutes = require("nextjs-routes/config")();
 
    /** @type {import('next').NextConfig} */
    const nextConfig = {
@@ -58,28 +70,6 @@ That's it! A `nextjs-routes.d.ts` file will be generated the first time you star
 
 Whenever your routes change, your `nextjs-routes.d.ts` file will automatically update.
 
-## Highlights
-
-🦄 Zero config
-
-💨 Types only -- zero runtime
-
-🛠 No more broken links
-
-🪄 Route autocompletion
-
-🔗 Supports all Next.js route types: static, dynamic, catch all and optional catch all
-
-## Configuration
-
-### withRoutes
-
-You can pass the following options to `withRoutes`:
-
-- `outDir`: The file path indicating the output directory where the generated route types
-  should be written to (e.g.: "types"). The default is to create the file in the same folder as your
-  `next-config.js` file.
-
 ## Examples 🛠
 
 ### Link
@@ -155,33 +145,32 @@ If you want to use the generated `Route` type in your code, you can import it fr
 import type { Route } from "nextjs-routes";
 ```
 
-## How does this work? 🤔
+### RoutedQuery
 
-`nextjs-routes` generates types for the `pathname` and `query` for every page in your `pages` directory. The generated types are written to `nextjs-routes.d.ts` which is automatically referenced by your Next project's `tsconfig.json`. `nextjs-routes.d.ts` redefines the types for `next/link` and `next/router` and applies the generated route types.
+If you want to use the generated `Query` for a given `Route`, you can import it from `nextjs-routes`:
 
-## Typed queries in static generation and server-side rendering
+```ts
+import type { RoutedQuery } from "nextjs-routes";
+```
 
-`nextjs-routes` exports the utility generic type `RoutedQuery` so that you can type the context parameter inside `getStaticProps` and `getServerSideProps`:
+This is useful as the context type parameter inside `getStaticProps` and `getServerSideProps`:
 
 ```ts
 import type { GetStaticProps } from "next";
 import type { RoutedQuery } from "nextjs-routes";
 
-type FooPageProps = { bar: string };
-
-export const getStaticProps: GetStaticProps<
-  FooPageProps,
-  RoutedQuery<"/foos/[foo]">
-> = (context) => {
-  // foo will be correctly typed to a string
-  const { foo } = context.params!;
-
-  return {
-    props: { foo },
-  };
+export const getStaticProps: GetStaticProps<{}, RoutedQuery<"/foos/[foo]">> = (
+  context
+) => {
+  // context.params will include `foo` as a string
+  const { foo } = context.params;
 };
 ```
 
+## How does this work? 🤔
+
+`nextjs-routes` generates types for the `pathname` and `query` for every page in your `pages` directory. The generated types are written to `nextjs-routes.d.ts` which is automatically referenced by your Next project's `tsconfig.json`. `nextjs-routes.d.ts` redefines the types for `next/link` and `next/router` and applies the generated route types.
+
 ## What if I need a runtime?
 
 There are some cases where you may want to generate a type safe path from a `Route` object, such as when `fetch`ing from an API route or serving redirects from `getServerSideProps`. These accept `strings` instead of the `Route` object that `Link` and `useRouter` accept. Because these do not perform the same string interpolation for dynamic routes, runtime code is required instead of a type only solution.
@@ -211,6 +200,12 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
 };
 ```
 
+## Configuration
+
+You can pass the following options to `withRoutes` in your `next.config.js`:
+
+- `outDir`: The file path indicating the output directory where the generated route types should be written to (e.g.: "types"). The default is to create the file in the same folder as your `next.config.js` file.
+
 ## Contributing 👫
 
 PR's and issues welcomed! For more guidance check out [CONTRIBUTING.md](https://github.com/tatethurston/nextjs-routes/blob/main/CONTRIBUTING.md)
diff --git a/examples/src-pages/next.config.js b/examples/src-pages/next.config.js
deleted file mode 100644
index 8c09b09..0000000
--- a/examples/src-pages/next.config.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/** @type {import('next').NextConfig} */
-const { withRoutes } = require("nextjs-routes/next-config.cjs");
-
-const nextConfig = {
-  reactStrictMode: true,
-};
-
-module.exports = withRoutes(nextConfig);
diff --git a/examples/src-pages/next.config.mjs b/examples/src-pages/next.config.mjs
new file mode 100644
index 0000000..e78af1c
--- /dev/null
+++ b/examples/src-pages/next.config.mjs
@@ -0,0 +1,7 @@
+import withRoutes from "nextjs-routes/config";
+
+const nextConfig = {
+  reactStrictMode: true,
+};
+
+export default withRoutes()(nextConfig);
diff --git a/examples/src-pages/nextjs-routes.d.ts b/examples/src-pages/nextjs-routes.d.ts
index 5b1939d..32b161f 100644
--- a/examples/src-pages/nextjs-routes.d.ts
+++ b/examples/src-pages/nextjs-routes.d.ts
@@ -10,15 +10,13 @@ declare module "nextjs-routes" {
     | { pathname: "/foos/[foo]"; query: Query<{ "foo": string }> }
     | { pathname: "/"; query?: Query | undefined };
 
-  export type Pathname = Route["pathname"];
-
   type Query<Params = {}> = Params & { [key: string]: string | string[] | undefined };
 
   type QueryForPathname = {
     [K in Route as K["pathname"]]: Exclude<K["query"], undefined>;
   };
 
-  export type RoutedQuery<P extends Pathname> = QueryForPathname[P];
+  export type RoutedQuery<P extends Route["pathname"]> = QueryForPathname[P];
 
   /**
    * A typesafe utility function for generating paths in your application.
@@ -58,7 +56,7 @@ declare module "next/link" {
 
 // prettier-ignore
 declare module "next/router" {
-  import type { Route, Pathname, RoutedQuery } from "nextjs-routes";
+  import type { Route, RoutedQuery } from "nextjs-routes";
   import type { NextRouter as Router } from "next/dist/client/router";
   export * from "next/dist/client/router";
   export { default } from "next/dist/client/router";
@@ -67,7 +65,7 @@ declare module "next/router" {
 
   type RouteOrQuery = Route | { query: { [key: string]: string | string[] | undefined } };
 
-  export interface NextRouter<P extends Pathname = Pathname>
+  export interface NextRouter<P extends Route["pathname"] = Route["pathname"]>
     extends Omit<Router, "push" | "replace"> {
     pathname: P;
     route: P;
@@ -84,5 +82,5 @@ declare module "next/router" {
     ): Promise<boolean>;
   }
 
-  export function useRouter<P extends Pathname>(): NextRouter<P>;
+  export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
diff --git a/examples/typescript/next.config.js b/examples/typescript/next.config.js
index 8c09b09..136d524 100644
--- a/examples/typescript/next.config.js
+++ b/examples/typescript/next.config.js
@@ -1,5 +1,7 @@
-/** @type {import('next').NextConfig} */
-const { withRoutes } = require("nextjs-routes/next-config.cjs");
+const withRoutes = require("nextjs-routes/config")({
+  // optional configuration: this will put the generated types in a types folder instead of at the project root.
+  outDir: "types",
+});
 
 const nextConfig = {
   reactStrictMode: true,
diff --git a/examples/typescript/nextjs-routes.d.ts b/examples/typescript/types/nextjs-routes.d.ts
similarity index 88%
rename from examples/typescript/nextjs-routes.d.ts
rename to examples/typescript/types/nextjs-routes.d.ts
index c36bad2..32b161f 100644
--- a/examples/typescript/nextjs-routes.d.ts
+++ b/examples/typescript/types/nextjs-routes.d.ts
@@ -12,6 +12,12 @@ declare module "nextjs-routes" {
 
   type Query<Params = {}> = Params & { [key: string]: string | string[] | undefined };
 
+  type QueryForPathname = {
+    [K in Route as K["pathname"]]: Exclude<K["query"], undefined>;
+  };
+
+  export type RoutedQuery<P extends Route["pathname"]> = QueryForPathname[P];
+
   /**
    * A typesafe utility function for generating paths in your application.
    *
@@ -50,26 +56,20 @@ declare module "next/link" {
 
 // prettier-ignore
 declare module "next/router" {
-  import type { Route } from "nextjs-routes";
+  import type { Route, RoutedQuery } from "nextjs-routes";
   import type { NextRouter as Router } from "next/dist/client/router";
   export * from "next/dist/client/router";
   export { default } from "next/dist/client/router";
 
   type TransitionOptions = Parameters<Router["push"]>[2];
 
-  type Pathname = Route["pathname"];
-
-  type QueryForPathname = {
-    [K in Route as K["pathname"]]: Exclude<K["query"], undefined>;
-  };
-
   type RouteOrQuery = Route | { query: { [key: string]: string | string[] | undefined } };
 
-  export interface NextRouter<P extends Pathname = Pathname>
+  export interface NextRouter<P extends Route["pathname"] = Route["pathname"]>
     extends Omit<Router, "push" | "replace"> {
     pathname: P;
     route: P;
-    query: QueryForPathname[P];
+    query: RoutedQuery<P>;
     push(
       url: RouteOrQuery,
       as?: string,
@@ -82,5 +82,5 @@ declare module "next/router" {
     ): Promise<boolean>;
   }
 
-  export function useRouter<P extends Pathname>(): NextRouter<P>;
+  export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
diff --git a/package-lock.json b/package-lock.json
index 150e53f..3af8025 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
       "devDependencies": {
         "@babel/preset-env": "^7.18.6",
         "@babel/preset-typescript": "^7.18.6",
+        "@swc/core": "^1.3.3",
         "@types/jest": "^29.0.3",
         "@types/node": "^18.0.3",
         "@types/react": "^18.0.15",
@@ -18,7 +19,6 @@
         "babel-loader": "^8.2.5",
         "chokidar": "^3.5.3",
         "codecov": "^3.8.3",
-        "esbuild": "^0.15.5",
         "eslint": "^8.19.0",
         "eslint-config-prettier": "^8.1.0",
         "husky": "^8.0.1",
@@ -27,7 +27,10 @@
         "prettier": "^2.7.1",
         "prettier-package-json": "^2.6.4",
         "react": "^18.2.0",
-        "typescript": "^4.7.4"
+        "swc-loader": "^0.2.3",
+        "typescript": "^4.7.4",
+        "webpack": "^5.74.0",
+        "webpack-cli": "^4.10.0"
       }
     },
     "node_modules/@ampproject/remapping": {
@@ -1676,6 +1679,15 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/@discoveryjs/json-ext": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
+      "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
     "node_modules/@eslint/eslintrc": {
       "version": "1.3.2",
       "dev": true,
@@ -2188,6 +2200,299 @@
         "@sinonjs/commons": "^1.7.0"
       }
     },
+    "node_modules/@swc/core": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.3.tgz",
+      "integrity": "sha512-OGx3Qpw+czNSaea1ojP2X2wxrGtYicQxH1QnzX4F3rXGEcSUFIllmrae6iJHW91zS4SNcOocnQoRz1IYnrILYw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "bin": {
+        "swcx": "run_swcx.js"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/swc"
+      },
+      "optionalDependencies": {
+        "@swc/core-android-arm-eabi": "1.3.3",
+        "@swc/core-android-arm64": "1.3.3",
+        "@swc/core-darwin-arm64": "1.3.3",
+        "@swc/core-darwin-x64": "1.3.3",
+        "@swc/core-freebsd-x64": "1.3.3",
+        "@swc/core-linux-arm-gnueabihf": "1.3.3",
+        "@swc/core-linux-arm64-gnu": "1.3.3",
+        "@swc/core-linux-arm64-musl": "1.3.3",
+        "@swc/core-linux-x64-gnu": "1.3.3",
+        "@swc/core-linux-x64-musl": "1.3.3",
+        "@swc/core-win32-arm64-msvc": "1.3.3",
+        "@swc/core-win32-ia32-msvc": "1.3.3",
+        "@swc/core-win32-x64-msvc": "1.3.3"
+      }
+    },
+    "node_modules/@swc/core-android-arm-eabi": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.3.3.tgz",
+      "integrity": "sha512-R6MpKXvNx/T/8a0wUTiX1THxfRbURSCmYlSi/JnUaqLYUclQK1N8aCMWz7EYSz6FE0VZBREJYDJcdnfP88E/1Q==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "dependencies": {
+        "@swc/wasm": "1.2.122"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-android-arm64": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-android-arm64/-/core-android-arm64-1.3.3.tgz",
+      "integrity": "sha512-yZlku4ypVKykwHTS8CETxw2PH23UBeM6VhNB8efF4A4gVWtRZjv1PfjsSqh/X0vjgVTrs2zSaQ+eF6GLVbWrgA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "dependencies": {
+        "@swc/wasm": "1.2.130"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-android-arm64/node_modules/@swc/wasm": {
+      "version": "1.2.130",
+      "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+      "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/@swc/core-darwin-arm64": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.3.tgz",
+      "integrity": "sha512-/T8vyikY7t/be6bHd1D9J/bmXYMDMkBo9NA3auDT/hmouzawhJ6E7OqRE4HLuLTflnRw8WmEWgpeRIzMHvNjBQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-darwin-x64": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.3.tgz",
+      "integrity": "sha512-hw4o1If986In5m3y3/OimgiBKJh49kbTG9MRWo8msqTic2aBlrtfHjSecMn1g+oP7pdaUUCTkovmT7OpvvQ/Tw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-freebsd-x64": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-freebsd-x64/-/core-freebsd-x64-1.3.3.tgz",
+      "integrity": "sha512-JFDu3uLa0WMw77o+QNR5D1uErQ5s18HmEwJr5ndOQoDlS+XO2qUG6AxU5LdwLEl5qMf2C99t7gkfzcCZG1PRsw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "dependencies": {
+        "@swc/wasm": "1.2.130"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-freebsd-x64/node_modules/@swc/wasm": {
+      "version": "1.2.130",
+      "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+      "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/@swc/core-linux-arm-gnueabihf": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.3.tgz",
+      "integrity": "sha512-kJoyNP/ury9KmZnjhpj0QApY6VxC9S4hkgsycm8yTJ23O8WrUbgeDOlgAgFJNyHszhR5CnlssDv7ErCwMZtkgw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "dependencies": {
+        "@swc/wasm": "1.2.130"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm-gnueabihf/node_modules/@swc/wasm": {
+      "version": "1.2.130",
+      "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+      "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/@swc/core-linux-arm64-gnu": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.3.tgz",
+      "integrity": "sha512-Y+10o78O2snKnrNTbasT9S3Out0wlOyAkLZvq5zqzW1cz2K2Yzm04zQdKQOCRHlfTF0XSmZ++qRWVNol49WsNA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm64-musl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.3.tgz",
+      "integrity": "sha512-y6ErPP6Sk0f8exoanUxXeFALvPraTjyoVr8pitpfTqoUd9YcxwOTpPbR5WXI3FWnQ7GS86iH0LvaFDCgHQ1fjg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-x64-gnu": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.3.tgz",
+      "integrity": "sha512-sqyvNJkPHKHlK/XLIoMNLiux8YxsCJpAk3UreS0NO+sRNRru2AMyrRwX6wxmnJybhEek9SPKF0pXi+GfcaFKYA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-x64-musl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.3.tgz",
+      "integrity": "sha512-5fjwHdMv+DOgEp7sdNVmvS4Hr2rDaewa0BpDW8RefcjHoJnDpFVButLDMkwv/Yd+v4YN+99kyX/lOI+/OTD99w==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-arm64-msvc": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.3.tgz",
+      "integrity": "sha512-JxcfG89GieqCFXkRl/mtFds/ME6ncEtLRIQ0+RBIREIGisA9ZgJ8EryBzGZyPu5+7kE0vXGVB6A2cfrv4SNW4A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "dependencies": {
+        "@swc/wasm": "1.2.130"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-arm64-msvc/node_modules/@swc/wasm": {
+      "version": "1.2.130",
+      "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+      "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/@swc/core-win32-ia32-msvc": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.3.tgz",
+      "integrity": "sha512-yqZjTn5V7wYCxMCC5Rg8u87SmGeRSlqYAafHL3IgiFe8hSxOykc2dR1MYNc4WZumYiMlU15VSa6mW8A0pj37FA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "dependencies": {
+        "@swc/wasm": "1.2.130"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-ia32-msvc/node_modules/@swc/wasm": {
+      "version": "1.2.130",
+      "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+      "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/@swc/core-win32-x64-msvc": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.3.tgz",
+      "integrity": "sha512-CIuxz9wiHkgG7m3kjgptgO3iHOmrybvLf0rUNGbVTTHwTcrpjznAnS/MnMPiaIQPlxz70KSXAR2QJjw7fGtfbA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/@swc/helpers": {
       "version": "0.4.11",
       "dev": true,
@@ -2201,6 +2506,13 @@
       "dev": true,
       "license": "0BSD"
     },
+    "node_modules/@swc/wasm": {
+      "version": "1.2.122",
+      "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.122.tgz",
+      "integrity": "sha512-sM1VCWQxmNhFtdxME+8UXNyPNhxNu7zdb6ikWpz0YKAQQFRGT5ThZgJrubEpah335SUToNg8pkdDF7ibVCjxbQ==",
+      "dev": true,
+      "optional": true
+    },
     "node_modules/@tootallnate/once": {
       "version": "1.1.2",
       "dev": true,
@@ -2715,6 +3027,42 @@
         "@xtuc/long": "4.2.2"
       }
     },
+    "node_modules/@webpack-cli/configtest": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
+      "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
+      "dev": true,
+      "peerDependencies": {
+        "webpack": "4.x.x || 5.x.x",
+        "webpack-cli": "4.x.x"
+      }
+    },
+    "node_modules/@webpack-cli/info": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
+      "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
+      "dev": true,
+      "dependencies": {
+        "envinfo": "^7.7.3"
+      },
+      "peerDependencies": {
+        "webpack-cli": "4.x.x"
+      }
+    },
+    "node_modules/@webpack-cli/serve": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
+      "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
+      "dev": true,
+      "peerDependencies": {
+        "webpack-cli": "4.x.x"
+      },
+      "peerDependenciesMeta": {
+        "webpack-dev-server": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@xtuc/ieee754": {
       "version": "1.2.0",
       "dev": true,
@@ -3245,6 +3593,20 @@
         "wrap-ansi": "^7.0.0"
       }
     },
+    "node_modules/clone-deep": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
+      "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4",
+        "kind-of": "^6.0.2",
+        "shallow-clone": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/co": {
       "version": "4.6.0",
       "dev": true,
@@ -3293,6 +3655,12 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/colorette": {
+      "version": "2.0.19",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
+      "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+      "dev": true
+    },
     "node_modules/commander": {
       "version": "4.1.1",
       "dev": true,
@@ -3492,6 +3860,18 @@
         "node": ">=10.13.0"
       }
     },
+    "node_modules/envinfo": {
+      "version": "7.8.1",
+      "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
+      "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
+      "dev": true,
+      "bin": {
+        "envinfo": "dist/cli.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/error-ex": {
       "version": "1.3.2",
       "dev": true,
@@ -3505,57 +3885,6 @@
       "dev": true,
       "license": "MIT"
     },
-    "node_modules/esbuild": {
-      "version": "0.15.9",
-      "dev": true,
-      "hasInstallScript": true,
-      "license": "MIT",
-      "bin": {
-        "esbuild": "bin/esbuild"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "optionalDependencies": {
-        "@esbuild/android-arm": "0.15.9",
-        "@esbuild/linux-loong64": "0.15.9",
-        "esbuild-android-64": "0.15.9",
-        "esbuild-android-arm64": "0.15.9",
-        "esbuild-darwin-64": "0.15.9",
-        "esbuild-darwin-arm64": "0.15.9",
-        "esbuild-freebsd-64": "0.15.9",
-        "esbuild-freebsd-arm64": "0.15.9",
-        "esbuild-linux-32": "0.15.9",
-        "esbuild-linux-64": "0.15.9",
-        "esbuild-linux-arm": "0.15.9",
-        "esbuild-linux-arm64": "0.15.9",
-        "esbuild-linux-mips64le": "0.15.9",
-        "esbuild-linux-ppc64le": "0.15.9",
-        "esbuild-linux-riscv64": "0.15.9",
-        "esbuild-linux-s390x": "0.15.9",
-        "esbuild-netbsd-64": "0.15.9",
-        "esbuild-openbsd-64": "0.15.9",
-        "esbuild-sunos-64": "0.15.9",
-        "esbuild-windows-32": "0.15.9",
-        "esbuild-windows-64": "0.15.9",
-        "esbuild-windows-arm64": "0.15.9"
-      }
-    },
-    "node_modules/esbuild-darwin-64": {
-      "version": "0.15.9",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
     "node_modules/escalade": {
       "version": "3.1.1",
       "dev": true,
@@ -3946,6 +4275,15 @@
         "punycode": "^1.3.2"
       }
     },
+    "node_modules/fastest-levenshtein": {
+      "version": "1.0.16",
+      "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+      "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4.9.1"
+      }
+    },
     "node_modules/fastq": {
       "version": "1.13.0",
       "dev": true,
@@ -4356,6 +4694,15 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/interpret": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
+      "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/is-arrayish": {
       "version": "0.2.1",
       "dev": true,
@@ -4426,6 +4773,18 @@
         "node": ">=0.12.0"
       }
     },
+    "node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/is-stream": {
       "version": "2.0.1",
       "dev": true,
@@ -4442,6 +4801,15 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/istanbul-lib-coverage": {
       "version": "3.2.0",
       "dev": true,
@@ -5104,6 +5472,15 @@
         "graceful-fs": "^4.1.6"
       }
     },
+    "node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/kleur": {
       "version": "3.0.3",
       "dev": true,
@@ -5811,6 +6188,18 @@
         "node": ">=8.10.0"
       }
     },
+    "node_modules/rechoir": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
+      "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
+      "dev": true,
+      "dependencies": {
+        "resolve": "^1.9.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/regenerate": {
       "version": "1.4.2",
       "dev": true,
@@ -6024,6 +6413,18 @@
         "randombytes": "^2.1.0"
       }
     },
+    "node_modules/shallow-clone": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
+      "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/shebang-command": {
       "version": "2.0.0",
       "dev": true,
@@ -6249,6 +6650,16 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/swc-loader": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.3.tgz",
+      "integrity": "sha512-D1p6XXURfSPleZZA/Lipb3A8pZ17fP4NObZvFCDjK/OKljroqDpPmsBdTraWhVBqUNpcWBQY1imWdoPScRlQ7A==",
+      "dev": true,
+      "peerDependencies": {
+        "@swc/core": "^1.2.147",
+        "webpack": ">=2"
+      }
+    },
     "node_modules/tapable": {
       "version": "2.2.1",
       "dev": true,
@@ -6635,8 +7046,9 @@
     },
     "node_modules/webpack": {
       "version": "5.74.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
+      "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@types/eslint-scope": "^3.7.3",
         "@types/estree": "^0.0.51",
@@ -6679,6 +7091,75 @@
         }
       }
     },
+    "node_modules/webpack-cli": {
+      "version": "4.10.0",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
+      "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
+      "dev": true,
+      "dependencies": {
+        "@discoveryjs/json-ext": "^0.5.0",
+        "@webpack-cli/configtest": "^1.2.0",
+        "@webpack-cli/info": "^1.5.0",
+        "@webpack-cli/serve": "^1.7.0",
+        "colorette": "^2.0.14",
+        "commander": "^7.0.0",
+        "cross-spawn": "^7.0.3",
+        "fastest-levenshtein": "^1.0.12",
+        "import-local": "^3.0.2",
+        "interpret": "^2.2.0",
+        "rechoir": "^0.7.0",
+        "webpack-merge": "^5.7.3"
+      },
+      "bin": {
+        "webpack-cli": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "4.x.x || 5.x.x"
+      },
+      "peerDependenciesMeta": {
+        "@webpack-cli/generators": {
+          "optional": true
+        },
+        "@webpack-cli/migrate": {
+          "optional": true
+        },
+        "webpack-bundle-analyzer": {
+          "optional": true
+        },
+        "webpack-dev-server": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/webpack-cli/node_modules/commander": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+      "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/webpack-merge": {
+      "version": "5.8.0",
+      "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
+      "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
+      "dev": true,
+      "dependencies": {
+        "clone-deep": "^4.0.1",
+        "wildcard": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
     "node_modules/webpack-sources": {
       "version": "3.2.3",
       "dev": true,
@@ -6715,6 +7196,12 @@
         "node": ">= 8"
       }
     },
+    "node_modules/wildcard": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
+      "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
+      "dev": true
+    },
     "node_modules/word-wrap": {
       "version": "1.2.3",
       "dev": true,
@@ -7813,6 +8300,12 @@
       "version": "0.2.3",
       "dev": true
     },
+    "@discoveryjs/json-ext": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
+      "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
+      "dev": true
+    },
     "@eslint/eslintrc": {
       "version": "1.3.2",
       "dev": true,
@@ -8167,6 +8660,181 @@
         "@sinonjs/commons": "^1.7.0"
       }
     },
+    "@swc/core": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.3.tgz",
+      "integrity": "sha512-OGx3Qpw+czNSaea1ojP2X2wxrGtYicQxH1QnzX4F3rXGEcSUFIllmrae6iJHW91zS4SNcOocnQoRz1IYnrILYw==",
+      "dev": true,
+      "requires": {
+        "@swc/core-android-arm-eabi": "1.3.3",
+        "@swc/core-android-arm64": "1.3.3",
+        "@swc/core-darwin-arm64": "1.3.3",
+        "@swc/core-darwin-x64": "1.3.3",
+        "@swc/core-freebsd-x64": "1.3.3",
+        "@swc/core-linux-arm-gnueabihf": "1.3.3",
+        "@swc/core-linux-arm64-gnu": "1.3.3",
+        "@swc/core-linux-arm64-musl": "1.3.3",
+        "@swc/core-linux-x64-gnu": "1.3.3",
+        "@swc/core-linux-x64-musl": "1.3.3",
+        "@swc/core-win32-arm64-msvc": "1.3.3",
+        "@swc/core-win32-ia32-msvc": "1.3.3",
+        "@swc/core-win32-x64-msvc": "1.3.3"
+      }
+    },
+    "@swc/core-android-arm-eabi": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.3.3.tgz",
+      "integrity": "sha512-R6MpKXvNx/T/8a0wUTiX1THxfRbURSCmYlSi/JnUaqLYUclQK1N8aCMWz7EYSz6FE0VZBREJYDJcdnfP88E/1Q==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@swc/wasm": "1.2.122"
+      }
+    },
+    "@swc/core-android-arm64": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-android-arm64/-/core-android-arm64-1.3.3.tgz",
+      "integrity": "sha512-yZlku4ypVKykwHTS8CETxw2PH23UBeM6VhNB8efF4A4gVWtRZjv1PfjsSqh/X0vjgVTrs2zSaQ+eF6GLVbWrgA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@swc/wasm": "1.2.130"
+      },
+      "dependencies": {
+        "@swc/wasm": {
+          "version": "1.2.130",
+          "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+          "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "@swc/core-darwin-arm64": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.3.tgz",
+      "integrity": "sha512-/T8vyikY7t/be6bHd1D9J/bmXYMDMkBo9NA3auDT/hmouzawhJ6E7OqRE4HLuLTflnRw8WmEWgpeRIzMHvNjBQ==",
+      "dev": true,
+      "optional": true
+    },
+    "@swc/core-darwin-x64": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.3.tgz",
+      "integrity": "sha512-hw4o1If986In5m3y3/OimgiBKJh49kbTG9MRWo8msqTic2aBlrtfHjSecMn1g+oP7pdaUUCTkovmT7OpvvQ/Tw==",
+      "dev": true,
+      "optional": true
+    },
+    "@swc/core-freebsd-x64": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-freebsd-x64/-/core-freebsd-x64-1.3.3.tgz",
+      "integrity": "sha512-JFDu3uLa0WMw77o+QNR5D1uErQ5s18HmEwJr5ndOQoDlS+XO2qUG6AxU5LdwLEl5qMf2C99t7gkfzcCZG1PRsw==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@swc/wasm": "1.2.130"
+      },
+      "dependencies": {
+        "@swc/wasm": {
+          "version": "1.2.130",
+          "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+          "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "@swc/core-linux-arm-gnueabihf": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.3.tgz",
+      "integrity": "sha512-kJoyNP/ury9KmZnjhpj0QApY6VxC9S4hkgsycm8yTJ23O8WrUbgeDOlgAgFJNyHszhR5CnlssDv7ErCwMZtkgw==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@swc/wasm": "1.2.130"
+      },
+      "dependencies": {
+        "@swc/wasm": {
+          "version": "1.2.130",
+          "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+          "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "@swc/core-linux-arm64-gnu": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.3.tgz",
+      "integrity": "sha512-Y+10o78O2snKnrNTbasT9S3Out0wlOyAkLZvq5zqzW1cz2K2Yzm04zQdKQOCRHlfTF0XSmZ++qRWVNol49WsNA==",
+      "dev": true,
+      "optional": true
+    },
+    "@swc/core-linux-arm64-musl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.3.tgz",
+      "integrity": "sha512-y6ErPP6Sk0f8exoanUxXeFALvPraTjyoVr8pitpfTqoUd9YcxwOTpPbR5WXI3FWnQ7GS86iH0LvaFDCgHQ1fjg==",
+      "dev": true,
+      "optional": true
+    },
+    "@swc/core-linux-x64-gnu": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.3.tgz",
+      "integrity": "sha512-sqyvNJkPHKHlK/XLIoMNLiux8YxsCJpAk3UreS0NO+sRNRru2AMyrRwX6wxmnJybhEek9SPKF0pXi+GfcaFKYA==",
+      "dev": true,
+      "optional": true
+    },
+    "@swc/core-linux-x64-musl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.3.tgz",
+      "integrity": "sha512-5fjwHdMv+DOgEp7sdNVmvS4Hr2rDaewa0BpDW8RefcjHoJnDpFVButLDMkwv/Yd+v4YN+99kyX/lOI+/OTD99w==",
+      "dev": true,
+      "optional": true
+    },
+    "@swc/core-win32-arm64-msvc": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.3.tgz",
+      "integrity": "sha512-JxcfG89GieqCFXkRl/mtFds/ME6ncEtLRIQ0+RBIREIGisA9ZgJ8EryBzGZyPu5+7kE0vXGVB6A2cfrv4SNW4A==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@swc/wasm": "1.2.130"
+      },
+      "dependencies": {
+        "@swc/wasm": {
+          "version": "1.2.130",
+          "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+          "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "@swc/core-win32-ia32-msvc": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.3.tgz",
+      "integrity": "sha512-yqZjTn5V7wYCxMCC5Rg8u87SmGeRSlqYAafHL3IgiFe8hSxOykc2dR1MYNc4WZumYiMlU15VSa6mW8A0pj37FA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@swc/wasm": "1.2.130"
+      },
+      "dependencies": {
+        "@swc/wasm": {
+          "version": "1.2.130",
+          "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.130.tgz",
+          "integrity": "sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "@swc/core-win32-x64-msvc": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.3.tgz",
+      "integrity": "sha512-CIuxz9wiHkgG7m3kjgptgO3iHOmrybvLf0rUNGbVTTHwTcrpjznAnS/MnMPiaIQPlxz70KSXAR2QJjw7fGtfbA==",
+      "dev": true,
+      "optional": true
+    },
     "@swc/helpers": {
       "version": "0.4.11",
       "dev": true,
@@ -8180,6 +8848,13 @@
         }
       }
     },
+    "@swc/wasm": {
+      "version": "1.2.122",
+      "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.2.122.tgz",
+      "integrity": "sha512-sM1VCWQxmNhFtdxME+8UXNyPNhxNu7zdb6ikWpz0YKAQQFRGT5ThZgJrubEpah335SUToNg8pkdDF7ibVCjxbQ==",
+      "dev": true,
+      "optional": true
+    },
     "@tootallnate/once": {
       "version": "1.1.2",
       "dev": true
@@ -8544,6 +9219,29 @@
         "@xtuc/long": "4.2.2"
       }
     },
+    "@webpack-cli/configtest": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
+      "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
+      "dev": true,
+      "requires": {}
+    },
+    "@webpack-cli/info": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
+      "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
+      "dev": true,
+      "requires": {
+        "envinfo": "^7.7.3"
+      }
+    },
+    "@webpack-cli/serve": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
+      "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
+      "dev": true,
+      "requires": {}
+    },
     "@xtuc/ieee754": {
       "version": "1.2.0",
       "dev": true
@@ -8866,6 +9564,17 @@
         "wrap-ansi": "^7.0.0"
       }
     },
+    "clone-deep": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
+      "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
+      "dev": true,
+      "requires": {
+        "is-plain-object": "^2.0.4",
+        "kind-of": "^6.0.2",
+        "shallow-clone": "^3.0.0"
+      }
+    },
     "co": {
       "version": "4.6.0",
       "dev": true
@@ -8896,6 +9605,12 @@
       "version": "1.1.4",
       "dev": true
     },
+    "colorette": {
+      "version": "2.0.19",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
+      "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+      "dev": true
+    },
     "commander": {
       "version": "4.1.1",
       "dev": true
@@ -9019,6 +9734,12 @@
         "tapable": "^2.2.0"
       }
     },
+    "envinfo": {
+      "version": "7.8.1",
+      "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
+      "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
+      "dev": true
+    },
     "error-ex": {
       "version": "1.3.2",
       "dev": true,
@@ -9030,39 +9751,6 @@
       "version": "0.9.3",
       "dev": true
     },
-    "esbuild": {
-      "version": "0.15.9",
-      "dev": true,
-      "requires": {
-        "@esbuild/android-arm": "0.15.9",
-        "@esbuild/linux-loong64": "0.15.9",
-        "esbuild-android-64": "0.15.9",
-        "esbuild-android-arm64": "0.15.9",
-        "esbuild-darwin-64": "0.15.9",
-        "esbuild-darwin-arm64": "0.15.9",
-        "esbuild-freebsd-64": "0.15.9",
-        "esbuild-freebsd-arm64": "0.15.9",
-        "esbuild-linux-32": "0.15.9",
-        "esbuild-linux-64": "0.15.9",
-        "esbuild-linux-arm": "0.15.9",
-        "esbuild-linux-arm64": "0.15.9",
-        "esbuild-linux-mips64le": "0.15.9",
-        "esbuild-linux-ppc64le": "0.15.9",
-        "esbuild-linux-riscv64": "0.15.9",
-        "esbuild-linux-s390x": "0.15.9",
-        "esbuild-netbsd-64": "0.15.9",
-        "esbuild-openbsd-64": "0.15.9",
-        "esbuild-sunos-64": "0.15.9",
-        "esbuild-windows-32": "0.15.9",
-        "esbuild-windows-64": "0.15.9",
-        "esbuild-windows-arm64": "0.15.9"
-      }
-    },
-    "esbuild-darwin-64": {
-      "version": "0.15.9",
-      "dev": true,
-      "optional": true
-    },
     "escalade": {
       "version": "3.1.1",
       "dev": true
@@ -9308,6 +9996,12 @@
         "punycode": "^1.3.2"
       }
     },
+    "fastest-levenshtein": {
+      "version": "1.0.16",
+      "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+      "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
+      "dev": true
+    },
     "fastq": {
       "version": "1.13.0",
       "dev": true,
@@ -9559,6 +10253,12 @@
       "version": "2.0.4",
       "dev": true
     },
+    "interpret": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
+      "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
+      "dev": true
+    },
     "is-arrayish": {
       "version": "0.2.1",
       "dev": true
@@ -9600,6 +10300,15 @@
       "version": "7.0.0",
       "dev": true
     },
+    "is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
     "is-stream": {
       "version": "2.0.1",
       "dev": true
@@ -9608,6 +10317,12 @@
       "version": "2.0.0",
       "dev": true
     },
+    "isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+      "dev": true
+    },
     "istanbul-lib-coverage": {
       "version": "3.2.0",
       "dev": true
@@ -10067,6 +10782,12 @@
         "universalify": "^2.0.0"
       }
     },
+    "kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true
+    },
     "kleur": {
       "version": "3.0.3",
       "dev": true
@@ -10472,6 +11193,15 @@
         "picomatch": "^2.2.1"
       }
     },
+    "rechoir": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
+      "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
+      "dev": true,
+      "requires": {
+        "resolve": "^1.9.0"
+      }
+    },
     "regenerate": {
       "version": "1.4.2",
       "dev": true
@@ -10597,6 +11327,15 @@
         "randombytes": "^2.1.0"
       }
     },
+    "shallow-clone": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
+      "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^6.0.2"
+      }
+    },
     "shebang-command": {
       "version": "2.0.0",
       "dev": true,
@@ -10732,6 +11471,13 @@
       "version": "1.0.0",
       "dev": true
     },
+    "swc-loader": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.3.tgz",
+      "integrity": "sha512-D1p6XXURfSPleZZA/Lipb3A8pZ17fP4NObZvFCDjK/OKljroqDpPmsBdTraWhVBqUNpcWBQY1imWdoPScRlQ7A==",
+      "dev": true,
+      "requires": {}
+    },
     "tapable": {
       "version": "2.2.1",
       "dev": true
@@ -10961,6 +11707,8 @@
     },
     "webpack": {
       "version": "5.74.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
+      "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
       "dev": true,
       "requires": {
         "@types/eslint-scope": "^3.7.3",
@@ -10995,6 +11743,44 @@
         }
       }
     },
+    "webpack-cli": {
+      "version": "4.10.0",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
+      "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
+      "dev": true,
+      "requires": {
+        "@discoveryjs/json-ext": "^0.5.0",
+        "@webpack-cli/configtest": "^1.2.0",
+        "@webpack-cli/info": "^1.5.0",
+        "@webpack-cli/serve": "^1.7.0",
+        "colorette": "^2.0.14",
+        "commander": "^7.0.0",
+        "cross-spawn": "^7.0.3",
+        "fastest-levenshtein": "^1.0.12",
+        "import-local": "^3.0.2",
+        "interpret": "^2.2.0",
+        "rechoir": "^0.7.0",
+        "webpack-merge": "^5.7.3"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+          "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+          "dev": true
+        }
+      }
+    },
+    "webpack-merge": {
+      "version": "5.8.0",
+      "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
+      "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
+      "dev": true,
+      "requires": {
+        "clone-deep": "^4.0.1",
+        "wildcard": "^2.0.0"
+      }
+    },
     "webpack-sources": {
       "version": "3.2.3",
       "dev": true
@@ -11014,6 +11800,12 @@
         "isexe": "^2.0.0"
       }
     },
+    "wildcard": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
+      "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
+      "dev": true
+    },
     "word-wrap": {
       "version": "1.2.3",
       "dev": true
diff --git a/package.json b/package.json
index d22be8f..959217e 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
   },
   "type": "module",
   "scripts": {
-    "build:commonjs": "esbuild src/next-config.cts --bundle --platform=node --outfile=dist/next-config.cjs --external:chokidar",
+    "build:commonjs": "webpack",
     "build:module": "tsc",
     "clean": "rm -rf dist",
     "e2e:setup": "npm run package:build && (cd e2e && npm install && npx next build)",
@@ -18,7 +18,7 @@
     "examples:setup": "npm run examples:each --command='npm install'",
     "lint": "npm run typecheck && prettier --check . && prettier-package-json --list-different '{,public.,example/}package.json' && eslint .",
     "lint:fix": "prettier --write '**/*.{ts,cts,mts,tsx,md,json}' && prettier-package-json --write '{,public.,example/}package.json' && eslint --fix .",
-    "package:build": "npm install && npm run build:module && npm run build:commonjs && npm run package:prune && npm run package:copy:files && chmod +x dist/cli.js",
+    "package:build": "npm install && npm run clean && npm run build:module && npm run build:commonjs && npm run package:prune && npm run package:copy:files && chmod +x dist/cli.js",
     "package:copy:files": "cp ./LICENSE ./README.md dist/ && cp ./public.package.json dist/package.json",
     "package:prune": "find dist -name *.test.* | xargs rm -f",
     "prepare": "husky install",
@@ -30,6 +30,7 @@
   "devDependencies": {
     "@babel/preset-env": "^7.18.6",
     "@babel/preset-typescript": "^7.18.6",
+    "@swc/core": "^1.3.3",
     "@types/jest": "^29.0.3",
     "@types/node": "^18.0.3",
     "@types/react": "^18.0.15",
@@ -39,7 +40,6 @@
     "babel-loader": "^8.2.5",
     "chokidar": "^3.5.3",
     "codecov": "^3.8.3",
-    "esbuild": "^0.15.5",
     "eslint": "^8.19.0",
     "eslint-config-prettier": "^8.1.0",
     "husky": "^8.0.1",
@@ -48,6 +48,9 @@
     "prettier": "^2.7.1",
     "prettier-package-json": "^2.6.4",
     "react": "^18.2.0",
-    "typescript": "^4.7.4"
+    "swc-loader": "^0.2.3",
+    "typescript": "^4.7.4",
+    "webpack": "^5.74.0",
+    "webpack-cli": "^4.10.0"
   }
 }
diff --git a/public.package.json b/public.package.json
index 5b865bd..760df73 100644
--- a/public.package.json
+++ b/public.package.json
@@ -1,6 +1,6 @@
 {
   "name": "nextjs-routes",
-  "version": "0.0.22",
+  "version": "0.1.0",
   "description": "Type safe routing for Next.js",
   "license": "MIT",
   "author": "Tate <tatethurston@gmail.com>",
@@ -12,7 +12,10 @@
   "exports": {
     ".": "./index.js",
     "./package.json": "./package.json",
-    "./next-config.cjs": "./next-config.cjs"
+    "./config": {
+      "import": "./config.js",
+      "require": "./config.cjs"
+    }
   },
   "bin": {
     "nextjs-routes": "cli.js"
diff --git a/src/next-config.cts b/src/config.ts
similarity index 63%
rename from src/next-config.cts
rename to src/config.ts
index 1289038..4ad0cc6 100644
--- a/src/next-config.cts
+++ b/src/config.ts
@@ -6,9 +6,10 @@
 import type { NextConfig } from "next";
 import { join } from "path";
 import type { Configuration, WebpackPluginInstance } from "webpack";
-import { getPagesDirectory } from "./utils";
+import { getPagesDirectory } from "./utils.js";
 import { watch } from "chokidar";
-import { writeNextjsRoutes } from "./core";
+import { writeNextjsRoutes } from "./core.js";
+import { existsSync, mkdirSync } from "fs";
 
 function debounce<Fn extends (...args: unknown[]) => unknown>(
   fn: Fn,
@@ -41,10 +42,11 @@ class NextJSRoutesPlugin implements WebpackPluginInstance {
 
   apply() {
     const pagesDirectory = getPagesDirectory();
-    const outputFilepath = join(
-      this.options?.outDir ?? "",
-      "nextjs-routes.d.ts"
-    );
+    const outDir = this.options?.outDir ?? "";
+    if (outDir && !existsSync(outDir)) {
+      mkdirSync(outDir, { recursive: true });
+    }
+    const outputFilepath = join(outDir, "nextjs-routes.d.ts");
     if (pagesDirectory) {
       if (this.config.watch) {
         const dir = join(process.cwd(), pagesDirectory);
@@ -64,32 +66,33 @@ class NextJSRoutesPlugin implements WebpackPluginInstance {
   }
 }
 
-export function withRoutes(
-  nextConfig: NextConfig,
+export default function withRoutes(
   options?: NextJSRoutesOptions
-): NextConfig {
-  return {
-    ...nextConfig,
-    webpack: (config: Configuration, context) => {
-      if (!config.plugins) {
-        config.plugins = [];
-      }
+): (nextConfig: NextConfig) => NextConfig {
+  return function (nextConfig) {
+    return {
+      ...nextConfig,
+      webpack: (config: Configuration, context) => {
+        if (!config.plugins) {
+          config.plugins = [];
+        }
 
-      // only watch in development
-      config.plugins.push(
-        new NextJSRoutesPlugin(
-          {
-            watch: context.dev && !context.isServer,
-          },
-          options
-        )
-      );
+        // only watch in development
+        config.plugins.push(
+          new NextJSRoutesPlugin(
+            {
+              watch: context.dev && !context.isServer,
+            },
+            options
+          )
+        );
 
-      // invoke any existing webpack extensions
-      if (nextConfig.webpack) {
-        return nextConfig.webpack(config, context);
-      }
-      return config;
-    },
+        // invoke any existing webpack extensions
+        if (nextConfig.webpack) {
+          return nextConfig.webpack(config, context);
+        }
+        return config;
+      },
+    };
   };
 }
diff --git a/src/core.ts b/src/core.ts
index cc204d9..980afa9 100644
--- a/src/core.ts
+++ b/src/core.ts
@@ -115,15 +115,13 @@ declare module "nextjs-routes" {
             .join("\n    | ")}`
     };
 
-  export type Pathname = Route["pathname"];
-
   type Query<Params = {}> = Params & ${unknownQueryParamsType};
 
   type QueryForPathname = {
     [K in Route as K["pathname"]]: Exclude<K["query"], undefined>;
   };
 
-  export type RoutedQuery<P extends Pathname> = QueryForPathname[P];
+  export type RoutedQuery<P extends Route["pathname"]> = QueryForPathname[P];
 
   /**
    * A typesafe utility function for generating paths in your application.
@@ -163,7 +161,7 @@ declare module "next/link" {
 
 // prettier-ignore
 declare module "next/router" {
-  import type { Route, Pathname, RoutedQuery } from "nextjs-routes";
+  import type { Route, RoutedQuery } from "nextjs-routes";
   import type { NextRouter as Router } from "next/dist/client/router";
   export * from "next/dist/client/router";
   export { default } from "next/dist/client/router";
@@ -172,7 +170,7 @@ declare module "next/router" {
 
   type RouteOrQuery = Route | { query: ${unknownQueryParamsType} };
 
-  export interface NextRouter<P extends Pathname = Pathname>
+  export interface NextRouter<P extends Route["pathname"] = Route["pathname"]>
     extends Omit<Router, "push" | "replace"> {
     pathname: P;
     route: P;
@@ -189,7 +187,7 @@ declare module "next/router" {
     ): Promise<boolean>;
   }
 
-  export function useRouter<P extends Pathname>(): NextRouter<P>;
+  export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
 `;
 }
diff --git a/webpack.config.cjs b/webpack.config.cjs
new file mode 100644
index 0000000..2f33e37
--- /dev/null
+++ b/webpack.config.cjs
@@ -0,0 +1,43 @@
+const { join } = require("path");
+
+const file = "config";
+
+module.exports = {
+  entry: `./src/${file}.ts`,
+  target: "node",
+  mode: "production",
+  output: {
+    filename: file + ".cjs",
+    library: {
+      type: "commonjs2",
+      export: "default",
+    },
+    path: join(__dirname, "dist"),
+  },
+  externals: {
+    chokidar: "commonjs chokidar",
+  },
+  resolve: {
+    extensionAlias: {
+      ".js": [".ts", ".js"],
+    },
+  },
+  module: {
+    rules: [
+      {
+        test: /\.(m|c)?tsx?$/,
+        exclude: /node_modules/,
+        use: {
+          loader: "swc-loader",
+          options: {
+            jsc: {
+              parser: {
+                syntax: "typescript",
+              },
+            },
+          },
+        },
+      },
+    ],
+  },
+};


Test patch:
diff --git a/e2e/next.config.js b/e2e/next.config.js
new file mode 100644
index 0000000..75cc307
--- /dev/null
+++ b/e2e/next.config.js
@@ -0,0 +1,7 @@
+const withRoutes = require("nextjs-routes/config")();
+
+const nextConfig = {
+  reactStrictMode: true,
+};
+
+module.exports = withRoutes(nextConfig);
diff --git a/e2e/nextjs-routes.d.ts b/e2e/nextjs-routes.d.ts
index 2507d65..945b731 100644
--- a/e2e/nextjs-routes.d.ts
+++ b/e2e/nextjs-routes.d.ts
@@ -8,15 +8,13 @@ declare module "nextjs-routes" {
     | { pathname: "/foos/[foo]"; query: Query<{ "foo": string }> }
     | { pathname: "/"; query?: Query | undefined };
 
-  export type Pathname = Route["pathname"];
-
   type Query<Params = {}> = Params & { [key: string]: string | string[] | undefined };
 
   type QueryForPathname = {
     [K in Route as K["pathname"]]: Exclude<K["query"], undefined>;
   };
 
-  export type RoutedQuery<P extends Pathname> = QueryForPathname[P];
+  export type RoutedQuery<P extends Route["pathname"]> = QueryForPathname[P];
 
   /**
    * A typesafe utility function for generating paths in your application.
@@ -56,7 +54,7 @@ declare module "next/link" {
 
 // prettier-ignore
 declare module "next/router" {
-  import type { Route, Pathname, RoutedQuery } from "nextjs-routes";
+  import type { Route, RoutedQuery } from "nextjs-routes";
   import type { NextRouter as Router } from "next/dist/client/router";
   export * from "next/dist/client/router";
   export { default } from "next/dist/client/router";
@@ -65,7 +63,7 @@ declare module "next/router" {
 
   type RouteOrQuery = Route | { query: { [key: string]: string | string[] | undefined } };
 
-  export interface NextRouter<P extends Pathname = Pathname>
+  export interface NextRouter<P extends Route["pathname"] = Route["pathname"]>
     extends Omit<Router, "push" | "replace"> {
     pathname: P;
     route: P;
@@ -82,5 +80,5 @@ declare module "next/router" {
     ): Promise<boolean>;
   }
 
-  export function useRouter<P extends Pathname>(): NextRouter<P>;
+  export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
diff --git a/e2e/package-lock.json b/e2e/package-lock.json
index 8920bd5..721362b 100644
--- a/e2e/package-lock.json
+++ b/e2e/package-lock.json
@@ -20,7 +20,7 @@
     },
     "../dist": {
       "name": "nextjs-routes",
-      "version": "0.0.22",
+      "version": "0.1.0",
       "dev": true,
       "license": "MIT",
       "dependencies": {
diff --git a/e2e/typetest.tsx b/e2e/typetest.tsx
index 99fbbbf..82433b0 100644
--- a/e2e/typetest.tsx
+++ b/e2e/typetest.tsx
@@ -203,12 +203,14 @@ route({ pathname: "/foos/[foo]", query: { bar: "baz" } });
 route({ pathname: "/foos/[foo]", query: { foo: ["bar", "baz"] } });
 
 // RoutedQuery
+
 // Path without dynamic segments
 let rq1: RoutedQuery<"/">;
 rq1 = {};
 rq1 = { foo: "baz" };
 rq1 = { foo: ["bar", "baz"] };
 rq1 = { foo: undefined };
+
 // Path with dynamic segments
 let rq2: RoutedQuery<"/foos/[foo]">;
 // @ts-expect-error missing 'foo' in query
diff --git a/src/__snapshots__/core.test.ts.snap b/src/__snapshots__/core.test.ts.snap
index a3a25ec..64f2073 100644
--- a/src/__snapshots__/core.test.ts.snap
+++ b/src/__snapshots__/core.test.ts.snap
@@ -13,15 +13,13 @@ declare module "nextjs-routes" {
   export type Route =
     never;
 
-  export type Pathname = Route["pathname"];
-
   type Query<Params = {}> = Params & { [key: string]: string | string[] | undefined };
 
   type QueryForPathname = {
     [K in Route as K["pathname"]]: Exclude<K["query"], undefined>;
   };
 
-  export type RoutedQuery<P extends Pathname> = QueryForPathname[P];
+  export type RoutedQuery<P extends Route["pathname"]> = QueryForPathname[P];
 
   /**
    * A typesafe utility function for generating paths in your application.
@@ -61,7 +59,7 @@ declare module "next/link" {
 
 // prettier-ignore
 declare module "next/router" {
-  import type { Route, Pathname, RoutedQuery } from "nextjs-routes";
+  import type { Route, RoutedQuery } from "nextjs-routes";
   import type { NextRouter as Router } from "next/dist/client/router";
   export * from "next/dist/client/router";
   export { default } from "next/dist/client/router";
@@ -70,7 +68,7 @@ declare module "next/router" {
 
   type RouteOrQuery = Route | { query: { [key: string]: string | string[] | undefined } };
 
-  export interface NextRouter<P extends Pathname = Pathname>
+  export interface NextRouter<P extends Route["pathname"] = Route["pathname"]>
     extends Omit<Router, "push" | "replace"> {
     pathname: P;
     route: P;
@@ -87,7 +85,7 @@ declare module "next/router" {
     ): Promise<boolean>;
   }
 
-  export function useRouter<P extends Pathname>(): NextRouter<P>;
+  export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
 ",
   ],
@@ -124,15 +122,13 @@ declare module "nextjs-routes" {
     | { pathname: "/settings/foo"; query?: Query | undefined }
     | { pathname: "/settings"; query?: Query | undefined };
 
-  export type Pathname = Route["pathname"];
-
   type Query<Params = {}> = Params & { [key: string]: string | string[] | undefined };
 
   type QueryForPathname = {
     [K in Route as K["pathname"]]: Exclude<K["query"], undefined>;
   };
 
-  export type RoutedQuery<P extends Pathname> = QueryForPathname[P];
+  export type RoutedQuery<P extends Route["pathname"]> = QueryForPathname[P];
 
   /**
    * A typesafe utility function for generating paths in your application.
@@ -172,7 +168,7 @@ declare module "next/link" {
 
 // prettier-ignore
 declare module "next/router" {
-  import type { Route, Pathname, RoutedQuery } from "nextjs-routes";
+  import type { Route, RoutedQuery } from "nextjs-routes";
   import type { NextRouter as Router } from "next/dist/client/router";
   export * from "next/dist/client/router";
   export { default } from "next/dist/client/router";
@@ -181,7 +177,7 @@ declare module "next/router" {
 
   type RouteOrQuery = Route | { query: { [key: string]: string | string[] | undefined } };
 
-  export interface NextRouter<P extends Pathname = Pathname>
+  export interface NextRouter<P extends Route["pathname"] = Route["pathname"]>
     extends Omit<Router, "push" | "replace"> {
     pathname: P;
     route: P;
@@ -198,7 +194,7 @@ declare module "next/router" {
     ): Promise<boolean>;
   }
 
-  export function useRouter<P extends Pathname>(): NextRouter<P>;
+  export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
 ",
   ],