Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Started working on new plugin remake #23

Merged
merged 9 commits into from
Aug 12, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ jobs:
- uses: actions/checkout@v3
- uses: denoland/setup-deno@v1
with:
deno-version: v1.26.X
deno-version: v1.34.X

- run: deno task test
- run: deno task test
90 changes: 41 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Fresh SEO 🍋   [![Badge License]][License]

*Quickly creating sitemaps for your **Deno [Fresh project]**.*
Expand All @@ -7,26 +6,27 @@

## Getting Started

*Run the setup at the root of your project.*

```shell
deno run --allow-read --allow-write https://deno.land/x/fresh_seo/init.ts

```
*Import the plugin `freshSEOPlugin` in your Fresh app*

<br>
```ts
// ./main.ts
import { start } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";

The following file should have been created:
import { freshSEOPlugin } from "https://deno.land/x/fresh_seo/mod.ts";

`routes/sitemap.xml.ts`
await start(manifest, {
plugins: [
freshSEOPlugin(manifest)
],
});

<br>
```

A basic sitemap should now be available at:

[`http://localhost:8000/sitemap.xml`][Localhost]

<br>
<br>

## How does it work?
Expand All @@ -42,50 +42,42 @@ A basic sitemap should now be available at:
*You will still have to map dynamic routes yourself!*

```ts
// ./routes/sitemap.xml.ts
import { SitemapContext } from 'https://deno.land/x/fresh_seo/mod.ts';
import { Handlers } from '$fresh/server.ts';
import manifest from '../fresh.gen.ts';

export const handler : Handlers = {
GET(request,context){
const sitemap = new SitemapContext(
'http://example.com', // put your domain here
manifest
);

// you can add additional page here
sitemap.add('/blog/hello-world');

return sitemap.render();
}
}
// ./main.ts
import { start } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";

import { freshSEOPlugin } from "https://deno.land/x/fresh_seo/mod.ts";

await start(manifest, {
plugins: [
freshSEOPlugin(manifest, {
include: ["/blog/intro"]
})
],
});
```

*You can also remove unwanted routes*

```ts
// ./routes/sitemap.xml.ts
import { SitemapContext } from 'https://deno.land/x/fresh_seo/mod.ts';
import { Handlers } from '$fresh/server.ts';
import manifest from '../fresh.gen.ts';

export const handler : Handlers = {
GET(request,context){
const sitemap = new SitemapContext(
'http://example.com',
manifest
);

// You can remove unwanted routes here
sitemap.remove('/admin');

return sitemap.render();
}
}
// ./main.ts
import { start } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";

import { freshSEOPlugin } from "https://deno.land/x/fresh_seo/mod.ts";

await start(manifest, {
plugins: [
freshSEOPlugin(manifest, {
exclude: [
"/blog/intro",
"/api/*"
]
})
],
});
```

<br>
<br>

## Testing
Expand Down
93 changes: 93 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions src/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ export {
extname,
join,
resolve,
} from "https://deno.land/std@0.153.0/path/mod.ts";
} from "https://deno.land/std@0.197.0/path/mod.ts";
export {
assert,
assertStringIncludes,
assertThrows,
} from "https://deno.land/[email protected]/testing/asserts.ts";
export { FakeTime } from "https://deno.land/[email protected]/testing/time.ts";
export { ensureFile } from "https://deno.land/[email protected]/fs/mod.ts";
} from "https://deno.land/[email protected]/testing/asserts.ts";
export { FakeTime } from "https://deno.land/[email protected]/testing/time.ts";
export { ensureFile } from "https://deno.land/[email protected]/fs/mod.ts";
export { filterFiles } from "https://deno.land/x/[email protected]/mod.ts";
1 change: 1 addition & 0 deletions src/mod.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { SitemapContext } from "./sitemap.ts";
export { freshSEOPlugin } from "./plugin.ts";
36 changes: 36 additions & 0 deletions src/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { SitemapContext } from "./sitemap.ts";
import { Manifest, Plugin } from "./types.ts";

