Skip to content

Commit

Permalink
feat: Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bamdadfr committed Mar 30, 2022
0 parents commit 6af1926
Show file tree
Hide file tree
Showing 19 changed files with 2,512 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: '@bamdadsabbagh/eslint-config',
};
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2
updates:

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
38 changes: 38 additions & 0 deletions .github/workflows/semantic-release-yarn--onPush.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: semantic-release-yarn--onPush

on:
push:
branches:
- master

jobs:
semantic-release-yarn--onPush:
runs-on: ubuntu-latest
steps:

- uses: actions/checkout@master

- uses: actions/setup-node@master
with:
node-version: '14'

- run: yarn

- run: |
npm install -g \
semantic-release \
@semantic-release/github \
@semantic-release/git \
@semantic-release/exec \
@semantic-release/changelog \
@semantic-release/npm \
semantic-release-chrome \
semantic-release-firefox-add-on \
aggregate-error
- run: semantic-release
env:
GH_TOKEN: ${{ secrets.PAT }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
FIREFOX_API_KEY: ${{ secrets.FIREFOX_API_KEY }}
FIREFOX_SECRET_KEY: ${{ secrets.FIREFOX_SECRET_KEY }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
yarn-error.log
.idea/sonarlint/
5 changes: 5 additions & 0 deletions .idea/.gitignore

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

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

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

6 changes: 6 additions & 0 deletions .idea/jsLinters/eslint.xml

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

6 changes: 6 additions & 0 deletions .idea/misc.xml

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

8 changes: 8 additions & 0 deletions .idea/modules.xml

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

11 changes: 11 additions & 0 deletions .idea/next-replace-url.iml

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

6 changes: 6 additions & 0 deletions .idea/vcs.xml

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

49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Replace URL parameters in Next.js without re-rendering.

## 🚀 Getting Started

```bash
npm install next-replace-url
yarn add next-replace-url
```

```javascript
import {useNextReplaceUrl, nextReplaceUrl} from 'next-replace-url';

// in your functional component
useNextReplaceUrl('parameter', value);

// from anywhere
nextReplaceUrl('parameter', value);
```

## 📖️ Description

The module replaces the `window.history.state` object therefore bypassing Next.js routing context, avoiding re-renders.

Some suggest shallow routing which unfortunately does not prevent re-renders.

### Under the hood example

```javascript
// User navigates to https://example.com/audio/1

// Current state
window.history.state = {
"url": "/audio/[volume]?volume=1", // Next.js URL
"as": "/audio/1" // What user sees
}

// Running the following command will replace the URL parameter "volume" with "2"
nextReplaceUrl('volume', '2')

// Resulting state
window.history.state = {
"url": "/audio/[volume]?volume=2",
"as": "/audio/2"
}
```

## 📖️ Related discussions

- https://github.com/vercel/next.js/discussions/18072
49 changes: 49 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "next-replace-url",
"version": "0.0.0",
"description": "Replace URL parameters in Next.js without re-rendering",
"author": {
"name": "Bamdad Sabbagh",
"email": "[email protected]",
"url": "https://bamdad.fr"
},
"repository": {
"type": "git",
"url": "https://github.com/bamdadsabbagh/next-replace-url.git"
},
"license": "MIT",
"keywords": [
"next",
"next.js",
"replace",
"url",
"route",
"parameter",
"parameters",
"param",
"params",
"render",
"re-render",
"rendering",
"re-rendering",
"query",
"string",
"querystring",
"query-string",
"history"
],
"type": "module",
"main": "src/main.js",
"types": "src/main.d.ts",
"files": [
"src"
],
"scripts": {
"package:reinstall": "rimraf node_modules && yarn",
"package:sort": "npx sort-package-json"
},
"devDependencies": {
"@bamdadsabbagh/eslint-config": "^2.0.21",
"react": "^18.0.0"
}
}
20 changes: 20 additions & 0 deletions release.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = {
plugins: [
'@semantic-release/commit-analyzer',
'@semantic-release/release-notes-generator',
['@semantic-release/changelog', {
changelogFile: 'CHANGELOG.md',
}],
['@semantic-release/npm', {
npmPublish: true,
}],
'@semantic-release/github',
['@semantic-release/git', {
assets: [
'CHANGELOG.md',
'package.json',
],
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
}],
],
};
17 changes: 17 additions & 0 deletions src/main.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
declare module 'next-replace-url' {
/**
* Replace URL parameters in Next.js without re-rendering
*
* @param {string} parameter - Route parameter
* @param {string} value - New parameter value
*/
export function nextReplaceUrl(parameter: string, value: string): void;

/**
* React Hook for replacing URL parameter in Next.js without re-rendering
*
* @param {string} parameter - Route parameter
* @param {string} value - New parameter value
*/
export function useNextReplaceUrl(parameter: string, value: string): void;
}
2 changes: 2 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export {nextReplaceUrl} from './next-replace-url.js';
export {useNextReplaceUrl} from './use-next-replace-url.js';
43 changes: 43 additions & 0 deletions src/next-replace-url.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Replace URL parameters in Next.js without re-rendering
*
* @param {string} parameter - Route parameter
* @param {string} value - New parameter value
*/
export function nextReplaceUrl(parameter, value) {
if (typeof parameter !== 'string') {
throw new Error('parameter is not a string');
}

if (typeof value !== 'string') {
throw new Error('value is not a string');
}

// Current state
const {as, url} = window.history.state;
const args = as.split('/');

// Find the parameter index
const parameterId = new RegExp(`^(.*)(\\[${parameter}\\])(.*)$`)
.exec(url)
.slice(1)[0]
.split('/')
.length - 1;

// Replace value
args[parameterId] = value;

// Build the new state
const newAs = args.join('/');
const newUrl = url.replace(
new RegExp(`${parameter}=.*?(?=&|$)`),
`${parameter}=${value}`,
);

// Apply the new state
window.history.replaceState(
{...window.history.state, as: newAs, url: newUrl},
'',
newAs,
);
}
14 changes: 14 additions & 0 deletions src/use-next-replace-url.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {useEffect} from 'react';
import {nextReplaceUrl} from './next-replace-url';

/**
* React Hook for replacing URL parameter in Next.js without re-rendering
*
* @param {string} parameter - Route parameter
* @param {string} value - New parameter value
*/
export function useNextReplaceUrl(parameter, value) {
useEffect(() => {
nextReplaceUrl(parameter, value);
}, [parameter, value]);
}
Loading

0 comments on commit 6af1926

Please sign in to comment.