@tenjuu99/blog 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,6 +29,11 @@ jobs:
29
29
  - name: Checkout
30
30
  uses: actions/checkout@master
31
31
 
32
+ - name: Use nodejs
33
+ uses: actions/setup-node@v4
34
+ with:
35
+ node-version: '22.x'
36
+
32
37
  - name: npm install
33
38
  run: npm install --omit=dev
34
39
 
package/.node-version ADDED
@@ -0,0 +1 @@
1
+ 22.7.0
package/bin/generate ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ import generate from '../lib/generate.js'
4
+ generate()
package/bin/server ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ import server from '../lib/server.js'
4
+ import { srcDir, pageDir } from '../lib/dir.js'
5
+ import { watchers, watch } from '../lib/watcher.js'
6
+ import generate from '../lib/generate.js'
7
+
8
+ watchers.push({
9
+ paths: srcDir,
10
+ watchOptions: {
11
+ ignored: pageDir
12
+ },
13
+ callback: generate
14
+ })
15
+ watchers.push({
16
+ paths: pageDir,
17
+ callback: generate,
18
+ watchOptions: {
19
+ ignoreInitial: true
20
+ },
21
+ event: ['change', 'unlink', 'add']
22
+ })
23
+ watch()
24
+ generate()
25
+
26
+ server().listen(process.env.PORT || 8000)
@@ -1,15 +1,9 @@
1
1
  "use strict"
2
2
  import fs from "node:fs/promises";
3
- import { applyCss, watchCss } from './cssGenerator.js'
4
- import {
5
- replaceIfFilter,
6
- replaceScriptFilter,
7
- replaceVariablesFilter,
8
- includeFilter
9
- } from './filter.js'
10
- import { marked } from "marked";
3
+ import applyCss from './cssGenerator.js'
4
+ import { includeFilter } from './filter.js'
11
5
  import { templateDir, cssDir } from './dir.js'
12
- import chokidar from 'chokidar'
6
+ import { watchers } from './watcher.js'
13
7
 
14
8
  let templates = {}
15
9
 
@@ -24,26 +18,9 @@ const applyTemplate = async (name = 'default.html') => {
24
18
  return templateContent
25
19
  }
26
20
 
27
- const render = async (templateName, data) => {
28
- let template = await applyTemplate(templateName)
29
- template = replaceIfFilter(template, data)
30
- template = await replaceScriptFilter(template, data)
21
+ watchers.push({
22
+ paths: [cssDir, templateDir],
23
+ callback: () => { templates = {} }
24
+ })
31
25
 
32
- let markdown = data.markdown
33
- markdown = await includeFilter(markdown)
34
- markdown = await replaceIfFilter(markdown, data)
35
- markdown = await replaceScriptFilter(markdown, data)
36
- data.markdown = data.__filetype === 'md' ? marked.parse(markdown) : markdown
37
-
38
-
39
- return replaceVariablesFilter(template, data)
40
- }
41
-
42
- const watchTemplate = () => {
43
- chokidar.watch([cssDir, templateDir]).on('change', () => {
44
- templates = {}
45
- })
46
- watchCss()
47
- }
48
-
49
- export { render, watchTemplate }
26
+ export default applyTemplate
@@ -4,7 +4,8 @@ import { minifyCss } from './minify.js'
4
4
  import { createHash } from 'crypto'
5
5
  import path from 'path'
6
6
  import { distDir as distRoot, cssDir } from './dir.js'
7
- import chokidar from 'chokidar'
7
+ import { watchers } from './watcher.js'
8
+ import { styleText } from 'node:util'
8
9
 
9
10
  let cacheBuster = {}
10
11
  const cacheBusterQuery = 't'