interface PluginOptions {
include: string[];
exclude: string[];
}
notangelmario marked this conversation as resolved.
Show resolved Hide resolved

export const freshSEOPlugin = (manifest: Manifest, opts: PluginOptions): Plugin => {
notangelmario marked this conversation as resolved.
Show resolved Hide resolved
return {
name: "fresh-seo",
routes: [
{
path: "/sitemap.xml",
handler: (req) => {
const sitemap = new SitemapContext(req.url, manifest);

if (opts.include) {
opts.include.forEach((path) => {
sitemap.add(path);
})
}

if (opts.exclude) {
opts.exclude.forEach((path) => {
sitemap.remove(path);
})
}


return sitemap.render();
}
}
]
}
}
15 changes: 13 additions & 2 deletions src/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/// <reference lib="deno.ns" />
/// <reference lib="deno.unstable" />

import { filterFiles } from "https://deno.land/x/[email protected]/mod.ts";
import { basename, extname } from "./deps.ts";
import { type Manifest, type Route, type RouteProps } from "./types.ts";

Expand Down Expand Up @@ -54,22 +55,28 @@ export class SitemapContext {
});
return this;
}

const { changefreq, priority, lastmod } = props;

this.#routes.push({
pathName: route.replace(/(^\/?)|(\/?$)/, "/"),
changefreq,
priority,
lastmod,
});

return this;
}

set(route: string, props?: RouteProps) {
if (typeof props === "undefined") return this;

const i = this.#routes.findIndex(
(v) => v.pathName === route.replace(/(^\/?)|(\/?$)/, "/"),
);

if (i === -1) return this;

const { changefreq, priority, lastmod } = props;
const currentRoute = this.#routes[i];
this.#routes[i] = {
Expand All @@ -82,7 +89,11 @@ export class SitemapContext {
}

remove(route: string) {
this.#routes = this.#routes.filter((r) => r.pathName !== route);
// glob_filter works best with absolute paths
// so we need to add the url to the route
const matching = filterFiles(this.#routes.map((r) => this.#url + r.pathName), { match: this.#url + route, ignore: this.#globalIgnore })
this.#routes = this.#routes.filter((r) => !matching.map((m) => m.replace(this.#url, "")).includes(r.pathName))

return this;
}

Expand Down Expand Up @@ -130,4 +141,4 @@ function formatYearMonthDate(date: Date) {
return `${date.getFullYear()}-${("00" + (date.getMonth() + 1)).slice(-2)}-${
("00" + date.getDate()).slice(-2)
}`;
}
}
8 changes: 8 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
// deno-lint-ignore-file no-explicit-any

export interface Plugin {
name: string;
routes: {
path: string;
handler: (req: Request) => Response;
}[];
}

export interface Manifest {
routes: Record<string, any>;
islands: Record<string, any>;
Expand Down
26 changes: 26 additions & 0 deletions tests/sitemap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,32 @@ Deno.test("Remove certain routes", () => {
assertStringIncludes(result, "</urlset>");
});

Deno.test("Remove all routes from /api", () => {
const manifest: Manifest = {
routes: {
"./routes/blog/[slug].tsx": { default: () => null },
"./routes/api/[...rest].tsx": { default: () => null },
},
islands: {},
baseUrl: url,
};
const sitemap = new SitemapContext(url, manifest);

const result = sitemap.remove("/api/*").generate();

assertStringIncludes(result, '<?xml version="1.0" encoding="UTF-8"?>');
assertStringIncludes(
result,
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">',
);

assertThrows(() =>
assertStringIncludes(result, "<loc>https://deno.land/api</loc>")
);

assertStringIncludes(result, "</urlset>");
});

Deno.test("Set current route", async (t) => {
const manifest: Manifest = {
routes: {
Expand Down