packaton 0.0.6 → 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.
Files changed (30) hide show
  1. package/README.md +1 -1
  2. package/TODO.md +1 -0
  3. package/index.d.ts +1 -1
  4. package/index.js +5 -5
  5. package/package.json +1 -1
  6. package/src/app-dev.js +2 -2
  7. package/src/app-prod.js +18 -55
  8. package/src/app.js +1 -1
  9. package/src/config.js +6 -6
  10. package/src/{WatcherDevClient.js → plugins-dev/WatcherDevClient.js} +1 -1
  11. package/src/{HtmlCompiler.js → plugins-prod/HtmlCompiler.js} +1 -1
  12. package/src/plugins-prod/cspNginxMapPlugin.js +9 -0
  13. package/src/{media-remaper.js → plugins-prod/media-remaper.js} +1 -1
  14. package/src/plugins-prod/netiflyAndCloudflareHeadersPlugin.js +19 -0
  15. package/src/{reportSizes.js → plugins-prod/reportSizesPlugin.js} +5 -2
  16. package/src/plugins-prod/sitemapPlugin.js +20 -0
  17. package/src/{app-router.js → router.js} +20 -20
  18. /package/src/{openInBrowser.js → plugins-dev/openInBrowser.js} +0 -0
  19. /package/src/{watcherDev.js → plugins-dev/watcherDev.js} +0 -0
  20. /package/src/{HtmlCompiler.test.js → plugins-prod/HtmlCompiler.test.js} +0 -0
  21. /package/src/{media-remaper.test.js → plugins-prod/media-remaper.test.js} +0 -0
  22. /package/src/{minifyCSS.js → plugins-prod/minifyCSS.js} +0 -0
  23. /package/src/{minifyCSS.test.js → plugins-prod/minifyCSS.test.js} +0 -0
  24. /package/src/{minifyHTML.js → plugins-prod/minifyHTML.js} +0 -0
  25. /package/src/{minifyHTML.test.js → plugins-prod/minifyHTML.test.js} +0 -0
  26. /package/src/{minifyJS.js → plugins-prod/minifyJS.js} +0 -0
  27. /package/src/{fs-utils.js → utils/fs-utils.js} +0 -0
  28. /package/src/{fs-utils.test.js → utils/fs-utils.test.js} +0 -0
  29. /package/src/{http-response.js → utils/http-response.js} +0 -0
  30. /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
package/TODO.md CHANGED
@@ -6,3 +6,4 @@
6
6
  - remap media in css and js
7
7
  - watch newly added routes
8
8
  - todo test on linux (open in browser too)
