Typescript support
This commit is contained in:
parent
57ed783083
commit
dcfc3eccc2
@ -8,7 +8,7 @@
|
||||
<tr>
|
||||
<td
|
||||
rowspan="3"
|
||||
style="vertical-align: center; border-right: 1px solid #212138; width: 80px"
|
||||
style="vertical-align: center; width: 80px"
|
||||
>
|
||||
<img
|
||||
src="https://michalvanko.dev/images/m-logo.png"
|
||||
@ -19,18 +19,18 @@
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="color: #212138; font-size: 12px; padding-bottom: 4px; padding-left: 8px;"
|
||||
style="color: #212138; font-size: 12px; padding-bottom: 4px; padding-left: 4px;"
|
||||
>
|
||||
<span>Michal Vanko</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: 42436a; font-size: 11px; padding-left: 8px;">
|
||||
<td style="color: #42436a; font-size: 11px; padding-left: 4px;">
|
||||
<span>Software Architect and Consultant</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-size: 11px; padding-left: 8px;">
|
||||
<td style="font-size: 11px; padding-left: 4px;">
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://michalvanko.dev"
|
||||
|
4096
package-lock.json
generated
4096
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
46
package.json
46
package.json
@ -14,31 +14,41 @@
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.6",
|
||||
"compression": "^1.7.4",
|
||||
"date-fns": "^2.11.1",
|
||||
"feed": "^4.2.0",
|
||||
"front-matter": "^3.1.0",
|
||||
"marked": "^0.8.2",
|
||||
"@rollup/plugin-typescript": "^6.0.0",
|
||||
"date-fns": "^2.16.1",
|
||||
"feed": "^4.2.1",
|
||||
"front-matter": "^4.0.2",
|
||||
"marked": "^1.1.1",
|
||||
"polka": "^0.5.2",
|
||||
"ramda": "^0.27.0",
|
||||
"rollup-plugin-svg": "^2.0.0",
|
||||
"sirv": "^0.4.2",
|
||||
"svelte-image": "^0.1.9"
|
||||
"ramda": "^0.27.1",
|
||||
"sirv": "^1.0.6",
|
||||
"svelte-image": "^0.2.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"npm-run-all": "^4.1.5",
|
||||
"sapper": "^0.27.12",
|
||||
"svelte": "^3.20.1",
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/core": "^7.11.6",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-transform-runtime": "^7.9.0",
|
||||
"@babel/preset-env": "^7.9.0",
|
||||
"@babel/runtime": "^7.9.2",
|
||||
"rollup": "^2.3.2",
|
||||
"@babel/plugin-transform-runtime": "^7.11.5",
|
||||
"@babel/preset-env": "^7.11.5",
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"@rollup/plugin-typescript": "^6.0.0",
|
||||
"@tsconfig/svelte": "^1.0.10",
|
||||
"@types/classnames": "^2.2.10",
|
||||
"@types/ramda": "^0.27.19",
|
||||
"autoprefixer": "^10.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.0.9",
|
||||
"rollup": "^2.28.2",
|
||||
"rollup-plugin-babel": "^4.4.0",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-replace": "^2.2.0",
|
||||
"rollup-plugin-svelte": "^5.2.1",
|
||||
"rollup-plugin-terser": "^5.3.0"
|
||||
"rollup-plugin-svelte": "^6.0.1",
|
||||
"rollup-plugin-svg": "^2.0.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"sapper": "^0.28.9",
|
||||
"svelte": "^3.28.0",
|
||||
"svelte-check": "^1.0.51",
|
||||
"svelte-preprocess": "^4.3.2",
|
||||
"typescript": "^4.0.3"
|
||||
}
|
||||
}
|
||||
|
@ -7,22 +7,24 @@ import { terser } from 'rollup-plugin-terser'
|
||||
import config from 'sapper/config/rollup.js'
|
||||
import pkg from './package.json'
|
||||
import svg from 'rollup-plugin-svg'
|
||||
import image from 'svelte-image'
|
||||
// import image from 'svelte-image'
|
||||
import sveltePreprocess from 'svelte-preprocess'
|
||||
import typescript from '@rollup/plugin-typescript'
|
||||
|
||||
const mode = process.env.NODE_ENV
|
||||
const dev = mode === 'development'
|
||||
const legacy = !!process.env.SAPPER_LEGACY_BUILD
|
||||
|
||||
const onwarn = (warning, onwarn) =>
|
||||
(warning.code === 'CIRCULAR_DEPENDENCY' &&
|
||||
/[/\\]@sapper[/\\]/.test(warning.message)) ||
|
||||
(warning.code === 'MISSING_EXPORT' && /'preload'/.test(warning.message)) ||
|
||||
(warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) ||
|
||||
onwarn(warning)
|
||||
const dedupe = (importee) =>
|
||||
importee === 'svelte' || importee.startsWith('svelte/')
|
||||
|
||||
export default {
|
||||
client: {
|
||||
input: config.client.input(),
|
||||
input: config.client.input().replace(/\.js$/, ".ts"),
|
||||
output: config.client.output(),
|
||||
plugins: [
|
||||
replace({
|
||||
@ -33,9 +35,16 @@ export default {
|
||||
dev,
|
||||
hydratable: true,
|
||||
emitCss: true,
|
||||
// Disabled automatic image compression
|
||||
// preprocess: {
|
||||
// ...image(),
|
||||
// },
|
||||
preprocess: sveltePreprocess({
|
||||
sourceMap: dev,
|
||||
defaults: {
|
||||
script: 'typescript',
|
||||
},
|
||||
}),
|
||||
}),
|
||||
resolve({
|
||||
browser: true,
|
||||
@ -78,7 +87,7 @@ export default {
|
||||
},
|
||||
|
||||
server: {
|
||||
input: config.server.input(),
|
||||
input: config.server.input().server.replace(/\.js$/, ".ts"),
|
||||
output: config.server.output(),
|
||||
plugins: [
|
||||
replace({
|
||||
@ -88,6 +97,13 @@ export default {
|
||||
svelte({
|
||||
generate: 'ssr',
|
||||
dev,
|
||||
hydratable: true,
|
||||
preprocess: sveltePreprocess({
|
||||
sourceMap: dev,
|
||||
defaults: {
|
||||
script: 'typescript',
|
||||
}
|
||||
}),
|
||||
// preprocess: {
|
||||
// ...image(),
|
||||
// },
|
||||
@ -96,6 +112,7 @@ export default {
|
||||
dedupe,
|
||||
}),
|
||||
commonjs(),
|
||||
typescript({ sourceMap: dev}),
|
||||
svg(),
|
||||
],
|
||||
external: Object.keys(pkg.dependencies).concat(
|
||||
|
@ -1,7 +1,8 @@
|
||||
<script>
|
||||
<script lang="typescript">
|
||||
import { format } from 'date-fns'
|
||||
import type { PostContent } from '../../routes/blog/_content';
|
||||
|
||||
export let post
|
||||
export let post: PostContent
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -1,5 +1,7 @@
|
||||
<script>
|
||||
export let project
|
||||
<script lang="typescript">
|
||||
import type { ProjectAttributes } from "../../routes/portfolio/index.json";
|
||||
|
||||
export let project: ProjectAttributes
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import marked from 'marked'
|
||||
|
||||
export function parseField(field) {
|
||||
return item => ({
|
||||
export function parseField<T>(field: string) {
|
||||
return (item: T) => ({
|
||||
...item,
|
||||
[field]: marked(item[field]),
|
||||
})
|
@ -2,13 +2,18 @@ import { readFile } from 'fs'
|
||||
import { promisify } from 'util'
|
||||
import fm from 'front-matter'
|
||||
import { parseField } from '../../markdown/parse-markdown'
|
||||
import type { PostAttributes } from './_content'
|
||||
|
||||
export interface SinglePost {
|
||||
body: string
|
||||
}
|
||||
|
||||
export async function get(req, res, next) {
|
||||
// the `slug` parameter is available because
|
||||
// this file is called [slug].json.js
|
||||
const { slug } = req.params
|
||||
|
||||
let postSource
|
||||
let postSource: string
|
||||
try {
|
||||
postSource = await promisify(readFile)(`_posts/blog/${slug}.md`, 'utf-8')
|
||||
} catch (e) {
|
||||
@ -22,9 +27,9 @@ export async function get(req, res, next) {
|
||||
return
|
||||
}
|
||||
|
||||
const parsedPost = fm(postSource)
|
||||
const parsedPost = fm<PostAttributes>(postSource)
|
||||
|
||||
const response = parseField('body')({
|
||||
const response = parseField<SinglePost>('body')({
|
||||
...parsedPost.attributes,
|
||||
body: parsedPost.body,
|
||||
})
|
@ -64,8 +64,8 @@
|
||||
|
||||
<svelte:head>
|
||||
<title>{post.title}</title>
|
||||
<link rel="stylesheet" href="prism.css" />
|
||||
<script src="prism.js">
|
||||
<link rel="stylesheet" href="/prism.css" />
|
||||
<script src="../../../static/prism.js" defer>
|
||||
|
||||
</script>
|
||||
</svelte:head>
|
||||
|
@ -7,17 +7,32 @@ import marked from 'marked'
|
||||
|
||||
const { NODE_ENV } = process.env
|
||||
|
||||
export async function getBlogListing(tag) {
|
||||
export interface PostAttributes {
|
||||
layout: string
|
||||
title: string
|
||||
published: boolean
|
||||
date: string
|
||||
thumbnail: string
|
||||
tags: string[]
|
||||
}
|
||||
|
||||
export interface PostContent extends PostAttributes {
|
||||
preview: string
|
||||
slug: string
|
||||
published: boolean
|
||||
}
|
||||
|
||||
export async function getBlogListing(tag?: string) {
|
||||
const files = await promisify(readdir)(`_posts/blog/`, 'utf-8')
|
||||
const filteredFiles = filterDevelopmentFiles(files)
|
||||
|
||||
const contents = await Promise.all(
|
||||
filteredFiles.map(async file => {
|
||||
filteredFiles.map(async (file) => {
|
||||
const fileContent = await promisify(readFile)(
|
||||
`_posts/blog/${file}`,
|
||||
'utf-8'
|
||||
)
|
||||
const parsedAttributes = fm(fileContent)
|
||||
const parsedAttributes = fm<PostAttributes>(fileContent)
|
||||
|
||||
const lineOfTextRegExp = /^(?:\w|\[).+/gm
|
||||
const lines = parsedAttributes.body
|
||||
@ -33,23 +48,30 @@ export async function getBlogListing(tag) {
|
||||
}
|
||||
})
|
||||
)
|
||||
const filteredContents = pipe(
|
||||
const filteredContents = pipe<
|
||||
PostContent[],
|
||||
PostContent[],
|
||||
PostContent[],
|
||||
PostContent[],
|
||||
PostContent[]
|
||||
>(
|
||||
sortBy(prop('date')),
|
||||
reverse,
|
||||
filter(article => article.published),
|
||||
filter<typeof contents[0]>((article) => article.published),
|
||||
partial(filterByTag, [tag])
|
||||
)(contents)
|
||||
|
||||
return filteredContents
|
||||
}
|
||||
|
||||
function filterDevelopmentFiles(files) {
|
||||
function filterDevelopmentFiles(files: string[]) {
|
||||
return NODE_ENV !== 'production'
|
||||
? files
|
||||
: files.filter(file => !file.startsWith('dev-'))
|
||||
: files.filter((file) => !file.startsWith('dev-'))
|
||||
}
|
||||
|
||||
function filterByTag(tag, contents) {
|
||||
return tag ? contents.filter(content => content.tags.includes(tag)) : contents
|
||||
function filterByTag(tag: string | undefined, contents: PostContent[]) {
|
||||
return tag
|
||||
? contents.filter((content) => content.tags.includes(tag))
|
||||
: contents
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script context="module">
|
||||
<script context="module" lang="typescript">
|
||||
export function preload({ params, query }) {
|
||||
const blogQuery = query
|
||||
? '?' +
|
||||
@ -14,11 +14,12 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
<script lang="typescript">
|
||||
import ArticleFooter from '../../components/blog/article-footer.svelte'
|
||||
import type { PostContent } from './_content';
|
||||
|
||||
export let posts
|
||||
export let query
|
||||
export let posts: PostContent[]
|
||||
export let query
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -25,14 +25,16 @@ export async function getFeed() {
|
||||
})
|
||||
|
||||
const blogListing = await getBlogListing()
|
||||
blogListing.forEach(post => {
|
||||
blogListing.forEach((post) => {
|
||||
feed.addItem({
|
||||
title: post.title,
|
||||
id: `https://michalvanko.dev/blog/${post.slug}`,
|
||||
link: `https://michalvanko.dev/blog/${post.slug}`,
|
||||
description: post.preview,
|
||||
date: post.date,
|
||||
image: post.thumbnail ? `https://michalvanko.dev/${post.thumbnail}` : undefined,
|
||||
date: new Date(post.date),
|
||||
image: post.thumbnail
|
||||
? `https://michalvanko.dev/${post.thumbnail}`
|
||||
: undefined,
|
||||
})
|
||||
})
|
||||
return feed
|
@ -1,11 +1,10 @@
|
||||
import { getFeed } from './_feed'
|
||||
|
||||
export async function get(req, res) {
|
||||
const feed = await getFeed()
|
||||
|
||||
const feed = await getFeed()
|
||||
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/json',
|
||||
})
|
||||
res.end(feed.json1())
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { getFeed } from './_feed'
|
||||
|
||||
export async function get(req, res) {
|
||||
const feed = await getFeed()
|
||||
|
||||
const feed = await getFeed()
|
||||
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/xml',
|
||||
})
|
||||
res.end(feed.rss2())
|
||||
}
|
||||
|
@ -4,8 +4,26 @@ import fm from 'front-matter'
|
||||
import marked from 'marked'
|
||||
import { parseField } from '../../markdown/parse-markdown'
|
||||
|
||||
export interface RecordAttributes {
|
||||
name: string
|
||||
description: string
|
||||
displayed: boolean
|
||||
}
|
||||
|
||||
export interface ProjectAttributes extends RecordAttributes {
|
||||
image: string
|
||||
}
|
||||
|
||||
export interface PortfolioAttributes {
|
||||
title: string
|
||||
work_history_prelude: string
|
||||
work_history: string[]
|
||||
projects: ProjectAttributes[]
|
||||
education: RecordAttributes[]
|
||||
}
|
||||
|
||||
export async function get(req, res, next) {
|
||||
let pageSource
|
||||
let pageSource: string
|
||||
try {
|
||||
pageSource = await promisify(readFile)('_pages/portfolio.md', 'utf-8')
|
||||
} catch (e) {
|
||||
@ -14,15 +32,15 @@ export async function get(req, res, next) {
|
||||
return
|
||||
}
|
||||
|
||||
const parsed = fm(pageSource)
|
||||
const parsed = fm<PortfolioAttributes>(pageSource)
|
||||
const workHistory = (parsed.attributes.work_history || []).map(
|
||||
parseField('description')
|
||||
)
|
||||
const projects = (parsed.attributes.projects || [])
|
||||
.filter(project => project.displayed)
|
||||
.filter((project) => project.displayed)
|
||||
.map(parseField('description'))
|
||||
const education = (parsed.attributes.education || [])
|
||||
.filter(education => education.displayed)
|
||||
.filter((education) => education.displayed)
|
||||
.map(parseField('description'))
|
||||
|
||||
const response = {
|
@ -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);
|
||||
});
|
17
src/server.ts
Normal file
17
src/server.ts
Normal file
@ -0,0 +1,17 @@
|
||||
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)
|
||||
})
|
@ -28,15 +28,16 @@
|
||||
<!-- This contains the contents of the <svelte:head> component, if
|
||||
the current page has one -->
|
||||
%sapper.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>
|
||||
<body>
|
||||
<!-- The application will be rendered inside this element,
|
||||
because `app/client.js` references it -->
|
||||
<div id="sapper">%sapper.html%</div>
|
||||
|
||||
<!-- Sapper creates a <script> tag containing `app/client.js`
|
||||
and anything else it needs to hydrate the app and
|
||||
initialise the router -->
|
||||
%sapper.scripts%
|
||||
</body>
|
||||
</html>
|
||||
|
10
tsconfig.json
Normal file
10
tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
"include": ["src/**/*", "src/node_modules"],
|
||||
"exclude": ["node_modules/*", "__sapper__/*", "static/*"],
|
||||
"compilerOptions": {
|
||||
"types": ["svelte", "node", "@sapper"],
|
||||
"typeRoots": ["typings"],
|
||||
"target": "ES2017"
|
||||
}
|
||||
}
|
41
typings/@sapper/index.d.ts
vendored
Normal file
41
typings/@sapper/index.d.ts
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
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 }
|
||||
}
|
Loading…
Reference in New Issue
Block a user