packaton 0.0.3 → 0.0.7
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.
- package/README.md +3 -3
- package/TODO.md +1 -0
- package/index.d.ts +2 -1
- package/index.js +5 -5
- package/package.json +1 -1
- package/src/app-dev.js +2 -2
- package/src/app-prod.js +28 -38
- package/src/app.js +1 -1
- package/src/config.js +7 -6
- package/src/{WatcherDevClient.js → plugins-dev/WatcherDevClient.js} +1 -1
- package/src/{HtmlCompiler.js → plugins-prod/HtmlCompiler.js} +5 -3
- package/src/plugins-prod/cspNginxMapPlugin.js +9 -0
- package/src/{media-remaper.js → plugins-prod/media-remaper.js} +10 -6
- package/src/plugins-prod/netiflyAndCloudflareHeadersPlugin.js +19 -0
- package/src/{reportSizes.js → plugins-prod/reportSizesPlugin.js} +5 -2
- package/src/plugins-prod/sitemapPlugin.js +20 -0
- package/src/{app-router.js → router.js} +20 -20
- /package/src/{openInBrowser.js → plugins-dev/openInBrowser.js} +0 -0
- /package/src/{watcherDev.js → plugins-dev/watcherDev.js} +0 -0
- /package/src/{HtmlCompiler.test.js → plugins-prod/HtmlCompiler.test.js} +0 -0
- /package/src/{media-remaper.test.js → plugins-prod/media-remaper.test.js} +0 -0
- /package/src/{minifyCSS.js → plugins-prod/minifyCSS.js} +0 -0
- /package/src/{minifyCSS.test.js → plugins-prod/minifyCSS.test.js} +0 -0
- /package/src/{minifyHTML.js → plugins-prod/minifyHTML.js} +0 -0
- /package/src/{minifyHTML.test.js → plugins-prod/minifyHTML.test.js} +0 -0
- /package/src/{minifyJS.js → plugins-prod/minifyJS.js} +0 -0
- /package/src/{fs-utils.js → utils/fs-utils.js} +0 -0
- /package/src/{fs-utils.test.js → utils/fs-utils.test.js} +0 -0
- /package/src/{http-response.js → utils/http-response.js} +0 -0
- /package/src/{mimes.js → utils/mimes.js} +0 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ computes their corresponding CSP nonce and injects it as well.
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
## Images and Videos (immutable naming)
|
|
15
|
-
For long-term caching, [media-remaper.js](src/media-remaper.js) appends a SHA-1 hash
|
|
15
|
+
For long-term caching, [media-remaper.js](src/plugins-prod/media-remaper.js) appends a SHA-1 hash
|
|
16
16
|
to the filenames and takes care of rewriting their `src` in HTML (**only in HTML**).
|
|
17
17
|
|
|
18
18
|
If you want to use media files in CSS, create a similar function to
|
|
@@ -45,6 +45,6 @@ To avoid minifying, you can pass `a=>a`
|
|
|
45
45
|
- can't write inline scripts or css (all must be in an external file, packaton inlines them)
|
|
46
46
|
- must have an index
|
|
47
47
|
- Ignored Documents start with `_`, so you can't have routes that begin with _
|
|
48
|
-
- Non-Documents and Files outside
|
|
48
|
+
- Non-Documents and Files outside /static are not automatically copied over,
|
|
49
49
|
you need to specify them.
|
|
50
|
-
-
|
|
50
|
+
- static/media only files at the top level get hashed-named. But files within subdirs are not (by design).
|
package/TODO.md
CHANGED
package/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export interface Config {
|
|
2
2
|
mode?: 'development' | 'production';
|
|
3
3
|
srcPath?: string
|
|
4
|
+
staticDir?: string
|
|
4
5
|
ignore?: RegExp
|
|
5
6
|
|
|
6
7
|
|
|
@@ -11,7 +12,7 @@ export interface Config {
|
|
|
11
12
|
hotReload?: boolean // For UI dev purposes only
|
|
12
13
|
|
|
13
14
|
// Production
|
|
14
|
-
|
|
15
|
+
outputDir?: string
|
|
15
16
|
outputExtension?: string
|
|
16
17
|
minifyJS?: (js: string) => Promise<string>
|
|
17
18
|
minifyCSS?: (css: string) => Promise<string>
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { Packaton } from './src/app.js'
|
|
2
|
-
export { HtmlCompiler } from './src/HtmlCompiler.js'
|
|
3
|
-
export { minifyHTML } from './src/minifyHTML.js'
|
|
4
|
-
export { minifyCSS } from './src/minifyCSS.js'
|
|
5
|
-
export { minifyJS } from './src/minifyJS.js'
|
|
6
|
-
export {
|
|
2
|
+
export { HtmlCompiler } from './src/plugins-prod/HtmlCompiler.js'
|
|
3
|
+
export { minifyHTML } from './src/plugins-prod/minifyHTML.js'
|
|
4
|
+
export { minifyCSS } from './src/plugins-prod/minifyCSS.js'
|
|
5
|
+
export { minifyJS } from './src/plugins-prod/minifyJS.js'
|
|
6
|
+
export { reportSizesPlugin } from './src/plugins-prod/reportSizesPlugin.js'
|
package/package.json
CHANGED
package/src/app-dev.js
CHANGED
package/src/app-prod.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import http from 'node:http'
|
|
2
1
|
import { cpSync } from 'node:fs'
|
|
2
|
+
import { createServer } from 'node:http'
|
|
3
3
|
import { basename, join, dirname } from 'node:path'
|
|
4
4
|
|
|
5
5
|
import { docs } from './app.js'
|
|
6
|
-
import { router } from './
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
6
|
+
import { router } from './router.js'
|
|
7
|
+
import { HtmlCompiler } from './plugins-prod/HtmlCompiler.js'
|
|
8
|
+
import { sitemapPlugin } from './plugins-prod/sitemapPlugin.js'
|
|
9
|
+
import { reportSizesPlugin } from './plugins-prod/reportSizesPlugin.js'
|
|
10
|
+
import { write, removeDir, } from './utils/fs-utils.js'
|
|
11
|
+
import { cspNginxMapPlugin } from './plugins-prod/cspNginxMapPlugin.js'
|
|
12
|
+
import { renameMediaWithHashes } from './plugins-prod/media-remaper.js'
|
|
13
|
+
import { netiflyAndCloudflareHeadersPlugin } from './plugins-prod/netiflyAndCloudflareHeadersPlugin.js'
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
/**
|
|
@@ -16,24 +19,20 @@ import { renameMediaWithHashes } from './media-remaper.js'
|
|
|
16
19
|
*/
|
|
17
20
|
export async function buildStaticPages(config) {
|
|
18
21
|
return new Promise((resolve, reject) => {
|
|
22
|
+
const MEDIA_REL_URL = join(config.staticDir, 'media')
|
|
23
|
+
|
|
19
24
|
const pSource = config.srcPath
|
|
20
|
-
const pDist = config.
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const pDistCspNginxMap = join(pDist, '.csp-map.nginx')
|
|
24
|
-
const pSizesReport = 'packed-sizes.json'
|
|
25
|
+
const pDist = config.outputDir
|
|
26
|
+
const pDistStatic = join(config.outputDir, config.staticDir)
|
|
27
|
+
const pDistMedia = join(pDist, MEDIA_REL_URL)
|
|
25
28
|
|
|
26
|
-
const server =
|
|
27
|
-
server.
|
|
29
|
+
const server = createServer(router(config))
|
|
30
|
+
server.on('error', reject)
|
|
31
|
+
server.listen(0, '127.0.0.1', async () => {
|
|
28
32
|
docs.init(config.srcPath, config.ignore)
|
|
29
33
|
try {
|
|
30
|
-
if (error) {
|
|
31
|
-
reject(error)
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
34
|
removeDir(pDist)
|
|
36
|
-
cpSync(join(pSource,
|
|
35
|
+
cpSync(join(pSource, config.staticDir), pDistStatic, {
|
|
37
36
|
recursive: true,
|
|
38
37
|
dereference: true,
|
|
39
38
|
filter(src) {
|
|
@@ -48,7 +47,12 @@ export async function buildStaticPages(config) {
|
|
|
48
47
|
|
|
49
48
|
const cspByRoute = []
|
|
50
49
|
for (const [route, rawHtml] of pages) {
|
|
51
|
-
const doc = new HtmlCompiler(rawHtml, join(pSource, dirname(route)),
|
|
50
|
+
const doc = new HtmlCompiler(rawHtml, join(pSource, dirname(route)), {
|
|
51
|
+
minifyJS: config.minifyJS,
|
|
52
|
+
minifyCSS: config.minifyCSS,
|
|
53
|
+
minifyHTML: config.minifyHTML,
|
|
54
|
+
mediaRelUrl: MEDIA_REL_URL
|
|
55
|
+
})
|
|
52
56
|
await doc.minifyHTML()
|
|
53
57
|
doc.remapMedia(mediaHashes)
|
|
54
58
|
// TODO remap media in css and js
|
|
@@ -58,24 +62,10 @@ export async function buildStaticPages(config) {
|
|
|
58
62
|
cspByRoute.push([route, doc.csp()])
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
.join('\n'))
|
|
66
|
-
|
|
67
|
-
if (config.cspMapEnabled) {
|
|
68
|
-
write(pDistCspNginxMap, cspByRoute.map(([route, csp]) =>
|
|
69
|
-
`${route} "${csp}";`).join('\n'))
|
|
70
|
-
|
|
71
|
-
// cloudflare
|
|
72
|
-
write(pDistMedia + '/_headers', cspByRoute.map(([route, csp]) => {
|
|
73
|
-
const r = route === '/index' ? '/' : route
|
|
74
|
-
return `${r}\n Content-Security-Policy: ${csp}`
|
|
75
|
-
}).join('\n'))
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
reportSizes(pSizesReport, pDist, docs.routes.map(f => f + config.outputExtension))
|
|
65
|
+
sitemapPlugin(config, docs.routes)
|
|
66
|
+
reportSizesPlugin(config, docs.routes)
|
|
67
|
+
cspNginxMapPlugin(config, cspByRoute)
|
|
68
|
+
netiflyAndCloudflareHeadersPlugin(config, cspByRoute, MEDIA_REL_URL)
|
|
79
69
|
}
|
|
80
70
|
catch (error) {
|
|
81
71
|
reject(error)
|
package/src/app.js
CHANGED
|
@@ -2,7 +2,7 @@ import { readdirSync } from 'node:fs'
|
|
|
2
2
|
import { basename, join, dirname } from 'node:path'
|
|
3
3
|
|
|
4
4
|
import { setup } from './config.js'
|
|
5
|
-
import { isFile } from './fs-utils.js'
|
|
5
|
+
import { isFile } from './utils/fs-utils.js'
|
|
6
6
|
import { devStaticPages } from './app-dev.js'
|
|
7
7
|
import { buildStaticPages } from './app-prod.js'
|
|
8
8
|
|
package/src/config.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { resolve } from 'node:path'
|
|
2
2
|
|
|
3
|
-
import { isDirectory } from './fs-utils.js'
|
|
4
|
-
import { openInBrowser } from './openInBrowser.js'
|
|
3
|
+
import { isDirectory } from './utils/fs-utils.js'
|
|
4
|
+
import { openInBrowser } from './plugins-dev/openInBrowser.js'
|
|
5
5
|
|
|
6
|
-
import { minifyJS } from './minifyJS.js'
|
|
7
|
-
import { minifyCSS } from './minifyCSS.js'
|
|
8
|
-
import { minifyHTML } from './minifyHTML.js'
|
|
6
|
+
import { minifyJS } from './plugins-prod/minifyJS.js'
|
|
7
|
+
import { minifyCSS } from './plugins-prod/minifyCSS.js'
|
|
8
|
+
import { minifyHTML } from './plugins-prod/minifyHTML.js'
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
/** @type {{
|
|
@@ -17,6 +17,7 @@ import { minifyHTML } from './minifyHTML.js'
|
|
|
17
17
|
const schema = {
|
|
18
18
|
mode: ['development', val => ['development', 'production'].includes(val)],
|
|
19
19
|
srcPath: [resolve('src'), isDirectory],
|
|
20
|
+
staticDir: ['static', optional(String)],
|
|
20
21
|
ignore: [/^_/, optional(RegExp)],
|
|
21
22
|
|
|
22
23
|
// Development
|
|
@@ -27,7 +28,7 @@ const schema = {
|
|
|
27
28
|
|
|
28
29
|
// Production
|
|
29
30
|
outputExtension: ['.html', optional(String)],
|
|
30
|
-
|
|
31
|
+
outputDir: ['dist', optional(String)], // TODO resolve
|
|
31
32
|
minifyJS: [minifyJS, optional(Function)],
|
|
32
33
|
minifyCSS: [minifyCSS, optional(Function)],
|
|
33
34
|
minifyHTML: [minifyHTML, optional(Function)],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { join } from 'node:path'
|
|
2
2
|
import { createHash } from 'node:crypto'
|
|
3
3
|
|
|
4
|
-
import { read } from '
|
|
4
|
+
import { read } from '../utils/fs-utils.js'
|
|
5
5
|
import { remapMediaInHTML } from './media-remaper.js'
|
|
6
6
|
|
|
7
7
|
|
|
@@ -10,6 +10,7 @@ export class HtmlCompiler {
|
|
|
10
10
|
pSource = ''
|
|
11
11
|
css = ''
|
|
12
12
|
scriptsJs = ''
|
|
13
|
+
mediaRelUrl = ''
|
|
13
14
|
scriptsNonJs = ''
|
|
14
15
|
externalScripts = []
|
|
15
16
|
externalCSS = []
|
|
@@ -17,12 +18,13 @@ export class HtmlCompiler {
|
|
|
17
18
|
#minifyCSS = a => a
|
|
18
19
|
#minifyHTML = a => a
|
|
19
20
|
|
|
20
|
-
constructor(html, pSource = '', { minifyJS, minifyCSS, minifyHTML }) {
|
|
21
|
+
constructor(html, pSource = '', { minifyJS, minifyCSS, minifyHTML, mediaRelUrl }) {
|
|
21
22
|
this.html = html
|
|
22
23
|
this.pSource = pSource
|
|
23
24
|
this.#minifyJS = minifyJS
|
|
24
25
|
this.#minifyCSS = minifyCSS
|
|
25
26
|
this.#minifyHTML = minifyHTML
|
|
27
|
+
this.mediaRelUrl = mediaRelUrl
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
// Removes comments and format multi-line tags (needed for `removeLineContaining`)
|
|
@@ -31,7 +33,7 @@ export class HtmlCompiler {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
remapMedia(mediaHashes) {
|
|
34
|
-
this.html = remapMediaInHTML(mediaHashes, this.html)
|
|
36
|
+
this.html = remapMediaInHTML(mediaHashes, this.html, this.mediaRelUrl)
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
async inlineMinifiedCSS() {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { write } from '../utils/fs-utils.js'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export function cspNginxMapPlugin(config, cspByRoute) {
|
|
6
|
+
const out = join(config.outputDir, '.csp-map.nginx')
|
|
7
|
+
write(out, cspByRoute.map(([route, csp]) =>
|
|
8
|
+
`${route} "${csp}";`).join('\n'))
|
|
9
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join, parse } from 'node:path'
|
|
2
2
|
import { renameSync } from 'node:fs'
|
|
3
|
-
import { sha1, listFiles } from '
|
|
3
|
+
import { sha1, listFiles } from '../utils/fs-utils.js'
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -21,7 +21,6 @@ export async function renameMediaWithHashes(dir) {
|
|
|
21
21
|
return mediaHashes
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
// TODO if media is made configurable, we'd need to espace the regex for example .media -> \.media
|
|
25
24
|
// Having one dir is kinda nice for nginx headers, but that's not an excuse nor solves nested dirs with same filename
|
|
26
25
|
|
|
27
26
|
// TODO for (b of base) find and replace base with new hash
|
|
@@ -35,17 +34,22 @@ export async function renameMediaWithHashes(dir) {
|
|
|
35
34
|
* If you want to handle CSS files, edit the regex so
|
|
36
35
|
* instead of checking `="` (e.g. src="img.png") also checks for `url(`
|
|
37
36
|
**/
|
|
38
|
-
export function remapMediaInHTML(mediaHashes, html) {
|
|
39
|
-
const
|
|
40
|
-
const
|
|
37
|
+
export function remapMediaInHTML(mediaHashes, html, mediaRelUrl) {
|
|
38
|
+
const mURL = escapeForRegex(mediaRelUrl)
|
|
39
|
+
const reFindMedia = new RegExp(`(="${mURL}/.*?)"`, 'g')
|
|
40
|
+
const reFindMediaKey = new RegExp(`="${mURL}/`)
|
|
41
41
|
|
|
42
42
|
for (const [, url] of html.matchAll(reFindMedia)) {
|
|
43
43
|
const hashedName = mediaHashes.get(url.replace(reFindMediaKey, ''))
|
|
44
44
|
if (!hashedName)
|
|
45
45
|
throw `ERROR: Missing ${url}\n`
|
|
46
|
-
html = html.replace(url, `="
|
|
46
|
+
html = html.replace(url, `="${mediaRelUrl}/${hashedName}`)
|
|
47
47
|
}
|
|
48
48
|
return html
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
function escapeForRegex(literal) {
|
|
53
|
+
return literal.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
54
|
+
}
|
|
55
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import { write } from '../utils/fs-utils.js'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export function netiflyAndCloudflareHeadersPlugin(config, cspByRoute, MEDIA_URL) {
|
|
6
|
+
const out = join(join(config.outputDir, config.staticDir), '_headers')
|
|
7
|
+
|
|
8
|
+
const cspHeaders = cspByRoute.map(([route, csp]) => {
|
|
9
|
+
const r = route === '/index'
|
|
10
|
+
? '/'
|
|
11
|
+
: route
|
|
12
|
+
return `${r}\n Content-Security-Policy: ${csp}`
|
|
13
|
+
})
|
|
14
|
+
cspHeaders.push(`${MEDIA_URL}/*`)
|
|
15
|
+
cspHeaders.push(' Cache-Control: public,max-age=31536000,immutable')
|
|
16
|
+
|
|
17
|
+
write(out, cspHeaders.join('\n'))
|
|
18
|
+
}
|
|
19
|
+
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { join } from 'node:path'
|
|
2
|
-
import { read, sizeOf, sha1, saveAsJSON, isFile } from '
|
|
2
|
+
import { read, sizeOf, sha1, saveAsJSON, isFile } from '../utils/fs-utils.js'
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
export function
|
|
5
|
+
export function reportSizesPlugin(config, routes) {
|
|
6
|
+
const files = routes.map(f => f + config.outputExtension)
|
|
7
|
+
const baseDir = config.outputDir
|
|
8
|
+
const reportFilename = 'packed-sizes.json'
|
|
6
9
|
const oldReport = isFile(reportFilename)
|
|
7
10
|
? JSON.parse(read(reportFilename))
|
|
8
11
|
: {}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import { write, isFile } from '../utils/fs-utils.js'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export function sitemapPlugin(config, routes) {
|
|
6
|
+
if (!config.sitemapDomain)
|
|
7
|
+
return
|
|
8
|
+
|
|
9
|
+
const outMap = join(config.outputDir, 'sitemap.txt')
|
|
10
|
+
const outRobots = join(config.outputDir, 'robots.txt')
|
|
11
|
+
|
|
12
|
+
write(outMap, routes
|
|
13
|
+
.filter(r => r !== '/index')
|
|
14
|
+
.map(r => `https://${config.sitemapDomain + r}`)
|
|
15
|
+
.join('\n'))
|
|
16
|
+
|
|
17
|
+
if (!isFile(outRobots))
|
|
18
|
+
write(outRobots,
|
|
19
|
+
`Sitemap: https://${config.sitemapDomain}/sitemap.txt`)
|
|
20
|
+
}
|
|
@@ -2,43 +2,43 @@ import { join } from 'node:path'
|
|
|
2
2
|
import { readFile } from 'node:fs/promises'
|
|
3
3
|
|
|
4
4
|
import { docs } from './app.js'
|
|
5
|
-
import { mimeFor } from './mimes.js'
|
|
6
|
-
import { devClientWatcher } from './WatcherDevClient.js'
|
|
7
|
-
import { sendError, sendJSON, servePartialContent, serveStaticAsset } from './http-response.js'
|
|
5
|
+
import { mimeFor } from './utils/mimes.js'
|
|
6
|
+
import { devClientWatcher } from './plugins-dev/WatcherDevClient.js'
|
|
7
|
+
import { sendError, sendJSON, servePartialContent, serveStaticAsset } from './utils/http-response.js'
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
const WATCHER_DEV = '/plugins-dev/watcherDev.js'
|
|
11
|
+
|
|
10
12
|
const API = {
|
|
11
13
|
watchDev: '/packaton/watch-dev'
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
const WATCHER_DEV = '/watcherDev.js'
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
/** @param {Config} config */
|
|
18
19
|
export function router({ srcPath, ignore, mode }) {
|
|
19
20
|
docs.init(srcPath, ignore)
|
|
21
|
+
const isDev = mode === 'development'
|
|
20
22
|
return async function (req, response) {
|
|
21
23
|
let url = new URL(req.url, 'http://_').pathname
|
|
22
24
|
try {
|
|
23
|
-
if (url === API.watchDev)
|
|
25
|
+
if (url === API.watchDev)
|
|
24
26
|
longPollDevHotReload(req, response)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (url === WATCHER_DEV) {
|
|
27
|
+
|
|
28
|
+
else if (url === WATCHER_DEV)
|
|
28
29
|
serveStaticAsset(response, join(import.meta.dirname, url))
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (docs.hasRoute(url))
|
|
37
|
-
await serveDocument(response, docs.fileFor(url), mode === 'development')
|
|
30
|
+
|
|
31
|
+
else if (docs.hasRoute(url))
|
|
32
|
+
await serveDocument(response, docs.fileFor(url), isDev)
|
|
33
|
+
|
|
34
|
+
else if (docs.hasRoute(join(url, 'index')))
|
|
35
|
+
await serveDocument(response, docs.fileFor(join(url, 'index')), isDev)
|
|
36
|
+
|
|
38
37
|
else if (req.headers.range)
|
|
39
|
-
await servePartialContent(response, req.headers,
|
|
38
|
+
await servePartialContent(response, req.headers, join(srcPath, url))
|
|
39
|
+
|
|
40
40
|
else
|
|
41
|
-
serveStaticAsset(response,
|
|
41
|
+
serveStaticAsset(response, join(srcPath, url))
|
|
42
42
|
}
|
|
43
43
|
catch (error) {
|
|
44
44
|
sendError(response, error)
|
|
@@ -51,7 +51,7 @@ async function serveDocument(response, file, isDev) {
|
|
|
51
51
|
? await readFile(file, 'utf8')
|
|
52
52
|
: (await import(file + '?' + Date.now())).default()
|
|
53
53
|
if (isDev)
|
|
54
|
-
html += `<script type="module" src="${WATCHER_DEV}"></script>`
|
|
54
|
+
html += `<script type="module" src="${WATCHER_DEV}"></script>`
|
|
55
55
|
response.setHeader('Content-Type', mimeFor('html'))
|
|
56
56
|
response.end(html)
|
|
57
57
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|