Svelte kit transition

This commit is contained in:
Michal Vanko 2021-04-24 18:24:17 +02:00
parent 59db328b4b
commit 58347b9ca6
29 changed files with 3451 additions and 7180 deletions

20
.eslintrc.cjs Normal file
View File

@ -0,0 +1,20 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
plugins: ['svelte3', '@typescript-eslint'],
ignorePatterns: ['*.cjs'],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
settings: {
'svelte3/typescript': require('typescript')
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 2019
},
env: {
browser: true,
es2017: true,
node: true
}
};

4
.gitignore vendored
View File

@ -5,6 +5,10 @@ yarn-error.log
/cypress/screenshots/ /cypress/screenshots/
/__sapper__/ /__sapper__/
/.svelte
/build
/functions
#amplify #amplify
amplify/\#current-cloud-backend amplify/\#current-cloud-backend
amplify/.config/local-* amplify/.config/local-*

1
.npmrc Normal file
View File

@ -0,0 +1 @@
engine-strict=true

4
.prettierignore Normal file
View File

@ -0,0 +1,4 @@
.svelte/**
static/**
build/**
node_modules/**

6
.prettierrc Normal file
View File

@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}

10176
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,56 +2,45 @@
"name": "michalvankodev", "name": "michalvankodev",
"description": "My personal website with blog", "description": "My personal website with blog",
"version": "0.0.1", "version": "0.0.1",
"type": "module",
"scripts": { "scripts": {
"dev": "sapper dev", "dev": "svelte-kit dev",
"prebuild": "node src/", "build": "svelte-kit build --verbose",
"build": "sapper build --legacy", "export": "svelte-kit build",
"export": "sapper export", "preview": "svelte-kit preview",
"start": "node __sapper__/build", "start": "svelte-kit start",
"cy:run": "cypress run", "cy:run": "cypress run",
"cy:open": "cypress open", "cy:open": "cypress open",
"test": "run-p --race dev cy:run" "test": "run-p --race dev cy:run",
"lint": "prettier --check . && eslint --ignore-path .gitignore .",
"format": "prettier --write ."
}, },
"dependencies": { "dependencies": {
"@rollup/plugin-typescript": "^8.0.0", "classnames": "^2.3.1",
"@types/node": "^14.14.10", "date-fns": "^2.21.1",
"classnames": "^2.2.6", "feed": "^4.2.2",
"compression": "^1.7.4",
"date-fns": "^2.16.1",
"feed": "^4.2.1",
"front-matter": "^4.0.2", "front-matter": "^4.0.2",
"marked": "^1.2.5", "marked": "^2.0.3",
"polka": "^0.5.2", "ramda": "^0.27.1"
"ramda": "^0.27.1",
"sirv": "^1.0.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.9", "@sveltejs/adapter-static": "^1.0.0-next.4",
"@babel/plugin-syntax-dynamic-import": "^7.8.3", "@sveltejs/kit": "^1.0.0-next.85",
"@babel/plugin-transform-runtime": "^7.12.1",
"@babel/preset-env": "^7.12.7",
"@babel/runtime": "^7.12.5",
"@rollup/plugin-typescript": "^8.0.0",
"@tsconfig/svelte": "^1.0.10", "@tsconfig/svelte": "^1.0.10",
"@types/classnames": "^2.2.11", "@types/classnames": "^2.3.1",
"@types/ramda": "^0.27.32", "@types/node": "^14.14.41",
"autoprefixer": "^10.0.4", "@types/ramda": "^0.27.40",
"npm-run-all": "^4.1.5", "@typescript-eslint/eslint-plugin": "^4.19.0",
"postcss": "^8.1.10", "@typescript-eslint/parser": "^4.19.0",
"rollup": "^2.34.0", "eslint": "^7.22.0",
"rollup-plugin-babel": "^4.4.0", "eslint-config-prettier": "^8.1.0",
"rollup-plugin-commonjs": "^10.1.0", "eslint-plugin-svelte3": "^3.1.0",
"rollup-plugin-node-resolve": "^5.2.0", "prettier": "~2.2.1",
"rollup-plugin-replace": "^2.2.0", "prettier-plugin-svelte": "^2.2.0",
"rollup-plugin-svelte": "^7.0.0", "svelte": "^3.37.0",
"rollup-plugin-svg": "^2.0.0", "svelte-preprocess": "^4.7.2",
"rollup-plugin-terser": "^7.0.2", "tslib": "^2.2.0",
"sapper": "^0.28.10", "typescript": "^4.2.4",
"svelte": "^3.30.1", "vite": "^2.2.1"
"svelte-check": "^1.1.17",
"svelte-preprocess": "^4.6.1",
"ts-node": "^9.1.1",
"tslib": "^2.0.3",
"typescript": "^4.1.2"
} }
} }

View File

@ -1,7 +0,0 @@
// prettier.config.js or .prettierrc.js
module.exports = {
trailingComma: 'es5',
tabWidth: 2,
semi: false,
singleQuote: true,
}

View File

@ -11,35 +11,20 @@
<link rel="alternate" type="application/rss+xml" title="RSS feed for latest posts" href="https://michalvanko.dev/feed.xml" /> <link rel="alternate" type="application/rss+xml" title="RSS feed for latest posts" href="https://michalvanko.dev/feed.xml" />
<link rel="alternate" title="JSON feed for latest posts" type="application/json" href="https://michalvanko.dev/feed.json" /> <link rel="alternate" title="JSON feed for latest posts" type="application/json" href="https://michalvanko.dev/feed.json" />
%sapper.base% <link rel="stylesheet" href="/global.css" />
<link rel="stylesheet" href="/print.css" media="print" />
<link rel="stylesheet" href="global.css" /> <link rel="stylesheet" href="/fonts.css" />
<link rel="stylesheet" href="print.css" media="print" />
<link rel="stylesheet" href="fonts.css" />
<!-- <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,400i,600,600i&display=swap&subset=latin-ext" rel="stylesheet"> --> <!-- <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,400i,600,600i&display=swap&subset=latin-ext" rel="stylesheet"> -->
<link rel="manifest" href="manifest.json" /> <link rel="manifest" href="/manifest.json" />
<link rel="icon" type="image/svg+xml" href="m-svgfavicon-192x192.svg" />
<link rel="icon" type="image/png" href="m-svgfavicon-192x192.png" />
<!-- Sapper generates a <style> tag containing critical CSS
for the current page. CSS for the rest of the app is
lazily loaded when it precaches secondary pages -->
%sapper.styles%
<link rel="icon" type="image/svg+xml" href="/m-svgfavicon-192x192.svg" />
<link rel="icon" type="image/png" href="/m-svgfavicon-192x192.png" />
<!-- This contains the contents of the <svelte:head> component, if <!-- This contains the contents of the <svelte:head> component, if
the current page has one --> the current page has one -->
%sapper.head% %svelte.head%
<!-- Sapper creates a <script> tag containing `app/client.js`
and anything else it needs to hydrate the app and
initialise the router -->
%sapper.scripts%
</head> </head>
<body> <body>
<!-- The application will be rendered inside this element, %svelte.body%
because `app/client.js` references it -->
<div id="sapper">%sapper.html%</div>
</body> </body>
</html> </html>

View File

@ -1,5 +0,0 @@
import * as sapper from '@sapper/app';
sapper.start({
target: document.querySelector('#sapper')
});

View File

@ -60,7 +60,7 @@
<section class="nav-main"> <section class="nav-main">
<ul> <ul>
<li> <li>
<a class={classNames({ selected: segment === undefined })} href="."> <a class={classNames({ selected: segment === undefined })} href="/">
Introduction Introduction
</a> </a>
</li> </li>

View File

@ -43,7 +43,7 @@
<ul class="tags-list"> <ul class="tags-list">
{#each post.tags as tag} {#each post.tags as tag}
<li> <li>
<a href="blog?tag={tag}">{tag}</a> <a href="/blog?tag={tag}">{tag}</a>
</li> </li>
{/each} {/each}
</ul> </ul>

3
src/global.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
/// <reference types="@sveltejs/kit" />
/// <reference types="svelte" />
/// <reference types="vite/client" />

View File

@ -1,11 +1,11 @@
<script context="module" lang="typescript"> <script context="module" lang="typescript">
import { take } from 'ramda' import { take } from 'ramda'
export function preload({ params, query }) { export function load({ fetch }) {
return this.fetch(`blog.json`) return fetch(`/blog.json`)
.then((r) => r.json()) .then((r) => r.json())
.then((posts) => { .then((posts) => {
return { latestPosts: take(5, posts) } return { props: { latestPosts: take(5, posts) }}
}) })
} }
</script> </script>

View File

@ -1,41 +0,0 @@
<script lang="typescript">
export let status
export let error
const dev = process.env.NODE_ENV === 'development'
</script>
<style>
h1,
p {
margin: 0 auto;
}
h1 {
font-size: 2.8em;
font-weight: 700;
margin: 0 0 0.5em 0;
}
p {
margin: 1em auto;
}
@media (min-width: 480px) {
h1 {
font-size: 4em;
}
}
</style>
<svelte:head>
<title>{status}</title>
</svelte:head>
<h1>{status}</h1>
<p>{error.message}</p>
{#if dev && error.stack}
<pre>{error.stack}</pre>
{/if}

View File

@ -8,23 +8,25 @@ export interface SinglePost {
body: string body: string
} }
export async function get(req, res, next) { export async function get({ params }) {
// the `slug` parameter is available because // the `slug` parameter is available because
// this file is called [slug].json.js // this file is called [slug].json.js
const { slug } = req.params const { slug } = params
let postSource: string let postSource: string
try { try {
postSource = await promisify(readFile)(`_posts/blog/${slug}.md`, 'utf-8') postSource = await promisify(readFile)(`_posts/blog/${slug}.md`, 'utf-8')
} catch (e) { } catch (e) {
if (e.code === 'ENOENT') { if (e.code === 'ENOENT') {
res.statusCode = 404 return {
res.end('Post not found \n' + e.toString()) status: 404,
return body: 'Post not found \n' + e.toString(),
}
}
return {
status: 500,
body: 'Error loading post source file. \n' + e.toString(),
} }
res.statusCode = 500
res.end('Error loading post source file. \n' + e.toString())
return
} }
const parsedPost = fm<PostAttributes>(postSource) const parsedPost = fm<PostAttributes>(postSource)
@ -34,6 +36,7 @@ export async function get(req, res, next) {
body: parsedPost.body, body: parsedPost.body,
}) })
res.setHeader('Content-Type', 'application/json') return {
res.end(JSON.stringify(response)) body: response,
}
} }

View File

@ -1,25 +1,37 @@
<script context="module"> <script context="module" lang="typescript">
export async function preload({ params, query }) { /**
const res = await this.fetch(`blog/${params.slug}.json`) * @type {import('@sveltejs/kit').Load}
const data = await res.json() */
export async function load({ fetch, page: { params }}) {
if (res.status === 200) { try {
return { post: data } const res = await fetch(`${params.slug}.json`)
} else { const data = await res.json()
this.error(res.status, data.message)
if (res.ok) {
return { props: { post: data }}
}
return {
status: res.status,
error: new Error(`Could not load ${params.slug} post`)
}
} catch(e) {
return {
status: 500,
error: e
}
} }
} }
</script> </script>
<script> <script lang="typescript">
import { onMount } from 'svelte' import { onMount } from 'svelte'
import ArticleFooter from '../../components/blog/article-footer.svelte' import ArticleFooter from '../../components/blog/article-footer.svelte'
import Prism from '../../../static/prism.js' // import Prism from '../../../static/prism.js'
export let post export let post
onMount(() => { onMount(() => {
Prism.highlightAll() // Prism.highlightAll()
}) })
</script> </script>
@ -44,7 +56,6 @@
so we have to use the :global(...) modifier to target so we have to use the :global(...) modifier to target
all elements inside .content all elements inside .content
*/ */
.content :global(pre) { .content :global(pre) {
background-color: #f9f9f9; background-color: #f9f9f9;
box-shadow: inset 1px 1px 5px rgba(0, 0, 0, 0.05); box-shadow: inset 1px 1px 5px rgba(0, 0, 0, 0.05);

View File

@ -1,10 +1,10 @@
import { getBlogListing } from './_content' import { getBlogListing } from './_content'
export async function get(req, res) { export async function get({ query }) {
const { tag } = req.query const { tag } = query
const filteredContents = await getBlogListing(tag) const filteredContents = await getBlogListing(tag)
res.writeHead(200, { return {
'Content-Type': 'application/json', status: 200,
}) body: filteredContents,
res.end(JSON.stringify(filteredContents)) }
} }

View File

@ -1,15 +1,18 @@
<script context="module" lang="typescript"> <script context="module" lang="typescript">
export function preload({ params, query }) { /**
* @type {import('@sveltejs/kit').Load}
*/
export function load({ fetch, page: { params, query }}) {
const blogQuery = query const blogQuery = query
? '?' + ? '?' +
Object.entries(query) Object.entries(query)
.map(q => q.join('=')) .map(q => q.join('='))
.join('&') .join('&')
: '' : ''
return this.fetch(`blog.json${blogQuery}`) return fetch(`blog.json${blogQuery}`)
.then(r => r.json()) .then(r => r.json())
.then(posts => { .then(posts => {
return { posts, query } return {props: { posts, query }}
}) })
} }
</script> </script>

View File

@ -1,10 +1,10 @@
import { getFeed } from './_feed' import { getFeed } from './_feed'
export async function get(req, res) { export async function get() {
const feed = await getFeed() const feed = await getFeed()
res.writeHead(200, { return {
'Content-Type': 'application/json', status: 200,
}) body: feed.json1(),
res.end(feed.json1()) }
} }

View File

@ -3,8 +3,11 @@ import { getFeed } from './_feed'
export async function get(req, res) { export async function get(req, res) {
const feed = await getFeed() const feed = await getFeed()
res.writeHead(200, { return {
'Content-Type': 'application/xml', status: 200,
}) headers: {
res.end(feed.rss2()) 'Content-Type': 'application/xml',
},
body: feed.rss2(),
}
} }

View File

@ -1,9 +1,3 @@
<script context="module">
// export async function preload() {
// return this.redirect(302, 'portfolio')
// }
</script>
<svelte:head> <svelte:head>
<title>Introduction @michalvankodev</title> <title>Introduction @michalvankodev</title>
</svelte:head> </svelte:head>

View File

@ -22,14 +22,15 @@ export interface PortfolioAttributes {
education: RecordAttributes[] education: RecordAttributes[]
} }
export async function get(req, res, next) { export async function get() {
let pageSource: string let pageSource: string
try { try {
pageSource = await promisify(readFile)('_pages/portfolio.md', 'utf-8') pageSource = await promisify(readFile)('_pages/portfolio.md', 'utf-8')
} catch (e) { } catch (e) {
res.statusCode = 500 return {
res.end('Error loading portfolio source file. \n' + e.toString()) status: 500,
return body: 'Error loading portfolio source file. \n' + e.toString(),
}
} }
const parsed = fm<PortfolioAttributes>(pageSource) const parsed = fm<PortfolioAttributes>(pageSource)
@ -52,6 +53,8 @@ export async function get(req, res, next) {
education, education,
} }
res.setHeader('Content-Type', 'application/json') return {
res.end(JSON.stringify(response)) status: 200,
body: response,
}
} }

