use routify

This commit is contained in:
Daniel Bulant 2021-05-20 16:59:12 +02:00
parent 7e2d9eb658
commit 8ea35930ab
36 changed files with 12202 additions and 550 deletions

7
.nolluprc.js Normal file
View file

@ -0,0 +1,7 @@
module.exports = {
hot: true,
contentBase: 'assets',
publicPath: 'build',
historyApiFallback: '__app.html',
port: 5000
}

18
.routify/config.js Normal file
View file

@ -0,0 +1,18 @@
module.exports = {
"pages": "src/pages",
"sourceDir": "public",
"routifyDir": ".routify",
"ignore": "",
"dynamicImports": true,
"singleBuild": false,
"noHashScroll": false,
"distDir": "dist",
"hashScroll": true,
"extensions": [
"svelte",
"html",
"svx",
"md"
],
"started": "2021-05-20T14:57:51.302Z"
}

102
.routify/routes.js Normal file
View file

@ -0,0 +1,102 @@
/**
* @roxi/routify 2.18.1
* File generated Thu May 20 2021 16:57:51 GMT+0200 (GMT+02:00)
*/
export const __version = "2.18.1"
export const __timestamp = "2021-05-20T14:57:51.330Z"
//buildRoutes
import { buildClientTree } from "@roxi/routify/runtime/buildRoutes"
//imports
//options
export const options = {}
//tree
export const _tree = {
"name": "_layout",
"filepath": "/_layout.svelte",
"root": true,
"ownMeta": {
"preload": "proximity"
},
"absolutePath": "/home/dan/Documents/node_projects/mangades/src/pages/_layout.svelte",
"children": [
{
"isFile": true,
"isDir": false,
"file": "_fallback.svelte",
"filepath": "/_fallback.svelte",
"name": "_fallback",
"ext": "svelte",
"badExt": false,
"absolutePath": "/home/dan/Documents/node_projects/mangades/src/pages/_fallback.svelte",
"importPath": "../src/pages/_fallback.svelte",
"isLayout": false,
"isReset": false,
"isIndex": false,
"isFallback": true,
"isPage": false,
"ownMeta": {},
"meta": {
"recursive": true,
"preload": "proximity",
"prerender": true
},
"path": "/_fallback",
"id": "__fallback",
"component": () => import('../src/pages/_fallback.svelte').then(m => m.default)
},
{
"isFile": true,
"isDir": false,
"file": "index.svelte",
"filepath": "/index.svelte",
"name": "index",
"ext": "svelte",
"badExt": false,
"absolutePath": "/home/dan/Documents/node_projects/mangades/src/pages/index.svelte",
"importPath": "../src/pages/index.svelte",
"isLayout": false,
"isReset": false,
"isIndex": true,
"isFallback": false,
"isPage": true,
"ownMeta": {},
"meta": {
"recursive": true,
"preload": "proximity",
"prerender": true
},
"path": "/index",
"id": "_index",
"component": () => import('../src/pages/index.svelte').then(m => m.default)
}
],
"isLayout": true,
"isReset": false,
"isIndex": false,
"isFallback": false,
"isPage": false,
"isFile": true,
"file": "_layout.svelte",
"ext": "svelte",
"badExt": false,
"importPath": "../src/pages/_layout.svelte",
"meta": {
"preload": "proximity",
"recursive": true,
"prerender": true
},
"path": "/",
"id": "__layout",
"component": () => import('../src/pages/_layout.svelte').then(m => m.default)
}
export const {tree, routes} = buildClientTree(_tree)

3
.routify/urlIndex.json Normal file
View file

@ -0,0 +1,3 @@
[
"/index"
]

154
README.md
View file

