Skip to content

Commit

Permalink
Initial Release
Browse files Browse the repository at this point in the history
  • Loading branch information
shgysk8zer0 committed Oct 14, 2024
1 parent e6f71d1 commit c304d17
Show file tree
Hide file tree
Showing 18 changed files with 1,770 additions and 886 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules/
.github/
test/
.editorconfig
.eslintignore
.eslintrc.json
Expand Down
72 changes: 1 addition & 71 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,76 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed
- Update node version via `.npmrc`
- Update Node CI workflow
- Install & use `@shgysk8zer0/eslint-config`
- Add support for `node --test`, including ignoring tests for publishing
- Update ESLint & super-linter
- Switch to more basic Rollup config
- Update `exports` and `main` accordingly

### Fixed
- Fix missed renaming in README

## Removed
- Remove old ESLint config files

## [v1.1.1] - 2023-09-24

### Added
- Add `unpkg` to `package.json`
- Add badges in README

### Changed
- Update `exports` to `package.json` to handle wider variety

### Fixed
- Fix typo in `fix:js` script

### [v1.1.0] - 2023-07-03

### Changed
- Update to node 20
- Update npm publishing GH Action

## [v1.0.5] - 2023-07-02

### Added
- Add `funding`

### Changed
- Updated GitHub Actions workflows
- Update versioning & lock-file scripts
- Update `.npmignore` & `.gitignore`

## [v1.0.4] - 2023-06-08

### Added
- Install `@shgysk8zer0/npm-utils`
- Add `exports` to package config

### Removed
- Uninstall `rollup`, `eslint`

### Changed
- Use `getConfig()` from `@shgysk8zer0/js-utils/rollup` for rollup config

## [v1.0.3] - 2023-06-01

### Fixed
- Revert to old Release Action, now with permissions & link to changelog

## [v1.0.2] - 2023-06-01

### Fixed
- Fix `changelog-entry` to match `[$version]` instead of `$version`

## [v1.0.1] - 2023-05-31