View File

@ -1,9 +1,14 @@
<script context="module"> <script context="module">
export async function preload() { /**
const res = await this.fetch('portfolio.json') * @type {import('@sveltejs/kit').Load}
*/
export async function load({ fetch }) {
const res = await fetch('portfolio.json')
const content = await res.json() const content = await res.json()
return { return {
content, props: {
content,
}
} }
} }
</script> </script>

View File

@ -1,17 +0,0 @@
import sirv from 'sirv'
import polka from 'polka'
import compression from 'compression'
import * as sapper from '@sapper/server'
const { PORT, NODE_ENV } = process.env
const dev = NODE_ENV === 'development'
polka() // You can also use Express
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
sapper.middleware()
)
.listen(PORT, (err) => {
if (err) console.log('error', err)
})

View File

@ -1,10 +1,10 @@
import { timestamp, files, shell } from '@sapper/service-worker' import { timestamp, files, build } from '$service-worker'
const ASSETS = `cache${timestamp}` const ASSETS = `cache${timestamp}`
// `shell` is an array of all the files generated by the bundler, // `shell` is an array of all the files generated by the bundler,
// `files` is an array of everything in the `static` directory // `files` is an array of everything in the `static` directory
const to_cache = shell.concat(files) const to_cache = build.concat(files)
const staticAssets = new Set(to_cache) const staticAssets = new Set(to_cache)
self.addEventListener('install', (event) => { self.addEventListener('install', (event) => {

18
svelte.config.cjs Normal file
View File

@ -0,0 +1,18 @@
const adapterStatic = require('@sveltejs/adapter-static')
const sveltePreprocess = require('svelte-preprocess')
const mode = process.env.NODE_ENV
const dev = mode === 'development'
/** @type {import('@sveltejs/kit').Config} */
module.exports = {
kit: {
adapter: adapterStatic(),
},
preprocess: sveltePreprocess({
sourceMap: dev,
defaults: {
script: 'typescript',
},
}),
}

View File

@ -1,10 +1,30 @@
{ {
"extends": "@tsconfig/svelte/tsconfig.json", "compilerOptions": {
"include": ["src/**/*", "src/node_modules"], "moduleResolution": "node",
"exclude": ["node_modules/*", "__sapper__/*", "static/*"], "module": "es2020",
"compilerOptions": { "lib": ["es2020"],
"types": ["svelte", "node", "@sapper"], "target": "es2019",
"typeRoots": ["typings"], /**
"target": "ES2017" svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
} to enforce using \`import type\` instead of \`import\` for Types.
*/
"importsNotUsedAsValues": "error",
"isolatedModules": true,
"resolveJsonModule": true,
/**
To have warnings/errors of the Svelte compiler at the correct position,
enable source maps by default.
*/
"sourceMap": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"allowJs": true,
"checkJs": true,
"paths": {
"$lib/*": ["src/lib/*"]
}
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"]
} }

View File

@ -1,41 +0,0 @@
declare module '@sapper/app' {
interface Redirect {
statusCode: number
location: string
}
function goto(
href: string,
opts: { replaceState: boolean; noscroll: boolean }
): Promise<unknown>
function prefetch(
href: string
): Promise<{ redirect?: Redirect; data?: unknown }>
function prefetchRoutes(pathnames: string[]): Promise<unknown>
function start(opts: { target: Node }): Promise<unknown>
const stores: () => unknown
export { goto, prefetch, prefetchRoutes, start, stores }
}
declare module '@sapper/server' {
import { RequestHandler } from 'express'
interface MiddlewareOptions {
session?: (req: Express.Request, res: Express.Response) => unknown
ignore?: unknown
}
function middleware(opts?: MiddlewareOptions): RequestHandler
export { middleware }
}
declare module '@sapper/service-worker' {
const timestamp: number
const files: string[]
const shell: string[]
const routes: { pattern: RegExp }[]
export { timestamp, files, files as assets, shell, routes }
}