Skip to content

Commit

Permalink
Merge pull request #89 from jorgegorka/site-prefix
Browse files Browse the repository at this point in the history
Site prefix
  • Loading branch information
jorgegorka authored Nov 4, 2020
2 parents 2dd54b3 + 52a822b commit 9d0bc5c
Show file tree
Hide file tree
Showing 9 changed files with 1,920 additions and 27 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Svelte Router changelog

## 5.8.0

Added prefix param to constrain routes.

## 5.7.4

Fix bug with anchor tags.
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ It's designed for Single Page Applications (SPA). If you need Server Side Render
- Named params.
- Localisation.
- Guards to protect urls. Public and private urls.
- Route prefix.
- Track pageviews in Google Analytics (optional).
- Use standard `<a href="/about-us">About</a>` elements to navigate between pages (or use [`<Navigate />`](#navigate) for bonus features).

Expand Down Expand Up @@ -563,6 +564,21 @@ If you define a 404 route it will be rendered instead of the default behaviour.
}
```

## Route prefix

You can easily constrain all your routes to a specific path like _/blog_

```javascript
<Router { routes } options={ {prefix: 'blog'} } />
```

With this option you don't have to define all your routes starting with _blog_ they will be prefixed automatically.

Using prefix has two advantages:

- You don't need to create a top level route in your routes file and then add every route as a nested route.
- Routes that don't start with the prefix will not be returned as 404 since they are out of the scope of the prefixed routes so you can navigate to them.

## Google Analytics

If you want to track route changes as pageviews in Google Analytics just add
Expand Down
40 changes: 20 additions & 20 deletions package-lock.json

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

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "svelte-router-spa",
"version": "5.7.4",
"version": "5.8.0",
"description": "A full featured router component for Svelte and your Single Page Applications.",
"main": "src/index.js",
"svelte": "src/index.js",
Expand All @@ -15,16 +15,16 @@
"license": "MIT",
"devDependencies": {
"chai": "^4.2.0",
"eslint": "^7.11.0",
"mocha": "^8.2.0",
"eslint": "^7.12.1",
"mocha": "^8.2.1",
"mocha-jsdom": "^2.0.0",
"svelte": "^3.29.4"
},
"dependencies": {
"url-params-parser": "^1.0.3"
},
"peerDependencies": {
"svelte": "^3.6.7"
"svelte": "^3.29.0"
},
"repository": {
"type": "git",
Expand Down
15 changes: 14 additions & 1 deletion src/router/finder.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const NotFoundPage = '/404.html'

function RouterFinder({ routes, currentUrl, routerOptions, convert }) {
const defaultLanguage = routerOptions.defaultLanguage
const urlParser = UrlParser(currentUrl)
const sitePrefix = routerOptions.prefix ? routerOptions.prefix.toLowerCase() : ''
const urlParser = parseCurrentUrl(currentUrl, sitePrefix)
let redirectTo = ''
let routeNamedParams = {}
let staticParamMatch = false
Expand All @@ -23,6 +24,9 @@ function RouterFinder({ routes, currentUrl, routerOptions, convert }) {
}
} else {
searchActiveRoute.path = pathWithoutQueryParams(searchActiveRoute)
if (sitePrefix) {
searchActiveRoute.path = `/${sitePrefix}${searchActiveRoute.path}`
}
}

return searchActiveRoute
Expand Down Expand Up @@ -102,6 +106,15 @@ function RouterFinder({ routes, currentUrl, routerOptions, convert }) {
return route.nestedRoutes && route.nestedRoutes.length > 0 && pathNames.length === 0
}

function parseCurrentUrl(currentUrl, sitePrefix) {
if (sitePrefix && sitePrefix.trim().length > 0) {
const noPrefixUrl = currentUrl.replace(sitePrefix + '/', '')
return UrlParser(noPrefixUrl)
} else {
return UrlParser(currentUrl)
}
}

function setCurrentRoute({ route, routePath, routeLanguage, urlParser, namedPath }) {
const routerRoute = RouterRoute({
routeInfo: route,
Expand Down
7 changes: 6 additions & 1 deletion src/spa_router.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,12 @@ function routeIsActive(queryPath, includePath = false) {
if (typeof window !== 'undefined') {
// Avoid full page reload on local routes
window.addEventListener('click', (event) => {
if (event.target.pathname && event.target.hostname === window.location.hostname && event.target.localName === 'a') {
const sitePrefix = routerOptions.prefix ? `/${routerOptions.prefix.toLowerCase()}` : ''
const targetHostNameInternal = event.target.pathname && event.target.hostname === window.location.hostname
const eventIsAnchor = event.target.localName === 'a'
const prefixMatchPath = sitePrefix.length > 1 ? event.target.pathname.startsWith(sitePrefix) : true

if (targetHostNameInternal && eventIsAnchor && prefixMatchPath) {
event.preventDefault()
let navigatePathname = event.target.pathname + event.target.search

Expand Down
27 changes: 27 additions & 0 deletions test/router/finder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,30 @@ describe('RouterFinder', function () {
})
})
})

describe('With site prefix', function () {
beforeEach(function () {
routes = [
{
name: '/',
component: 'PublicLayout',
nestedRoutes: [{ name: 'index', component: 'PublicIndex' }],
},
{ name: 'about-us', component: 'AboutUs' },
{ name: 'login', component: 'Login' },
{ name: 'project/:name', component: 'ProjectList' },
]

currentUrl = 'http://web.app/company/about-us'
routerOptions = { prefix: 'company' }
activeRoute = RouterFinder({ routes, currentUrl, routerOptions }).findActiveRoute()
})

it('should set path to root path', function () {
expect(activeRoute.path).to.equal('/company/about-us')
})

it('should set component name', function () {
expect(activeRoute.component).to.equal('AboutUs')
})
})
93 changes: 92 additions & 1 deletion test/spa_router.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe('Router', function () {
testRouter = SpaRouter(routes, pathName).setActiveRoute()
})

it('should set path to root path black', function () {
it('should set path to root path', function () {
expect(testRouter.path).to.equal('/')
})

Expand Down Expand Up @@ -1798,3 +1798,94 @@ describe('admin routes example localised', function () {
expect(localisedRoute('public/users/show/frank', 'es').path).to.equal('/publico/usuarios/mostrar/frank')
})
})

describe('With site prefix', function () {
const routes = [
{
name: '/',
component: 'PublicLayout',
nestedRoutes: [{ name: 'index', component: 'PublicIndex' }],
},
{ name: 'about-us', component: 'AboutUs' },
{ name: 'login', component: 'Login' },
{ name: 'project/:name', component: 'ProjectList' },
{
name: 'admin',
component: 'AdminLayout',
nestedRoutes: [
{ name: 'index', component: 'DashboardIndex' },
{
name: 'company',
component: 'CompanyLayout',
lang: { es: 'empresa' },
nestedRoutes: [
{ name: 'index', component: 'CompanyIndex' },
{ name: 'edit', component: 'CompanyEdit' },
],
},
{
name: 'employees',
component: 'EmployeesLayout',
lang: { es: 'empleados' },
nestedRoutes: [
{ name: 'index', component: 'EmployeesIndex' },
{ name: 'new', component: 'EmployeesNew', lang: { es: 'nuevo' } },
{ name: 'show/:id', component: 'EmployeesShow', lang: { es: 'mostrar/:id' } },
{ name: 'edit/:id', component: 'EmployeesEdit', lang: { es: 'modificar/:id' } },
{ name: 'calendar/:id', component: 'EmployeeCalendar', lang: { es: 'calendario/:id' } },
{ name: 'list/:id', component: 'EmployeeActivityList', lang: { es: 'listado/:id' } },
],
},
],
},
]

describe('about us route', function () {
beforeEach(function () {
currentUrl = 'http://web.app/company/about-us'
activeRoute = SpaRouter(routes, currentUrl, { prefix: 'company' }).setActiveRoute()
})

it('should set path to root path', function () {
expect(activeRoute.path).to.equal('/company/about-us')
})

it('should set component name', function () {
expect(activeRoute.component).to.equal('AboutUs')
})
})

describe('named params', function () {
beforeEach(function () {
currentUrl = 'http://web.app/company/project/miracle'
activeRoute = SpaRouter(routes, currentUrl, { prefix: 'company' }).setActiveRoute()
})

it('should set path to root path', function () {
expect(activeRoute.path).to.equal('/company/project/miracle')
})

it('should set component name', function () {
expect(activeRoute.component).to.equal('ProjectList')
})
})

describe('named params', function () {
beforeEach(function () {
currentUrl = 'http://web.app/admin/employees/show/12/Danny-filth'
activeRoute = SpaRouter(routes, currentUrl, { prefix: 'company' }).setActiveRoute()
})

it('should set path to root path', function () {
expect(activeRoute.path).to.equal('/company/admin/employees/show/12')
})

it('should set component name', function () {
expect(activeRoute.component).to.equal('AdminLayout')
})

it('should set named params', function () {
expect(activeRoute.childRoute.childRoute.namedParams.id).to.equal('12')
})
})
})
Loading

0 comments on commit 9d0bc5c

Please sign in to comment.