@ -1,105 +1,67 @@
*Looking for a shareable component template? Go here --> [sveltejs/component-template](https://github.com/sveltejs/component-template)*
# routify-starter
---
Starter template for [Routify](https://github.com/roxiness/routify).
# svelte app
### Get started
This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template.
#### Starter templates
| Template | Description |
|-------------------------------------------|-------------------------------------------------------------|
| [master](https://example.routify.dev/) | Default template, includes examples folder |
| [blog](https://blog-example.routify.dev/) | Generates a blog from local markdown posts. Includes mdsvex |
| [auth](https://auth-example.routify.dev/) | Embedded login on protected pages. Includes Auth0 |
To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit):
To use a template, run:
```bash
npx degit sveltejs/template svelte-app
cd svelte-app
```
`npx @roxi/routify init`
*Note that you will need to have [Node.js](https://nodejs.org) installed.*
or
`npx @roxi/routify init --branch <branch-name>`
The above commands will populate the current directory, they don't create a new one.
### npm scripts
| Syntax | Description |
|------------------|-----------------------------------------------------------------------------------|
| `dev` | Development (port 5000) |
| `dev:nollup` | Development with crazy fast rebuilds (port 5000) |
| `dev-dynamic` | Development with dynamic imports |
| `build` | Build a bundled app with SSR + prerendering and dynamic imports |
| `serve` | Run after a build to preview. Serves SPA on 5000 and SSR on 5005 |
| `deploy:*` | Deploy to netlify or now |
| `export` | Create static pages from content in dist folder (used by `npm run build`) |
### SSR and pre-rendering
SSR and pre-rendering are included in the default build process.
`npm run deploy:(now|netlify)` will deploy the app with SSR and prerendering included.
To render async data, call the `$ready()` helper whenever your data is ready.
If $ready() is present, rendering will be delayed till the function has been called.
Otherwise it will be rendered instantly.
See [src/pages/example/api/[showId].svelte](https://github.com/roxiness/routify-starter/blob/master/src/pages/example/api/%5BshowId%5D.svelte) for an example.
### Production
* For SPA or SSR apps please make sure that url rewrite is enabled on the server.
* For SPA redirect to `__app.html`.
* For SSR redirect to the lambda function or express server.
### Typescript
For Typescript, we recommend [@lamualfa](https://github.com/lamualfa) excellent [routify-ts](https://github.com/lamualfa/routify-ts/)
New project: `npx routify-ts init <project-name> [routify-init-args]`
Existing project: `npx routify-ts convert [project-directory]`
## Get started
### Issues?
Install the dependencies...
```bash
cd svelte-app
npm install
```
...then start [Rollup](https://rollupjs.org):
```bash
npm run dev
```
Navigate to [localhost:5000](http://localhost:5000). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes.
By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`.
If you're using [Visual Studio Code](https://code.visualstudio.com/) we recommend installing the official extension [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). If you are using other editors you may need to install a plugin in order to get syntax highlighting and intellisense.
## Building and running in production mode
To create an optimised version of the app:
```bash
npm run build
```
You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com).
## Single-page app mode
By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere.
If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for *any* path. You can make it so by editing the `"start"` command in package.json:
```js
"start": "sirv public --single"
```
## Using TypeScript
This template comes with a script to set up a TypeScript development environment, you can run it immediately after cloning the template with:
```bash
node scripts/setupTypeScript.js
```
Or remove the script via:
```bash
rm scripts/setupTypeScript.js
```
## Deploying to the web
### With [Vercel](https://vercel.com)
Install `vercel` if you haven't already:
```bash
npm install -g vercel
```
Then, from within your project folder:
```bash
cd public
vercel deploy --name my-project
```
### With [surge](https://surge.sh/)
Install `surge` if you haven't already:
```bash
npm install -g surge
```
Then, from within your project folder:
```bash
npm run build
surge public my-project.surge.sh
```
File on Github! See https://github.com/sveltech/routify/issues .

16
api/netlify/package.json Normal file
View file

@ -0,0 +1,16 @@
{
"name": "ssr",
"version": "1.0.0",
"description": "",
"main": "ssr.js",
"scripts": {
"build": "node utils/build.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"esbuild": "^0.8.8",
"tossr": "^1.3.1"
}
}

11
api/netlify/ssr.js Normal file
View file

@ -0,0 +1,11 @@
const fs = require('fs')
const { tossr } = require('tossr')
const { script, template } = require('./bundle.json')
exports.handler = async (event, context) => {
const qs = Object.entries(event.queryStringParameters)
.map(([key, value]) => `${key}=${value}`)
.join('&');
const body = await tossr(template, script, `${event.path}?${qs}`);
return { statusCode: 200, body: body + '\n<!--ssr rendered-->' }
}

View file

@ -0,0 +1,26 @@
/**
* Creates a JSON and inlines it with esbuild for ssr.js to consume
* {
* data: duh,
* script: inlined main.js
* template: __app.html
* }
*/
const { resolve } = require('path')
const { readFileSync, writeFileSync } = require('fs')
const { build } = require('esbuild')
const scriptPath = resolve(__dirname, '../../../dist/build/main.js')
const templatePath = resolve(__dirname, '../../../dist/__app.html')
const bundlePath = resolve(__dirname, '../build/bundle.js')
build({ entryPoints: [scriptPath], outfile: bundlePath, bundle: true }).then(() => {
const bundle = {
date: new Date,
script: readFileSync(bundlePath, 'utf8'),
template: readFileSync(templatePath, 'utf8')
}
writeFileSync(resolve(__dirname, '../bundle.json'), JSON.stringify(bundle, null, 2))
})

36
api/vercel-ssr/build.js Normal file
View file

@ -0,0 +1,36 @@
const { resolve } = require('path')
const { existsSync } = require('fs')
const { execSync } = require('child_process')
const { rollup } = require('rollup')
const shouldBuildSpa = process.env.NOW_GITHUB_DEPLOYMENT || process.env.NOW_BUILDER
const script = resolve(__dirname, '../../dist/build/main.js')
const bundlePath = resolve(__dirname, '../../dist/build/bundle.js')
build()
async function build() {
if (shouldBuildSpa)
execSync('npm install && npm run build:app', { cwd: resolve('..', '..'), stdio: 'inherit' })
else
await waitForAppToExist()
buildSSRBundle()
}
async function waitForAppToExist() {
while (!existsSync(script)) {
console.log(`checking if "${script}" exists`)
await new Promise(r => setTimeout(r, 2000))
}
console.log(`found "${script}"`)
}
async function buildSSRBundle() {
const bundle = await rollup({
input: script,
inlineDynamicImports: true,
})
await bundle.write({ format: 'umd', file: bundlePath, name: 'roxi-ssr' })
}

11
api/vercel-ssr/index.js Normal file
View file

@ -0,0 +1,11 @@
const fs = require('fs')
const { tossr } = require('tossr')
const script = fs.readFileSync(require.resolve('../../dist/build/bundle.js'), 'utf8')
const template = fs.readFileSync(require.resolve('../../dist/__app.html'), 'utf8')
module.exports = async (req, res) => {
const html = await tossr(template, script, req.url, {})
res.send(html + '\n<!--ssr rendered-->')
}

View file

@ -0,0 +1,8 @@
{
"scripts": {
"vercel-build": "node ./build.js"
},
"devDependencies": {
"rollup": "^2.28.2"
}
}

1
assets/404.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><linearGradient id="a" x1="2.625" x2="25.637" y1="13.491" y2="13.491" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2B2E81"/><stop offset="1" stop-color="#BE4F9C"/></linearGradient><path fill="url(#a)" d="M10.5 15.5H12v.5c0 .3.2.5.5.5s.5-.2.5-.5v-.5h.5c.3 0 .5-.2.5-.5s-.2-.5-.5-.5H13V13c0-.3-.2-.5-.5-.5s-.5.2-.5.5v1.5h-.9l.6-3.4c.1-.3-.1-.5-.4-.6-.3-.1-.5.1-.6.4l-.8 4c0 .1 0 .3.1.4s.4.2.5.2z"/><linearGradient id="b" x1="2.625" x2="25.637" y1="13.491" y2="13.491" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2B2E81"/><stop offset="1" stop-color="#BE4F9C"/></linearGradient><path fill="url(#b)" d="M20.5 15.5H22v.5c0 .3.2.5.5.5s.5-.2.5-.5v-.5h.5c.3 0 .5-.2.5-.5s-.2-.5-.5-.5H23V13c0-.3-.2-.5-.5-.5s-.5.2-.5.5v1.5h-.9l.6-3.4c.1-.3-.1-.5-.4-.6-.3-.1-.5.1-.6.4l-.8 4c0 .1 0 .3.1.4s.4.2.5.2z"/><linearGradient id="c" x1="2.625" x2="25.637" y1="22" y2="22" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2B2E81"/><stop offset="1" stop-color="#BE4F9C"/></linearGradient><path fill="url(#c)" d="M6.5 21.5h-.6c-.1-.3-.2-.6-.4-.9l.5-.4c.2-.2.2-.5 0-.7s-.5-.2-.7 0l-.4.4c-.3-.2-.6-.3-.9-.4V19c0-.3-.2-.5-.5-.5s-.5.2-.5.5v.6c-.3.1-.6.2-.9.4l-.4-.4c-.2-.2-.5-.2-.7 0s-.2.4 0 .6l.4.4c-.2.3-.3.6-.4.9H.5c-.3 0-.5.2-.5.5s.2.5.5.5h.6c.1.3.2.6.4.9l-.5.4c-.2.2-.2.5 0 .7.1.1.2.1.4.1s.3 0 .4-.1l.4-.4c.3.2.6.3.9.4v.5c0 .3.2.5.5.5s.4-.2.4-.5v-.6c.3-.1.6-.2.9-.4l.4.4c.1.1.2.1.4.1s.3 0 .4-.1c.2-.2.2-.5 0-.7l-.4-.4c.2-.3.3-.6.4-.9h.6c.1.1.3-.1.3-.4s-.2-.5-.5-.5zm-3 2c-.8 0-1.5-.7-1.5-1.5 0-.4.2-.8.4-1.1.3-.3.7-.4 1.1-.4.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5z"/><linearGradient id="d" x1="2.625" x2="25.637" y1="22" y2="22" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2B2E81"/><stop offset="1" stop-color="#BE4F9C"/></linearGradient><circle cx="3.5" cy="22" r=".5" fill="url(#d)"/><linearGradient id="e" x1="2.625" x2="25.637" y1="16" y2="16" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2B2E81"/><stop offset="1" stop-color="#BE4F9C"/></linearGradient><path fill="url(#e)" d="M31.5 12h-.8l.6-.6c.2-.2.2-.5 0-.7l-1.4-1.4c-.2-.2-.5-.2-.7 0l-.6.6V9c0-.3-.2-.5-.5-.5h-1V8c0-.8-.7-1.5-1.5-1.5h-17C7.7 6.5 7 7.2 7 8v5.6c-.3.1-.6.2-.9.4l-.4-.4c-.2-.2-.5-.2-.7 0s-.2.4 0 .6l.4.4c-.2.3-.3.6-.4.9h-.5c-.3 0-.5.2-.5.5s.2.5.5.5h.6c.1.3.2.6.4.9l-.5.4c-.2.2-.2.5 0 .7.1.1.2.1.4.1s.3 0 .4-.1l.4-.4c.3.2.6.3.9.4V20c0 .8.7 1.5 1.5 1.5H14v3h-3.5c-.3 0-.5.2-.5.5s.2.5.5.5h13c.3 0 .5-.2.5-.5s-.2-.5-.5-.5H20v-3h5.5c.8 0 1.5-.7 1.5-1.5v-1.5h1c.3 0 .5-.2.5-.5v-.8l.6.6c.2.2.5.2.7 0l1.4-1.4c.2-.2.2-.5 0-.7l-.5-.7h.8c.3 0 .5-.2.5-.5v-2c0-.3-.2-.5-.5-.5zm-4.5.5c.6 0 1 .4 1 1s-.4 1-1 1v-2zm-18.5-5h17c.3 0 .5.2.5.5v9.5H8V8c0-.3.2-.5.5-.5zM7 17.4c-.6-.2-1-.8-1-1.4 0-.4.2-.8.4-1.1.2-.2.4-.3.6-.3v2.8zm12 7.1h-4v-3h4v3zm6.5-4h-17c-.3 0-.5-.2-.5-.5v-1.5h18V20c0 .3-.2.5-.5.5zM31 14h-.7c-.2 0-.4.1-.5.4-.1.2-.1.4-.2.6-.1.2-.1.4.1.6l.5.5-.7.7-.5-.6c-.2-.2-.4-.2-.6-.1-.2.1-.4.2-.6.2-.2.1-.3.3-.3.5v.7H27v-2c1.1 0 2-.9 2-2s-.9-2-2-2v-2h.5v.7c0 .2.1.4.3.5.2.1.4.1.6.2.2.1.4.1.6-.1l.5-.5.7.7-.5.5c-.2.2-.2.4-.1.6.1.2.2.4.2.6.1.2.3.4.5.4h.7v.9z"/><linearGradient id="f" x1="2.625" x2="25.637" y1="13.5" y2="13.5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2B2E81"/><stop offset="1" stop-color="#BE4F9C"/></linearGradient><path fill="url(#f)" d="M16.5 16.5h1c.8 0 1.5-.7 1.5-1.5v-3c0-.8-.7-1.5-1.5-1.5h-1c-.8 0-1.5.7-1.5 1.5v3c0 .8.7 1.5 1.5 1.5zM16 12c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v3c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-3z"/></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

22
assets/__app.html Normal file
View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte app</title>
<meta name="theme-color" content="#E938C2">
<link rel="apple-touch-icon" href="/images/touch-icons/logo-192.png">
<link rel="manifest" href="/manifest.json">
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel="modulepreload" href="/build/main.js" />
<script type="module" src="/build/main.js"></script>
</head>
<body>
<noscript>Please enable Javascript for best experience.</noscript>
</body>
</html>

BIN
assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -32,7 +32,6 @@ label {
input, button, select, textarea {
font-family: inherit;
font-size: inherit;
-webkit-padding: 0.4em 0;
padding: 0.4em;
margin: 0 0 0.5em 0;
box-sizing: border-box;
@ -44,6 +43,10 @@ input:disabled {
color: #ccc;
}
input[type="range"] {
height: 0;
}
button {
color: #333;
background-color: #f4f4f4;

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

21
assets/manifest.json Normal file
View file

@ -0,0 +1,21 @@
{
"background_color": "#ffffff",
"theme_color": "#E938C2",
"name": "Routify app",
"short_name": "Routify app",
"start_url": "/",
"display": "standalone",
"icons": [
{
"src": "/images/touch-icons/logo-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/images/touch-icons/logo-800.png",
"sizes": "800x800",
"type": "image/png",
"purpose": "maskable any"
}
]
}

2
assets/robots.txt Normal file
View file

@ -0,0 +1,2 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *

23
netlify.toml Normal file
View file

@ -0,0 +1,23 @@
[build]
publish = "dist"
functions = "api/netlify"
command = "npm run build && cd api/netlify && npm run build"
# Dev doesn't work yet. Any takers?
# [dev]
# command = "npm run dev:ssr"
# targetPort = 5000
# publish = "assets"
# autoLaunch = true
[[redirects]]
# SSR and SPA
from = "/*"
to = "/.netlify/functions/ssr"
status = 200
# SPA only
# from = "/*"
# to = "/__app.html"
# status = 200

11675
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,58 @@
{
"name": "svelte-app",
"version": "1.0.0",
"private": true,
"@comments scripts": {
"dev": "develop with blazing fast rebuilds",
"dev:features": "develop with features like SSR and serviceworker enabled",
"build": "run build scripts below",
"build:app": "build single page application (SPA)",
"build:static": "Generate static pages",
"serve": "serve content in 'dist' folder",
"rollup": "run the rollup bundler",
"nollup": "run the nollup no-bundler",
"routify": "run routify"
},
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public --no-clear"
"dev": "run-p routify nollup",
"dev:ssr": "run-p routify rollup",
"build": "run-s build:*",
"build:app": "routify -b && rollup -c",
"build:static": "spank",
"serve": "spassr --ssr",
"rollup": "rollup -cw",
"nollup": "nollup -c --verbose",
"routify": "routify"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^11.0.0",
"rollup": "^2.3.4",
"rollup-plugin-css-only": "^3.1.0",
"@rollup/plugin-commonjs": "^19.0.0",
"@rollup/plugin-node-resolve": "^13.0.0",
"@roxi/routify": "^2.18.1",
"cross-env": "^7.0.3",
"fs-extra": "^10.0.0",
"nollup": "^0.16.4",
"npm-run-all": "^4.1.5",
"postcss": "^8.2.14",
"postcss-import": "^14.0.1",
"rollup": "^2.47.0",
"rollup-plugin-hot": "^0.1.1",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-node-polyfills": "^0.2.1",
"rollup-plugin-svelte": "^7.0.0",
"rollup-plugin-terser": "^7.0.0",
"svelte": "^3.0.0"
"rollup-plugin-svelte": "^7.1.0",
"rollup-plugin-svelte-hot": "^1.0.0-7",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-workbox": "^5.2.1",
"spank": "^1.7.0",
"spassr": "^2.6.0",
"svelte": "^3.38.2",
"svelte-preprocess": "^4.7.3",
"tossr": "^1.4.2"
},
"dependencies": {
"sirv-cli": "^1.0.0"
"routify": {
"extensions": "svelte,html,svx,md"
},
"spassr": {},
"spank": {
"blacklist": [
"/example/modal/basic/4"
]
}
}

View file

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel='stylesheet' href='/global.css'>
<link rel='stylesheet' href='/build/bundle.css'>
<script defer src='/build/bundle.js'></script>
</head>
<body>
</body>
</html>

View file

@ -1,80 +1,94 @@
import svelte from 'rollup-plugin-svelte';
import commonjs from '@rollup/plugin-commonjs';
import svelte from 'rollup-plugin-svelte-hot';
import Hmr from 'rollup-plugin-hot'
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import css from 'rollup-plugin-css-only';
import nodePolyfills from 'rollup-plugin-node-polyfills';
import json from "@rollup/plugin-json";
import { copySync, removeSync } from 'fs-extra'
import { spassr } from 'spassr'
import getConfig from '@roxi/routify/lib/utils/config'
import autoPreprocess from 'svelte-preprocess'
import postcssImport from 'postcss-import'
import { injectManifest } from 'rollup-plugin-workbox'
const { distDir } = getConfig() // use Routify's distDir for SSOT
const assetsDir = 'assets'
const buildDir = `${distDir}/build`
const isNollup = !!process.env.NOLLUP
const production = !process.env.ROLLUP_WATCH;
function serve() {
let server;
// clear previous builds
removeSync(distDir)
removeSync(buildDir)
function toExit() {
if (server) server.kill(0);
}
return {
writeBundle() {
if (server) return;
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
const serve = () => ({
writeBundle: async () => {
const options = {
assetsDir: [assetsDir, distDir],
entrypoint: `${assetsDir}/__app.html`,
script: `${buildDir}/main.js`
}
spassr({ ...options, port: 5000 })
spassr({ ...options, ssr: true, port: 5005, ssrOptions: { inlineDynamicImports: true, dev: true } })
}
})
const copyToDist = () => ({ writeBundle() { copySync(assetsDir, distDir) } })
process.on('SIGTERM', toExit);
process.on('exit', toExit);
}
};
}
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
},
plugins: [
nodePolyfills(),
svelte({
compilerOptions: {
// enable run-time checks when not in production
dev: !production
}
}),
// we'll extract any component CSS out into
// a separate file - better for performance
css({ output: 'bundle.css' }),
preserveEntrySignatures: false,
input: [`src/main.js`],
output: {
sourcemap: true,
format: 'esm',
dir: buildDir,
// for performance, disabling filename hashing in development
chunkFileNames:`[name]${production && '-[hash]' || ''}.js`
},
plugins: [
svelte({
emitCss: false,
hot: isNollup,
preprocess: [
autoPreprocess({
postcss: { plugins: [postcssImport()] },
defaults: { style: 'postcss' }
})
]
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte']
}),
commonjs(),
json(),
// resolve matching modules from current working directory
resolve({
browser: true,
dedupe: importee => !!importee.match(/svelte(\/|$)/)
}),
commonjs(),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
production && terser(),
!production && !isNollup && serve(),
!production && !isNollup && livereload(distDir), // refresh entire window when code is updated
!production && isNollup && Hmr({ inMemory: true, public: assetsDir, }), // refresh only updated code
{
// provide node environment on the client
transform: code => ({
code: code.replace(/process\.env\.NODE_ENV/g, `"${process.env.NODE_ENV}"`),
map: { mappings: '' }
})
},
injectManifest({
globDirectory: assetsDir,
globPatterns: ['**/*.{js,css,svg}', '__app.html'],
swSrc: `src/sw.js`,
swDest: `${distDir}/serviceworker.js`,
maximumFileSizeToCacheInBytes: 10000000, // 10 MB,
mode: 'production'
}),
production && copyToDist(),
],
watch: {
clearScreen: false,
buildDelay: 100,
}
}

6
sandbox.config.json Normal file
View file

@ -0,0 +1,6 @@
{
"container": {
"port": 5000,
"template": "node"
}
}

View file

@ -1,117 +0,0 @@
// @ts-check
/** This script modifies the project to support TS code in .svelte files like:
<script lang="ts">
export let name: string;
</script>
As well as validating the code for CI.
*/
/** To work on this script:
rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template
*/
const fs = require("fs")
const path = require("path")
const { argv } = require("process")
const projectRoot = argv[2] || path.join(__dirname, "..")
// Add deps to pkg.json
const packageJSON = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf8"))
packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
"svelte-check": "^1.0.0",
"svelte-preprocess": "^4.0.0",
"@rollup/plugin-typescript": "^8.0.0",
"typescript": "^4.0.0",
"tslib": "^2.0.0",
"@tsconfig/svelte": "^1.0.0"
})
// Add script for checking
packageJSON.scripts = Object.assign(packageJSON.scripts, {
"validate": "svelte-check"
})
// Write the package JSON
fs.writeFileSync(path.join(projectRoot, "package.json"), JSON.stringify(packageJSON, null, " "))
// mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too
const beforeMainJSPath = path.join(projectRoot, "src", "main.js")
const afterMainTSPath = path.join(projectRoot, "src", "main.ts")
fs.renameSync(beforeMainJSPath, afterMainTSPath)
// Switch the app.svelte file to use TS
const appSveltePath = path.join(projectRoot, "src", "App.svelte")
let appFile = fs.readFileSync(appSveltePath, "utf8")
appFile = appFile.replace("<script>", '<script lang="ts">')
appFile = appFile.replace("export let name;", 'export let name: string;')
fs.writeFileSync(appSveltePath, appFile)
// Edit rollup config
const rollupConfigPath = path.join(projectRoot, "rollup.config.js")
let rollupConfig = fs.readFileSync(rollupConfigPath, "utf8")
// Edit imports
rollupConfig = rollupConfig.replace(`'rollup-plugin-terser';`, `'rollup-plugin-terser';
import sveltePreprocess from 'svelte-preprocess';
import typescript from '@rollup/plugin-typescript';`)
// Replace name of entry point
rollupConfig = rollupConfig.replace(`'src/main.js'`, `'src/main.ts'`)
// Add preprocessor
rollupConfig = rollupConfig.replace(
'compilerOptions:',
'preprocess: sveltePreprocess({ sourceMap: !production }),\n\t\t\tcompilerOptions:'
);
// Add TypeScript
rollupConfig = rollupConfig.replace(
'commonjs(),',
'commonjs(),\n\t\ttypescript({\n\t\t\tsourceMap: !production,\n\t\t\tinlineSources: !production\n\t\t}),'
);
fs.writeFileSync(rollupConfigPath, rollupConfig)
// Add TSConfig
const tsconfig = `{
"extends": "@tsconfig/svelte/tsconfig.json",
"include": ["src/**/*"],
"exclude": ["node_modules/*", "__sapper__/*", "public/*"]
}`
const tsconfigPath = path.join(projectRoot, "tsconfig.json")
fs.writeFileSync(tsconfigPath, tsconfig)
// Delete this script, but not during testing
if (!argv[2]) {
// Remove the script
fs.unlinkSync(path.join(__filename))
// Check for Mac's DS_store file, and if it's the only one left remove it
const remainingFiles = fs.readdirSync(path.join(__dirname))
if (remainingFiles.length === 1 && remainingFiles[0] === '.DS_store') {
fs.unlinkSync(path.join(__dirname, '.DS_store'))
}
// Check if the scripts folder is empty
if (fs.readdirSync(path.join(__dirname)).length === 0) {
// Remove the scripts folder
fs.rmdirSync(path.join(__dirname))
}
}
// Adds the extension recommendation
fs.mkdirSync(path.join(projectRoot, ".vscode"), { recursive: true })
fs.writeFileSync(path.join(projectRoot, ".vscode", "extensions.json"), `{
"recommendations": ["svelte.svelte-vscode"]
}
`)
console.log("Converted to TypeScript.")
if (fs.existsSync(path.join(projectRoot, "node_modules"))) {
console.log("\nYou will need to re-run your dependency manager to get started.")
}

View file

@ -1,41 +1,10 @@
<script>
import request from "./request";
var name = "";
var result = request("manga", "title=" + name + "&contentRating[]=safe&contentRating[]=suggestive");
$: result = request("manga", "title=" + name + "&contentRating[]=safe&contentRating[]=suggestive");
result.then(console.log);
import { Router } from "@roxi/routify";
import { routes } from "../.routify/routes";
</script>
<main>
<style global>
@import "../assets/global.css";
</style>
<h1>MANGADEX</h1>
<input type="text" bind:value={name}>
{#await result}
Loading...
{:then result}
<br>
Showing results: {result.results.length}
<br>
Total results: {result.total}
<ul>
{#each result.results as manga}
<li>
{manga.data.attributes.title.en}
</li>
{/each}
</ul>
{/await}
</main>
<style>
main
{
max-width: 450px;
margin: auto;
}
input {
width: 100%;
}
</style>
<Router {routes} />

20
src/Serviceworker.svelte Normal file
View file

@ -0,0 +1,20 @@
<script>
/**
* This file handles serviceworker registration
* To enable it, import it from another file, ie. src/pages/_layout.svelte
* ⚠ The imported component could get treeshaken if not used, eg. <SW />
* For configuring the serviceworker, refer to sw.js
*/
if ("serviceWorker" in navigator) {
import("workbox-window").then(async ({ Workbox }) => {
const wb = new Workbox("/serviceworker.js");
const registration = await wb.register();
// Reload the page if the PWA has been updated. Change strategy if needed.
wb.addEventListener("redundant", () => {
location.reload();
console.log("updated app");
});
});
}
</script>

View file

@ -1,7 +1,6 @@
import HMR from '@roxi/routify/hmr'
import App from './App.svelte';
const app = new App({
target: document.body
});
const app = HMR(App, { target: document.body }, 'routify-app')
export default app;

View file

@ -0,0 +1,24 @@
<script>
import { url } from '@roxi/routify'
</script>
<style>
.huge {
font-size: 12rem;
}
.e404 {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
</style>
<div class="e404">
<div class="huge">404</div>
<div class="big">Page not found.
<!-- link to the parent folder of _fallback.svelte -->
<a href={$url('../')}>Go back</a>
</div>
</div>

2
src/pages/_layout.svelte Normal file
View file

@ -0,0 +1,2 @@
<!-- routify:options preload="proximity" -->
<slot />

40
src/pages/index.svelte Normal file
View file

@ -0,0 +1,40 @@
<script>
import request from "../util/request";
var name = "";
var result = request("manga", "title=" + name + "&contentRating[]=safe&contentRating[]=suggestive");
$: result = request("manga", "title=" + name + "&contentRating[]=safe&contentRating[]=suggestive");
result.then(console.log);
</script>
<main>
<h1>MANGADEX</h1>
<input type="text" bind:value={name}>
{#await result}
Loading...
{:then result}
<br>
Showing results: {result.results.length}
<br>
Total results: {result.total}
<ul>
{#each result.results as manga}
<li>
{manga.data.attributes.title.en}
</li>
{/each}
</ul>
{/await}
</main>
<style>
main
{
max-width: 450px;
margin: auto;
}
input {
width: 100%;
}
</style>

108
src/sw.js Normal file
View file

@ -0,0 +1,108 @@
// @ts-check
import { registerRoute, setDefaultHandler, setCatchHandler } from 'workbox-routing';
import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies';
import { skipWaiting, clientsClaim } from 'workbox-core';
import { precacheAndRoute, matchPrecache } from 'workbox-precaching';
import { ExpirationPlugin } from 'workbox-expiration';
import { RoutifyPlugin, freshCacheData } from '@roxi/routify/workbox-plugin'
/**********
* CONFIG *
**********/
const entrypointUrl = '__app.html' // entrypoint
const fallbackImage = '404.svg'
const files = self.__WB_MANIFEST // files matching globDirectory and globPattern in rollup.config.js
const externalAssetsConfig = () => ({
cacheName: 'external',
plugins: [
RoutifyPlugin({
validFor: 60 // cache is considered fresh for n seconds.
}),
new ExpirationPlugin({
maxEntries: 50, // last used entries will be purged when we hit this limit
purgeOnQuotaError: true // purge external assets on quota error
})]
})
/**************
* INITIALIZE *
**************/
/**
* precache all files
* remember to precache __app.html and 404.svg if caching of all files is disabled
*/
precacheAndRoute(files)
/** precache only fallback files */
// precacheAndRoute(files.filter(file =>
// ['__app.html', '404.svg']
// .includes(file.url)
// ))
skipWaiting() // auto update service workers across all tabs when new release is available
clientsClaim() // take control of client without having to wait for refresh
/**
* manually upgrade service worker by sending a SKIP_WAITING message.
* (remember to disable skipWaiting() above)
*/
// addEventListener('message', event => { if (event.data && event.data.type === 'SKIP_WAITING') skipWaiting(); });
/**********
* ROUTES *
**********/
// serve local pages from the SPA entry point (__app.html)
registerRoute(isLocalPage, matchPrecache(entrypointUrl))
// serve local assets from cache first
registerRoute(isLocalAsset, new CacheFirst())
// serve external assets from cache if they're fresh
registerRoute(hasFreshCache, new CacheFirst(externalAssetsConfig()))
// serve external pages and assets
setDefaultHandler(new NetworkFirst(externalAssetsConfig()));
// serve a fallback for 404s if possible or respond with an error
setCatchHandler(async ({ event }) => {
switch (event.request.destination) {
case 'document':
return await matchPrecache(entrypointUrl)
case 'image':
return await matchPrecache(fallbackImage)
default:
return Response.error();
}
})
/**********
* CONDITIONS *
**********/
function isLocalAsset({ url, request }) { return url.host === self.location.host && request.destination != 'document' }
function isLocalPage({ url, request }) { return url.host === self.location.host && request.destination === 'document' }
function hasFreshCache(event) { return !!freshCacheData(event) }
/** Example condition */
function hasWitheringCache(event) {
const cache = freshCacheData(event)
if (cache) {
const { cachedAt, validFor, validLeft, validUntil } = cache
// return true if half the fresh time has passed
return validFor / 2 > validFor - validLeft
}
}

17
vercel.json Normal file
View file

@ -0,0 +1,17 @@
{
"version": 2,
"functions": {
"api/vercel-ssr/index.js": {
"includeFiles": "dist/**"
}
},
"routes": [
{
"handle": "filesystem"
},
{
"src": "/.*",
"dest": "/api/vercel-ssr/index.js"
}
]
}