### Fixed
- Update GitHub Release workflow to use [Auto Release](https://github.com/marketplace/actions/auto-release)

## [v1.0.0] - 2023-05-31
## [v1.0.0] - 2024-10-13

Initial Release
155 changes: 141 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# npm-template
# `@aegisjsproject/router`

A template repo for npm packages
A simple but powerful router module

[![CodeQL](https://github.com/shgysk8zer0/npm-template/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/shgysk8zer0/npm-template/actions/workflows/codeql-analysis.yml)
![Node CI](https://github.com/shgysk8zer0/npm-template/workflows/Node%20CI/badge.svg)
![Lint Code Base](https://github.com/shgysk8zer0/npm-template/workflows/Lint%20Code%20Base/badge.svg)
[![CodeQL](https://github.com/AegisJSProject/router/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/AegisJSProject/router/actions/workflows/codeql-analysis.yml)
![Node CI](https://github.com/AegisJSProject/router/workflows/Node%20CI/badge.svg)
![Lint Code Base](https://github.com/AegisJSProject/router/workflows/Lint%20Code%20Base/badge.svg)

[![GitHub license](https://img.shields.io/github/license/shgysk8zer0/npm-template.svg)](https://github.com/shgysk8zer0/npm-template/blob/master/LICENSE)
[![GitHub last commit](https://img.shields.io/github/last-commit/shgysk8zer0/npm-template.svg)](https://github.com/shgysk8zer0/npm-template/commits/master)
[![GitHub release](https://img.shields.io/github/release/shgysk8zer0/npm-template?logo=github)](https://github.com/shgysk8zer0/npm-template/releases)
[![GitHub license](https://img.shields.io/github/license/AegisJSProject/router.svg)](https://github.com/AegisJSProject/router/blob/master/LICENSE)
[![GitHub last commit](https://img.shields.io/github/last-commit/AegisJSProject/router.svg)](https://github.com/AegisJSProject/router/commits/master)
[![GitHub release](https://img.shields.io/github/release/AegisJSProject/router?logo=github)](https://github.com/AegisJSProject/router/releases)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/shgysk8zer0?logo=github)](https://github.com/sponsors/shgysk8zer0)

[![npm](https://img.shields.io/npm/v/@shgysk8zer0/npm-template)](https://www.npmjs.com/package/@shgysk8zer0/npm-template)
![node-current](https://img.shields.io/node/v/@shgysk8zer0/npm-template)
![npm bundle size gzipped](https://img.shields.io/bundlephobia/minzip/@shgysk8zer0/npm-template)
[![npm](https://img.shields.io/npm/dw/@shgysk8zer0/npm-template?logo=npm)](https://www.npmjs.com/package/@shgysk8zer0/npm-template)
[![npm](https://img.shields.io/npm/v/@aegisjsproject/router)](https://www.npmjs.com/package/@aegisjsproject/router)
![node-current](https://img.shields.io/node/v/@aegisjsproject/router)
![npm bundle size gzipped](https://img.shields.io/bundlephobia/minzip/@aegisjsproject/router)
[![npm](https://img.shields.io/npm/dw/@aegisjsproject/router?logo=npm)](https://www.npmjs.com/package/@aegisjsproject/router)

[![GitHub followers](https://img.shields.io/github/followers/shgysk8zer0.svg?style=social)](https://github.com/shgysk8zer0)
![GitHub forks](https://img.shields.io/github/forks/shgysk8zer0/npm-template.svg?style=social)
![GitHub stars](https://img.shields.io/github/stars/shgysk8zer0/npm-template.svg?style=social)
![GitHub forks](https://img.shields.io/github/forks/AegisJSProject/router.svg?style=social)
![GitHub stars](https://img.shields.io/github/stars/AegisJSProject/router.svg?style=social)
[![Twitter Follow](https://img.shields.io/twitter/follow/shgysk8zer0.svg?style=social)](https://twitter.com/shgysk8zer0)

[![Donate using Liberapay](https://img.shields.io/liberapay/receives/shgysk8zer0.svg?logo=liberapay)](https://liberapay.com/shgysk8zer0/donate "Donate using Liberapay")
Expand All @@ -27,3 +27,130 @@ A template repo for npm packages
- [Code of Conduct](./.github/CODE_OF_CONDUCT.md)
- [Contributing](./.github/CONTRIBUTING.md)
<!-- - [Security Policy](./.github/SECURITY.md) -->

> [!CRITICAL]
> This package requires [`URLPattern`](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern) to be polyfilled *before*
> any paths are registered. A common polyfill recommended by MDN can be [found here](https://github.com/kenchris/urlpattern-polyfill).
## Installation
```bash
npm install @aegisjsproject/router
```

## CDN and importmap
You do not even need to `npm install` this or use any build process. You may either import it directly from a CDN
or use an [importmap](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap).

```html
<script type="importmap">
{
"imports": {
"@aegisjsproject/router": "https://unpkg.com/@aegisjsproject/router[@version]/router.js",
"@aegisjsproject/state": "https://unpkg.com/@aegisjsproject/state[@version]/state.js"
}
}
</script>
```

## Advantages of `@aegisjsproject/router`

* **Lightweight and Efficient:** The library is designed to be small and performant, with a focus on efficient URL matching and module loading.
* **Dynamic Loading:** Modules are loaded on-demand, improving initial page load performance and reducing resource usage.
* **Flexible Exports:** Supports a variety of module exports, including custom elements, functions, and HTML structures, making it adaptable to different UI architectures.
* **Component Injection:** Automatically injects relevant URL information and state into registered components, simplifying component development and data management.
* **History Integration:** Seamlessly manages browser history, allowing users to navigate back and forward without reloading the entire page.
* **Error Handling:** Provides built-in error handling mechanisms to gracefully handle unexpected situations during module loading or navigation.
* **Customizable:** Offers flexibility for customization, allowing you to tailor the router's behavior to your specific project requirements.
* **Easy to Use:** The library provides a simple and intuitive API, making it easy to learn and integrate into your projects.

## Fundamentals

At its core, this package matches matches URLs matching a `URLPattern` to modules to be dynamically
imported. This yields a powerful but minimal package size, dynamic loading of "View"s as-needed,
high reusability of code, and potentially nearly instant navigations, especially when used in
conjunction with service workers and caches. Just create a script that has a `default` export
that is a `Document`, `DocumentFragment`, `HTMLElement` and especially a custom element or
web component, and map the `URLPattern`s to their respective modules.

## Example

```js
import { init, navigate, back, forward, reload } from '@aegisjsproject/router';

init({
'/product/:productId': '@scope/views/product.js',
'/test/': '@scope/views/home.js',
'/search?q=:query': '@scope/views/search.js',
'/img': '/views/img.js',
}, {
preload: true, // Preload all registered modules
notFound: './views/404.js', // Set custom 404 module
rootNode: '#root', // Declares element for base of content updates
intceptRoot: document.body, // Use `MutationObserver` to observer `<a>` elements and intercept naviations
signal: controller.signal, // An `AbortSignal`, should you want to disable routing funcitonality
});

document.querySelectorAll('[data-link]').forEach(el => {
el.addEventListener('click', ({ currentTarget }) => {
const { link, ...state } = currentTarget.dataset;
navigate(link, state);
});
});

document.querySelectorAll('[data-nav').forEach(el => {
el.addEventListener('click', ({ currentTarget }) => {
switch (currentTarget.dataset.nav) {
case 'back':
back();
break;

case 'forward':
forward();
break;

case 'reload':
reload();

default:
throw new TypeError(`Invalid nav button type: ${currentTarget.dataset.nav}.`);
}
});
});
```

## Registering Paths
At the core, this router module just uses `URLPattern`s in a map, mapped to a source for a module. When a URL
is navigated to, it finds the pattern that the URL matches, dynamically imports that module, and passes the
current state and URL and the results of `urlPattern.exec(url)` to the function or constructor.

You may register paths via either `registerPath()` or through an object given to the `init()` function. `registerPath()`
allows for the use of `new URLPattern()` to be used, but as `init()` requires an object, its keys must be strings
to be converted into `URLPattern` through `new URLPattern(key, moduleSrc)`.

## Handling Navigation
If you call the `init()` function, the `popstate` listener will be added automatically and the module for the
current page will be loaded. Should you want more manual loading, you may also call `addListener()` on your own.

There is also a `MutationObserver` that adds `click` event handlers to intercept clicks on same-origin `<a>`s.
This observer watches for `<a>`s in the children of what it is set to observe and calls `event.preventDefault()`
to avoid the default navigation, then calls `navigate(a.href)`.

> [!NOTE]
> While the `MutationObserver` automatically adds the necessary click handlers on all `<a>` elements under its
> root, it cannot reach into Shadow DOM. For any web component with shadow, you should call `observeLinksOn(shadow)`
> in either the constructor or `connectedCallback`.
## 404 Pages
You can register a module for 404 pages using either `set404()` or by passing it via `{ notFound }` in `init()`.
This component or function will be given the current state and URL and can be dynamically generated.

## Preloading
You can preload modules for views by using `preloadModule()` or by passing `{ preload: true }` in `init()`.
Preloading modules will make navigation effectively instant and potentially without network traffic, however
it will increase initial load times (though you can set low priority to let the browser decide when to preload).

## State Managment
This currently uses [`@aegisjsproject/state`](https://npmjs.com/package/@aegisjsproject/state) for state
mangement. It is a lightweight wrapper around `history.state` that uses `BroadcastChannel` to sync state
changes between tabs/windows. It should be noted that this is `global` state and not specific to some component,
so please avoid generic names and be aware of the global nature.
1 change: 0 additions & 1 deletion consts.js

This file was deleted.

2 changes: 0 additions & 2 deletions index.js

This file was deleted.

8 changes: 0 additions & 8 deletions index.test.js

This file was deleted.

Loading

0 comments on commit c304d17

Please sign in to comment.