Skip to content

Commit

Permalink
add dir config option (#93)
Browse files Browse the repository at this point in the history
  • Loading branch information
tatethurston authored Nov 8, 2022
1 parent 8133690 commit d09ebd1
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 34 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@

## 0.1.7

- Support [Next 13 app (beta)](https://nextjs.org/docs/advanced-features/custom-app)
- Support [Next 13 app (beta) directory](https://nextjs.org/docs/advanced-features/custom-app)

- Add `dir` option to support non standard NextJS project structures such as [Nx](https://nx.dev/packages/next):

```js
// next.config.js
const withRoutes = require("nextjs-routes/config")({ dir: __dirname });
```

Thanks [@alexgorbatchev](https://github.com/alexgorbatchev) for the contribution!

## 0.1.6

Expand Down
2 changes: 1 addition & 1 deletion public.package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nextjs-routes",
"version": "0.1.6",
"version": "0.1.7",
"description": "Type safe routing for Next.js",
"license": "MIT",
"author": "Tate <[email protected]>",
Expand Down
17 changes: 5 additions & 12 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
import type { NextConfig } from "next";
import { join } from "path";
import type { Configuration, WebpackPluginInstance } from "webpack";
import { getAppDirectory, getPagesDirectory } from "./utils.js";
import { watch } from "chokidar";
import { logger, writeNextjsRoutes } from "./core.js";
import { logger, NextJSRoutesOptions, writeNextjsRoutes } from "./core.js";

function debounce<Fn extends (...args: unknown[]) => unknown>(
fn: Fn,
Expand Down Expand Up @@ -40,9 +39,9 @@ class NextJSRoutesPlugin implements WebpackPluginInstance {
apply() {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const cwd = this.options?.cwd ?? process.cwd();
const watchDirs = [getPagesDirectory(cwd), getAppDirectory(cwd)]
.filter((x) => x != undefined)
.map((dir) => join(cwd, dir as string));
const watchDirs = [getPagesDirectory(cwd), getAppDirectory(cwd)].filter(
(x) => x != undefined
) as string[];

if (watchDirs.length > 0) {
const options = {
Expand Down Expand Up @@ -70,13 +69,7 @@ class NextJSRoutesPlugin implements WebpackPluginInstance {
}
}

interface WithRoutesOptions {
/**
* The file path indicating the output directory where the generated route types
* should be written to (e.g.: "types").
*/
outDir?: string;
}
type WithRoutesOptions = Pick<NextJSRoutesOptions, "outDir" | "dir">;

export default function withRoutes(
options?: WithRoutesOptions
Expand Down
1 change: 1 addition & 0 deletions src/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jest.mock("fs", () => ({
}));
const writeFileSyncMock = writeFileSync as jest.Mock;
const existsSyncMock = existsSync as jest.Mock;
jest.spyOn(process, "cwd").mockReturnValue("");

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
jest.mock("./utils.js", () => ({
Expand Down
35 changes: 24 additions & 11 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,23 +248,34 @@ export const logger: Pick<Console, "error"> = {
error: (str: string) => console.error("[nextjs-routes] " + str),
};

interface NextJSRoutesOptions {
export interface NextJSRoutesOptions {
/**
* The file path indicating the output directory where the generated route types
* should be written to (e.g.: "types").
*/
outDir?: string;
outDir?: string | undefined;
/**
* Location of the Next.js project. Defaults to the current working directory.
*
* This is only necessary when working with a non standard NextJS project setup, such as Nx.
*
* Example:
*
* // next.config.js
* const withRoutes = require("nextjs-routes/config")({ dir: __dirname });
*/
dir?: string | undefined;
/**
* NextJS pageExtensions.
* https://nextjs.org/docs/api-reference/next.config.js/custom-page-extensions
*/
pageExtensions?: string[];
pageExtensions?: string[] | undefined;
/**
* Internationalization configuration
*
* @see [Internationalization docs](https://nextjs.org/docs/advanced-features/i18n-routing)
*/
i18n?: I18NConfig | null;
i18n?: I18NConfig | null | undefined;
}

interface Opts {
Expand Down Expand Up @@ -328,6 +339,7 @@ export function getPageRoutes(files: string[], opts: Opts): string[] {

export function writeNextjsRoutes(options: NextJSRoutesOptions): void {
const defaultOptions = {
dir: process.cwd(),
outDir: "",
pageExtensions: ["tsx", "ts", "jsx", "js"],
};
Expand All @@ -336,17 +348,17 @@ export function writeNextjsRoutes(options: NextJSRoutesOptions): void {
...options,
};
const files = [];
const pagesDirectory = getPagesDirectory();
const pagesDirectory = getPagesDirectory(opts.dir);
if (pagesDirectory) {
const routes = getPageRoutes(findFiles(join(".", pagesDirectory)), {
const routes = getPageRoutes(findFiles(pagesDirectory), {
pageExtensions: opts.pageExtensions,
directory: pagesDirectory,
});
files.push(...routes);
}
const appDirectory = getAppDirectory();
const appDirectory = getAppDirectory(opts.dir);
if (appDirectory) {
const routes = getAppRoutes(findFiles(join(".", appDirectory)), {
const routes = getAppRoutes(findFiles(appDirectory), {
pageExtensions: opts.pageExtensions,
directory: appDirectory,
});
Expand All @@ -365,9 +377,10 @@ export function cli(): void {
console.warn(
`[nextjs-routes]: Direct invocation of nextjs-routes has been deprecated in favor of automatic regeneration via 'withRoutes': https://github.com/tatethurston/nextjs-routes#installation--usage-. See https://github.com/tatethurston/nextjs-routes/issues/63 for the motivation behind this change or to voice any concerns.`
);
const dirs = [getPagesDirectory(), getAppDirectory()].filter(
(x) => x != undefined
);
const dirs = [
getPagesDirectory(process.cwd()),
getAppDirectory(process.cwd()),
].filter((x) => x != undefined);
if (dirs.length === 0) {
logger.error(`Could not find a Next.js pages directory. Expected to find either 'pages' (1), 'src/pages' (2), or 'app' (3) in your project root.
Expand Down
24 changes: 15 additions & 9 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,26 @@ import { existsSync, readdirSync, statSync } from "fs";
import { join } from "path";

// istanbul ignore next: io mocking not worthwhile
export function getPagesDirectory(cwd = process.cwd()): string | undefined {
const dirs = ["pages", join("src", "pages")];
for (const dir of dirs) {
if (existsSync(join(cwd, dir))) {
return dir;
function findDir(dir: string, cwd: string): string | undefined {
const dirs = [dir, join("src", dir)];
for (const d of dirs) {
const path = join(cwd, d);
if (existsSync(path)) {
return path;
}
}
}

export function getAppDirectory(cwd = process.cwd()): string | undefined {
if (existsSync(join(cwd, "app"))) {
return "app";
}
// istanbul ignore next: io mocking not worthwhile
export function getPagesDirectory(cwd: string): string | undefined {
return findDir("pages", cwd);
}

// istanbul ignore next: io mocking not worthwhile
export function getAppDirectory(cwd: string): string | undefined {
return findDir("app", cwd);
}

// istanbul ignore next: io mocking not worthwhile
export function findFiles(entry: string): string[] {
return readdirSync(entry).flatMap((file) => {
Expand Down

0 comments on commit d09ebd1

Please sign in to comment.