@@ -29,16 +30,16 @@ const cssGenerator = async (src, dist) => {
29
30
  css = minifyCss(css)
30
31
  cacheBuster[key] = createHash('md5').update(css).digest('hex')
31
32
 
32
- return await fs.mkdir(`${distRoot}${path.dirname(dist)}`, { recursive: true }).then(async () => {
33
- await fs.writeFile(`${distRoot}${dist}`, css)
34
- console.log(`generate ${src} => ${distRoot}${dist}`)
33
+ return await fs.mkdir(`${distRoot}${path.dirname(dist)}`, { recursive: true }).then(() => {
34
+ fs.writeFile(`${distRoot}${dist}`, css)
35
+ console.log(styleText('green', '[generate]'), `${src} => ${distRoot}${dist}`)
35
36
  return cacheBuster[key]
36
37
  })
37
38
  }
38
39
 
39
40
  /**
40
41
  * 次のような記述を想定している。
41
- * <link rel="stylesheet" href="${/css/layout.css:/css/base.css,/css/page.css}">
42
+ * <link rel="stylesheet" href="${/css/layout.css<<base.css,page.css}">
42
43
  * href の記述は ${dist:src} の関係になっている。
43
44
  *
44
45
  * これを
@@ -59,10 +60,9 @@ const applyCss = async (text) => {
59
60
  return text
60
61
  }
61
62
 
62
- const watchCss = () => {
63
- chokidar.watch([cssDir]).on('change', (path) => {
64
- cacheBuster = {}
65
- })
66
- }
63
+ watchers.push({
64
+ paths: cssDir,
65
+ callback: () => { cacheBuster = {} }
66
+ })
67
67
 
68
- export { applyCss, watchCss }
68
+ export default applyCss
package/lib/dir.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const rootDir = process.cwd()
2
2
  const srcDir = `${rootDir}/${process.env.SRC_DIR}`
3
3
  const distDir = `${rootDir}/${process.env.DIST_DIR}`
4
+ const pageDir = `${srcDir}/pages`
4
5
  const templateDir = `${srcDir}/template`
5
6
  const cssDir = `${srcDir}/css`
6
7
  const cacheDir = `${rootDir}/.cache`
@@ -9,6 +10,7 @@ export {
9
10
  rootDir,
10
11
  srcDir,
11
12
  distDir,
13
+ pageDir,
12
14
  templateDir,
13
15
  cssDir,
14
16
  cacheDir,
package/lib/distribute.js CHANGED
@@ -2,13 +2,14 @@
2
2
  import fs from "node:fs/promises";
3
3
  import path from 'path'
4
4
  import { minifyHtml } from './minify.js'
5
- import { render, watchTemplate } from './applyTemplate.js'
5
+ import render from './render.js'
6
+ import { styleText } from 'node:util'
6
7
 
7
- const distribute = async (data, srcDir, distDir) => {
8
- if (data['__deleted']) {
9
- for (const i in data['__deleted']) {
10
- console.log(`unlink ${distDir}${data['__deleted'][i].__output}`)
11
- fs.unlink(`${distDir}${data['__deleted'][i].__output}`)
8
+ const distribute = async (data, deleted, srcDir, distDir) => {
9
+ if (deleted) {
10
+ for (const obj of deleted) {
11
+ console.log(styleText('red', '[unlink]'), `${distDir}${obj.__output}`)
12
+ fs.unlink(`${distDir}${obj.__output}`)
12
13
  }
13
14
  delete data['__deleted']
14
15
  }
@@ -18,7 +19,7 @@ const distribute = async (data, srcDir, distDir) => {
18
19
  let writeTo = `${distDir}${data[name].__output}`
19
20
  fs.mkdir(path.dirname(writeTo), { recursive: true}).then(() => {
20
21
  fs.writeFile(writeTo, minifyHtml(rendered))
21
- console.log(`generate ${writeTo}`)
22
+ console.log(styleText('green', '[generate]'), writeTo)
22
23
  })
23
24
  }
24
25
  const distributeRaw = process.env.DISTRIBUTE_RAW.split(',')
@@ -27,9 +28,10 @@ const distribute = async (data, srcDir, distDir) => {
27
28
  await fs.stat(`${distDir}/${copyDir}/`).catch(async err => await fs.mkdir(`${distDir}/${copyDir}/`))
28
29
  files.forEach(file => {
29
30
  fs.copyFile(`${srcDir}/${copyDir}/${file}`, `${distDir}/${copyDir}/${file}`)
31
+ console.log(styleText('green', '[copy]'), `${srcDir}/${copyDir}/${file} => ${distDir}/${copyDir}/${file}`)
30
32
  })
31
33
  })
32
34
  })
33
35
  }
34
36
 
35
- export { distribute, watchTemplate }
37
+ export default distribute
package/lib/generate.js CHANGED
@@ -1,15 +1,16 @@
1
1
  "use strict"
2
- import { distribute } from './distribute.js'
3
- import { indexing } from './indexer.js'
2
+ import distribute from './distribute.js'
3
+ import { indexing, allData, deleted } from './indexer.js'
4
4
  import { srcDir, distDir } from './dir.js'
5
+ import { styleText } from 'node:util'
5
6
 
6
7
  const generate = async () => {
7
8
  const start = performance.now()
8
- const data = await indexing(srcDir + '/pages/')
9
+ await indexing()
9
10
 
10
- await distribute(data, srcDir, distDir)
11
+ await distribute(allData, deleted, srcDir, distDir)
11
12
  const end = performance.now()
12
- console.log('build: ' + (end - start) + "ms")
13
+ console.log(styleText('blue', '[build: ' + (end - start) + "ms]"))
13
14
  }
14
15
 
15
16
  export default generate
package/lib/indexer.js CHANGED
@@ -1,82 +1,33 @@
1
1
  "use strict"
2
2
  import fs from "node:fs/promises";
3
- import { cacheDir } from './dir.js'
4
-
5
- const parseMetaData = (markdown, filename) => {
6
- const regexp = new RegExp(/^(<!|-)--(?<variables>[\s\S]*?)--(-|>)/)
7
- const matched = markdown.match(regexp)
8
- const markdownReplaced = markdown.replace(regexp, '')
9
- const metaDataDefault = {
10
- name: filename,
11
- title: filename,
12
- url: `/${filename}`,
13
- description: '',
14
- og_description: '',
15
- published: '1970-01-01',
16
- index: true,
17
- noindex: false,
18
- lang: 'ja',
19
- site_name: process.env.SITE_NAME,
20
- url_base: process.env.URL_BASE,
21
- gtag_id: process.env.GTAG_ID,
22
- markdown: markdownReplaced,
23
- relative_path: process.env.RELATIVE_PATH || '',
24
- template: 'default.html',
25
- ext: 'html',
26
- __output: `/${filename}.html`
27
- }
28
- if (!matched) {
29
- return metaDataDefault
30
- }
31
- const metaData = Object.fromEntries(
32
- matched.groups.variables.split('\n').filter(line => line.includes(':'))
33
- .map(line => {
34
- const index = line.indexOf(':')
35
- const key = line.slice(0, index)
36
- let value = line.slice(index + 1).trim()
37
- if (value === 'true' || value === 'false') {
38
- value = JSON.parse(value)
39
- }
40
- return [key, value]
41
- })
42
- )
43
- const metaDataMerged = Object.assign(metaDataDefault, metaData)
44
- if (!metaDataMerged.description) {
45
- metaDataMerged.description = markdownReplaced.replace(/(<([^>]+)>)/gi, '').slice(0, 200).replaceAll("\n", '') + '...'
46
- }
47
- if (!metaDataMerged.og_description) {
48
- metaDataMerged.og_description = metaDataMerged.og_description
49
- }
50
- metaDataMerged['__output'] = filename === 'index' ? '/index.html' : `${metaDataMerged.url}.${metaDataMerged.ext}`
51
-
52
- return metaDataMerged
53
- }
3
+ import { pageDir, cacheDir } from './dir.js'
4
+ import makePageData from './pageData.js'
54
5
 
55
6
  const indexFile = `${cacheDir}/index.json`
56
7
 
57
- const newIndex = []
58
- const allData = {}
8
+ let allData = {}
9
+ let deleted = []
59
10
 
60
- const indexing = async (targetDir) => {
61
- const targets = await fs.readdir(targetDir).then(files => {
62
- return files.filter(fileName => fileName.match('\.(md|html)$'))
11
+ const indexing = async () => {
12
+ const oldIndex = await fs.readFile(indexFile, 'utf8').then(text => JSON.parse(text)).catch(error => [])
13
+
14
+ const newIndex = []
15
+ allData = {}
16
+ deleted = []
17
+ await fs.readdir(pageDir).then(files => {
18
+ files
19
+ .filter(fileName => fileName.match('\.(md|html)$'))
20
+ .forEach(file => {
21
+ const metaData = makePageData(file)
22
+ allData[metaData.name] = metaData
23
+ const { name, url, __output } = metaData
24
+ newIndex.push({ name, url, __output })
25
+ })
63
26
  })
64
- for (const file of targets) {
65
- const markdownText = await fs.readFile(`${targetDir}/${file}`, 'utf8')
66
- const [target, ext] = file.split('.')
67
- const metaData = parseMetaData(markdownText, target)
68
- metaData.__filetype = ext
69
- allData[target] = metaData
70
- let { name, title, index, url, published, modified, __output } = metaData
71
- newIndex.push({ name, title, index, url, published, modified, __output })
72
- }
73
- await fs.writeFile(indexFile, JSON.stringify(newIndex))
27
+ fs.writeFile(indexFile, JSON.stringify(newIndex))
74
28
 
75
29
  // 旧インデックスから差分を計算して削除対象をピックアップする
76
- const oldIndex = await fs.readFile(indexFile, 'utf8').then(text => JSON.parse(text)).catch(error => [])
77
- const deleted = oldIndex.filter(oi => !newIndex.map(ni => ni.__output).includes(oi.__output))
78
- allData['__deleted'] = deleted
79
- return allData
30
+ deleted = oldIndex.filter(oi => !newIndex.map(ni => ni.__output).includes(oi.__output))
80
31
  }
81
32
 
82
- export { indexing, allData }
33
+ export { indexing, allData, deleted }
@@ -0,0 +1,66 @@
1
+ "use strict"
2
+ import fs from "node:fs";
3
+ import { pageDir } from './dir.js'
4
+
5
+ const load = (path) => {
6
+ return fs.readFileSync(path, 'utf8')
7
+ }
8
+
9
+ const makePageData = (filename) => {
10
+ const content = load(`${pageDir}/${filename}`)
11
+ const [name, ext] = filename.split('.')
12
+ return parse(content, name, ext)
13
+ }
14
+
15
+ const parse = (content, name, ext) => {
16
+ const regexp = new RegExp(/^(<!|-)--(?<variables>[\s\S]*?)--(-|>)/)
17
+ const matched = content.match(regexp)
18
+ const markdownReplaced = content.replace(regexp, '')
19
+ const metaDataDefault = {
20
+ name,
21
+ title: name,
22
+ url: `/${name}`,
23
+ description: '',
24
+ og_description: '',
25
+ published: '1970-01-01',
26
+ index: true,
27
+ noindex: false,
28
+ lang: 'ja',
29
+ site_name: process.env.SITE_NAME,
30
+ url_base: process.env.URL_BASE,
31
+ gtag_id: process.env.GTAG_ID,
32
+ markdown: markdownReplaced,
33
+ relative_path: process.env.RELATIVE_PATH || '',
34
+ template: 'default.html',
35
+ ext: 'html',
36
+ __output: `/${name}.html`,
37
+ __filetype: ext,
38
+ }
39
+ if (!matched) {
40
+ return metaDataDefault
41
+ }
42
+ const metaData = Object.fromEntries(
43
+ matched.groups.variables.split('\n').filter(line => line.includes(':'))
44
+ .map(line => {
45
+ const index = line.indexOf(':')
46
+ const key = line.slice(0, index)
47
+ let value = line.slice(index + 1).trim()
48
+ if (value === 'true' || value === 'false') {
49
+ value = JSON.parse(value)
50
+ }
51
+ return [key, value]
52
+ })
53
+ )
54
+ const metaDataMerged = Object.assign(metaDataDefault, metaData)
55
+ if (!metaDataMerged.description) {
56
+ metaDataMerged.description = markdownReplaced.replace(/(<([^>]+)>)/gi, '').slice(0, 200).replaceAll("\n", '') + '...'
57
+ }
58
+ if (!metaDataMerged.og_description) {
59
+ metaDataMerged.og_description = metaDataMerged.og_description
60
+ }
61
+ metaDataMerged['__output'] = name === 'index' ? '/index.html' : `${metaDataMerged.url}.${metaDataMerged.ext}`
62
+
63
+ return metaDataMerged
64
+ }
65
+
66
+ export default makePageData
package/lib/render.js ADDED
@@ -0,0 +1,24 @@
1
+ import {
2
+ replaceIfFilter,
3
+ replaceScriptFilter,
4
+ replaceVariablesFilter,
5
+ includeFilter
6
+ } from './filter.js'
7
+ import { marked } from "marked";
8
+ import applyTemplate from './applyTemplate.js'
9
+
10
+ const render = async (templateName, data) => {
11
+ let template = await applyTemplate(templateName)
12
+ template = replaceIfFilter(template, data)
13
+ template = await replaceScriptFilter(template, data)
14
+
15
+ let markdown = data.markdown
16
+ markdown = await includeFilter(markdown)
17
+ markdown = await replaceIfFilter(markdown, data)
18
+ markdown = await replaceScriptFilter(markdown, data)
19
+ data.markdown = data.__filetype === 'md' ? marked.parse(markdown) : markdown
20
+
21
+ return replaceVariablesFilter(template, data)
22
+ }
23
+
24
+ export default render
package/lib/server.js ADDED
@@ -0,0 +1,64 @@
1
+ import http from 'http'
2
+ import url from 'url'
3
+ import fs from 'node:fs'
4
+ import { distDir } from './dir.js'
5
+ import { styleText } from 'node:util'
6
+
7
+ const contentType = (ext) => {
8
+ switch (ext) {
9
+ case 'html':
10
+ case 'css':
11
+ return `text/${ext}`
12
+ case 'js':
13
+ return 'text/javascript'
14
+ case 'jpeg':
15
+ case 'png':
16
+ case 'webp':
17
+ case 'avif':
18
+ return `image/${ext}`
19
+ case 'jpg':
20
+ return 'image/jpeg'
21
+ case 'svg':
22
+ return 'image/svg+xml'
23
+ case 'xml':
24
+ case 'json':
25
+ return `application/${ext}`
26
+ case 'rdf':
27
+ return 'application/rdf+xml.rdf'
28
+ default:
29
+ return 'application/octet-stream'
30
+ }
31
+ }
32
+
33
+ const server = () => {
34
+ return http.createServer((request, response) => {
35
+ const url = new URL(`http://${request.headers.host}${request.url}`)
36
+ let path = url.pathname === '/' ? '/index.html' : decodeURIComponent(url.pathname)
37
+ if (!path.includes('.')) {
38
+ path += '.html'
39
+ }
40
+ if (!fs.existsSync(`${distDir}${path}`)) {
41
+ console.log(styleText('red', `[${request.method}] 404`), request.url)
42
+ const errorContent = fs.readFileSync(`${distDir}/404.html`)
43
+ response.writeHead(404)
44
+ response.end(errorContent)
45
+ return
46
+ }
47
+ try {
48
+ const content = fs.readFileSync(`${distDir}${path}`, 'binary')
49
+
50
+ const ext = path.split('.')[1]
51
+ console.log(styleText('green', `[${request.method}] 200`), request.url)
52
+ response.writeHead(200, { 'Content-Type': `${contentType(ext)}; charset=utf-8` })
53
+ response.end(content, 'binary')
54
+ } catch (e) {
55
+ console.log(e)
56
+ console.log(styleText('red', `[${request.method}] 500`), request.url)
57
+ const errorContent = fs.readFileSync(`${distDir}/404.html`)
58
+ response.writeHead(500)
59
+ response.end(errorContent)
60
+ }
61
+ })
62
+ }
63
+
64
+ export default server
package/lib/watcher.js ADDED
@@ -0,0 +1,28 @@
1
+ import chokidar from 'chokidar'
2
+
3
+ const container = []
4
+
5
+ const watchers = {
6
+ push({ paths, event = 'change', callback, watchOptions }) {
7
+ if (!paths || !callback || typeof callback !== 'function') {
8
+ throw new Error('Invalid object type for watcher.')
9
+ }
10
+ container.push({ paths, event, callback, watchOptions })
11
+ }
12
+ }
13
+
14
+ const watch = () => {
15
+ container.forEach((watcher) => {
16
+ const { paths, event, callback, watchOptions } = watcher
17
+ const cwatcher = chokidar.watch(paths, watchOptions)
18
+ if (Array.isArray(event)) {
19
+ event.forEach(e => cwatcher.on(e, callback))
20
+ } else if (typeof event === 'string') {
21
+ cwatcher.on(event, callback)
22
+ } else {
23
+ throw new Error('Invalid event for watcher.')
24
+ }
25
+ })
26
+ }
27
+
28
+ export { watchers , watch }
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@tenjuu99/blog",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "blog template",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "serve": "eval $(cat .env | tr \"\n\" \" \") node server.js",
8
- "generate": "eval $(cat .env | tr \"\n\" \" \") node generate.js",
7
+ "dev": "eval $(cat .env | tr \"\n\" \" \") node bin/server",
8
+ "generate": "eval $(cat .env | tr \"\n\" \" \") node bin/generate",
9
9
  "test": "echo \"Error: no test specified\" && exit 1"
10
10
  },
11
11
  "bin": {
12
- "generate": "generate.js",
13
- "server": "server.js"
12
+ "generate": "bin/generate",
13
+ "server": "bin/server"
14
14
  },
15
15
  "author": "AmashigeSeiji",
16
16
  "repository": {
@@ -22,5 +22,8 @@
22
22
  "chokidar": "^3.6.0",
23
23
  "marked": "^13.x"
24
24
  },
25
- "type": "module"
25
+ "type": "module",
26
+ "engines": {
27
+ "node": ">=21.7"
28
+ }
26
29
  }
package/performance.js CHANGED
@@ -1,22 +1,22 @@
1
1
  "use strict"
2
2
  import distribute from './lib/distribute.js'
3
- import { indexing } from './lib/indexer.js'
3
+ import { indexing, allData, deleted } from './lib/indexer.js'
4
4
  import { srcDir, distDir } from './lib/dir.js'
5
5
 
6
6
  process.env.FORCE_BUILD = true
7
- const execute = async () => {
7
+ const doBuild = async () => {
8
8
  const start = performance.now()
9
- const data = await indexing(srcDir)
10
- await distribute(data, srcDir, distDir)
9
+ await indexing()
10
+ await distribute(allData, deleted, srcDir, distDir)
11
11
  const end = performance.now()
12
12
  return end - start
13
13
  }
14
14
  const times = 100
15
15
  let executed = 0
16
- //for (let i = 0; i < times; i++) {
17
- //console.log(await executed())
18
- const buildTime = await execute()
19
- //executed += (buildTime)
16
+ for (let i = 0; i < times; i++) {
17
+ // console.log(await executed())
18
+ const buildTime = await doBuild()
19
+ executed += (buildTime)
20
20
  console.log(buildTime)
21
- //}
22
- //console.log('build average: 100 times: ' + (executed/times) + "ms")
21
+ }
22
+ console.log('build average: 100 times: ' + (executed/times) + "ms")
File without changes
File without changes
File without changes
File without changes
File without changes
package/generate.js DELETED
@@ -1,2 +0,0 @@
1
- import generate from './lib/generate.js'
2
- generate()
package/server.js DELETED
@@ -1,56 +0,0 @@
1
- import http from 'http'
2
- import url from 'url'
3
- import fs from 'node:fs/promises'
4
- import { srcDir, distDir } from './lib/dir.js'
5
- import chokidar from 'chokidar'
6
- import generate from './lib/generate.js'
7
- import { watchTemplate } from './lib/applyTemplate.js'
8
-
9
- chokidar.watch(srcDir).on('change', (event, path) => {
10
- generate()
11
- })
12
- watchTemplate()
13
- generate()
14
- const contentType = (ext) => {
15
- switch (ext) {
16
- case 'html':
17
- return 'text/html'
18
- case 'css':
19
- return 'text/css'
20
- case 'js':
21
- case 'javascript':
22
- return 'text/javascript'
23
- case 'json':
24
- return 'application/json'
25
- case 'jpg':
26
- case 'jpeg':
27
- return 'image/jpeg'
28
- case 'svg':
29
- return 'image/svg+xml'
30
- case 'xml':
31
- return 'application/xml'
32
- case 'rdf':
33
- return 'application/rdf+xml.rdf'
34
- default:
35
- return 'application/octet-stream'
36
- }
37
- }
38
-
39
- http.createServer((request, response) => {
40
- console.log(request.method, request.url)
41
- const url = new URL(`http://${request.headers.host}${request.url}`)
42
- let path = url.pathname === '/' ? '/index.html' : decodeURIComponent(url.pathname)
43
- if (!path.includes('.')) {
44
- path += '.html'
45
- }
46
- fs.readFile(`${distDir}${path}`, 'binary').catch(async (error) => {
47
- const errorContent = await fs.readFile(`${distDir}/404.html`)
48
- console.log(error)
49
- response.writeHead(404)
50
- response.end(errorContent)
51
- }).then(file => {
52
- const ext = path.split('.')[1]
53
- response.writeHead(200, { 'Content-Type': `${contentType(ext)}; charset=utf-8` })
54
- response.end(file, 'binary')
55
- })
56
- }).listen(process.env.PORT || 8000)