9
+ - refactor to plugins/prod and plugins/dev
package/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export interface Config {
12
12
  hotReload?: boolean // For UI dev purposes only
13
13
 
14
14
  // Production
15
- outputPath?: string
15
+ outputDir?: string
16
16
  outputExtension?: string
17
17
  minifyJS?: (js: string) => Promise<string>
18
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 { reportSizes } from './src/reportSizes.js'
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "packaton",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "type": "module",
5
5
  "author": "Eric Fortis",
6
6
  "license": "MIT",
package/src/app-dev.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import http from 'node:http'
2
2
 
3
- import { router } from './app-router.js'
4
- import { watchDev } from './WatcherDevClient.js'
3
+ import { router } from './router.js'
4
+ import { watchDev } from './plugins-dev/WatcherDevClient.js'
5
5
 
6
6
 
7
7
  /**
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 './app-router.js'
7
- import { reportSizes } from './reportSizes.js'
8
- import { HtmlCompiler } from './HtmlCompiler.js'
9
- import { write, removeDir, isFile } from './fs-utils.js'
10
- import { renameMediaWithHashes } from './media-remaper.js'
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
  /**
@@ -19,25 +22,15 @@ export async function buildStaticPages(config) {
19
22
  const MEDIA_REL_URL = join(config.staticDir, 'media')
20
23
 
21
24
  const pSource = config.srcPath
22
- const pDist = config.outputPath
23
- const pDistStatic = join(config.outputPath, config.staticDir)
25
+ const pDist = config.outputDir
26
+ const pDistStatic = join(config.outputDir, config.staticDir)
24
27
  const pDistMedia = join(pDist, MEDIA_REL_URL)
25
- const pDistSitemap = join(pDist, 'sitemap.txt')
26
- const pDistRobots = join(pDist, 'robots.txt')
27
- const pSizesReport = 'packed-sizes.json'
28
28
 
29
- const pDistCspNginxMap = join(pDist, '.csp-map.nginx')
30
- const CLOUDFLARE_HEADERS_FILE = join(pDistStatic, '_headers')
31
-
32
- const server = http.createServer(router(config))
33
- server.listen(0, '127.0.0.1', async error => {
29
+ const server = createServer(router(config))
30
+ server.on('error', reject)
31
+ server.listen(0, '127.0.0.1', async () => {
34
32
  docs.init(config.srcPath, config.ignore)
35
33
  try {
36
- if (error) {
37
- reject(error)
38
- return
39
- }
40
-
41
34
  removeDir(pDist)
42
35
  cpSync(join(pSource, config.staticDir), pDistStatic, {
43
36
  recursive: true,
@@ -69,27 +62,10 @@ export async function buildStaticPages(config) {
69
62
  cspByRoute.push([route, doc.csp()])
70
63
  }
71
64
 
72
- if (config.sitemapDomain) {
73
- write(pDistSitemap, docs.routes
74
- .filter(r => r !== '/index')
75
- .map(r => `https://${config.sitemapDomain + r}`)
76
- .join('\n'))
77
-
78
- if (!isFile(pDistRobots))
79
- write(pDistRobots,
80
- `Sitemap: https://${config.sitemapDomain}/sitemap.txt`)
81
- }
82
-
83
- if (config.cspMapEnabled) {
84
- write(pDistCspNginxMap, cspByRoute.map(([route, csp]) =>
85
- `${route} "${csp}";`).join('\n'))
86
-
87
- write(CLOUDFLARE_HEADERS_FILE,
88
- makeHeadersFile(cspByRoute, MEDIA_REL_URL))
89
- }
90
-
91
- reportSizes(pSizesReport, pDist,
92
- 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)
93
69
  }
94
70
  catch (error) {
95
71
  reject(error)
@@ -104,19 +80,6 @@ export async function buildStaticPages(config) {
104
80
  })
105
81
  }
106
82
 
107
- // TODO @ThinkAbout in Nginx we need to use `/index` but in CF `/`
108
- function makeHeadersFile(cspByRoute, MEDIA_URL) {
109
- const cspHeaders = cspByRoute.map(([route, csp]) => {
110
- const r = route === '/index'
111
- ? '/'
112
- : route
113
- return `${r}\n Content-Security-Policy: ${csp}`
114
- })
115
- cspHeaders.push(`${MEDIA_URL}/*`)
116
- cspHeaders.push(' Cache-Control: public,max-age=31536000,immutable')
117
- return cspHeaders.join('\n')
118
- }
119
-
120
83
 
121
84
  async function crawlRoutes({ address, port }, routes) {
122
85
  const pages = []
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 {{
@@ -28,7 +28,7 @@ const schema = {
28
28
 
29
29
  // Production
30
30
  outputExtension: ['.html', optional(String)],
31
- outputPath: ['dist', optional(String)], // TODO resolve
31
+ outputDir: ['dist', optional(String)], // TODO resolve
32
32
  minifyJS: [minifyJS, optional(Function)],
33
33
  minifyCSS: [minifyCSS, optional(Function)],
34
34
  minifyHTML: [minifyHTML, optional(Function)],
@@ -1,7 +1,7 @@
1
1
  import { join } from 'node:path'
2
2
  import { watch } from 'node:fs'
3
3
  import { EventEmitter } from 'node:events'
4
- import { docs } from './app.js'
4
+ import { docs } from '../app.js'
5
5
 
6
6
 
7
7
  export const devClientWatcher = new class extends EventEmitter {
@@ -1,7 +1,7 @@
1
1
  import { join } from 'node:path'
2
2
  import { createHash } from 'node:crypto'
3
3
 
4
- import { read } from './fs-utils.js'
4
+ import { read } from '../utils/fs-utils.js'
5
5
  import { remapMediaInHTML } from './media-remaper.js'
6
6
 
7
7
 
@@ -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 './fs-utils.js'
3
+ import { sha1, listFiles } from '../utils/fs-utils.js'
4
4
 
5
5
 
6
6
  /**
@@ -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 './fs-utils.js'
2
+ import { read, sizeOf, sha1, saveAsJSON, isFile } from '../utils/fs-utils.js'
3
3
 
4
4
 
5
- export function reportSizes(reportFilename, baseDir, files) {
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
- return
26
- }
27
- if (url === WATCHER_DEV) {
27
+
28
+ else if (url === WATCHER_DEV)
28
29
  serveStaticAsset(response, join(import.meta.dirname, url))
29
- return
30
- }
31
-
32
- if (url === '/')
33
- url = '/index'
34
-
35
- const file = join(srcPath, url)
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, file)
38
+ await servePartialContent(response, req.headers, join(srcPath, url))
39
+
40
40
  else
41
- serveStaticAsset(response, file)
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