npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

svelte-selfheal

v0.1.0

Published

Generate SEO friendly URLs with IDs and redirect to the canonical URL even if the URL is not correct.

Downloads

5

Readme

svelte-selfheal

A simple Svelte package inspired by this video from Aaron Francis and heavily based on a similar package for Laravel.

It allows you to redirect users to a canonical and SEO-friendly URL for a page, even if the slug is altered at any point or doesn't exist at all.

svelte-selfheal-gif

Example

Canonical URL: https://my-app.com/blog/my-fancy-title-5312

The following URLs would still redirect to the correct page

  • /blog/my-fancy-title-5312 (original)
  • /blog/my-fancy-but-spelled-wrong-title-5312
  • /blog/5312
  • /blog/-5312
  • /blog/THIS should NOT be r3alURL -5312

Installation

Install this package using any of the popular package managers.

npm i svelte-selfheal
pnpm add svelte-selfheal
yarn add svelte-selfheal

Usage

Once installed, export a healer:

import { selfheal } from 'svelte-selfheal';

export const healer = selfheal();

Now you can use the self-healing functions anywhere across your app.

Example +page.server.ts

Inside your load function you want to

  1. Import the healer and destructure the most important functions
const { identifier, shouldRedirect, reroute, create } = healer;
  1. Separate the identifier from the slug using the handler you defined on creation
const { identifier: id } = identifier.separate(params.id);
  1. Query the database using the ID and see if something is found
const article = db.articles.find((article) => String(article.id) === id);
if (!article) throw error(404, `Article ${identifier} not found`);
  1. Compare the DB slug to your current URL (and redirect if they're differerent)
const slug = create(article.title, article.id);

// You can either use the built-in rerouter
reroute(slug, params.id);

// Or manually check and handle the error yourself
if (shouldRedirect(slug, params.id)) throw redirect(301, slug);

Now you are guaranteed to either be on the 404 page because no content with that ID is found or you have been redirected to use the canonical slug for this entity.

Complete example

import { error, redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types.js';

import { healer } from '$lib/selfheal.js';
import { db } from '$lib/db.js';

export const load: PageServerLoad = async ({ params }) => {
	const { identifier, shouldRedirect, reroute, create } = healer;

	const { identifier: id } = identifier.separate(params.id);

	const article = db.articles.find((article) => String(article.id) === id);
	if (!article) throw error(404, `Article ${identifier} not found`);

	const slug = create(article.title, article.id);

	reroute(slug, params.id); // or throw manually
	if (shouldRedirect(slug, params.id)) throw redirect(301, slug);

	return { article, slug: params.id };
};

Don't worry if your "slug" isn't URL friendly; the package will take care of formatting it for you whenever you call create(). In fact, it doesn't even have to be unique because the defined unique identifier for your model will also be included at the end.

Limitations

By default, the package requires that your unique identifier (such as the id or uuid column) not have any - characters. You can implement your own IdentifierHandler as detailed in the next section.

As of now, all URL parameters are removed during redirect but this will be fixed in a future release.

Configuration

During initialization you can configure the healer by passing in functions to handle its operations, or use its sensible defaults.

By default, the package uses

| Function | Method | Description | | ----------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- | | sanitize() | Kebab | Trims, replaces spaces with hyphens, removes multiple hyphens, removes hyphens at the start and end of the string and converts to lowercase | | shouldRedirect() && reroute() | Name | Compares the canonical and current routes by their names using a simple === | | identifier() | Hyphen | Appends the ID to the slug using a hyphen - |

You can however change any of these individually, within the limitations mentioned above.

export const healer = selfheal({
	sanitize: (slug) => {
		/* ... */
	},
	identifier: {
		join(slug, identifier) {
			/* ... */
		},
		separate(slug) {
			/* ... */
		}
	},
	shouldRedirect: (slug, identifier) => {
		/* ... */
	},
	reroute: (slug, identifier) => {
		/* ... */
	}
});

Using a custom IdentifierHandler

If you need to customize how a slug is joined to a model identifier (which by default is just a hyphen), you can create your own IdentifierHandler that returns a join() and a separate() function and supply itduring the initialization of your healer.

Here is an example using a _ instead

export const healer = selfheal({
	identifier: {
		join(slug, identifier) {
			return `${slug}_${identifier}`;
		},
		separate(slug) {
			const [identifier, ...rest] = slug.split('_').reverse();
			return {
				identifier,
				slug: rest.reverse().join('_')
			};
		}
	}
});

This would result in URLs like /my-fancy-title_123, depending of course on how your sanitizer works.

License

Licensed under the MIT license.