include admin and frontend inside the exe

Massimo Melina committed Feb 9, 2022 at 22:55 UTC e8ad7d6e66c8b6364abc8a59d8551432515441aa
4 files changed +24 -24
package-lock.json
+2 -2
@@ -1,12 +1,12 @@
1 {
2 "name": "hfs",
3 - "version": "0.9.1",
3 + "version": "0.10.0",
4 "lockfileVersion": 2,
5 "requires": true,
6 "packages": {
7 "": {
8 "name": "hfs",
9 - "version": "0.9.1",
9 + "version": "0.10.0",
10 "license": "GPL-3.0",
11 "dependencies": {
12 "@koa/router": "^10.1.1",
package.json
+6 -7
@@ -1,6 +1,6 @@
1 {
2 "name": "hfs",
3 - "version": "0.9.1",
3 + "version": "0.10.0",
4 "description": "HTTP File Server",
5 "keywords": [
6 "file server",
@@ -20,12 +20,9 @@
20 "build-admin": "cd admin && npm install && npm run build",
21 "test": "mocha -r ts-node/register 'tests/**/*.ts'",
22 "zip-dist": "cd dist && zip hfs.zip -r * -x *.zip *.exe",
23 - "exe-dist": "pkg . -C brotli && cd dist && rm -rf src node_modules && zip hfs.exe.zip -r * -x *.zip run.bat",
23 + "exe-dist": "pkg . -C brotli && cd dist && zip hfs.exe.zip hfs.exe -r plugins",
24 "new-dist": "npm run build-all && npm run zip-dist && npm run exe-dist"
25 },
26 - "bin": {
27 - "hfs": "./dist/src/index.js"
28 - },
26 "engines": {
27 "node": ">=16.13.0"
28 },
@@ -36,9 +33,11 @@
33 "type": "git",
34 "url": "https://github.com/rejetto/hfs/"
35 },
36 + "bin": {
37 + "hfs": "dist/src/index.js"
38 + },
39 "pkg": {
40 - "scripts": "dist/src/**/*.js",
41 - "assets": "",
40 + "assets": ["dist/admin/**/*", "dist/frontend/**/*"],
41 "targets": [
42 "node16-win"
43 ],
src/serveFile.ts
+3 -2
@@ -1,5 +1,5 @@
1 import Koa from 'koa'
2 -import { createReadStream } from 'fs'
2 +import { createReadStream, stat } from 'fs'
3 import fs from 'fs/promises'
4 import { METHOD_NOT_ALLOWED, NO_CONTENT } from './const'
5 import { MIME_AUTO, VfsNode } from './vfs'
@@ -8,6 +8,7 @@ import { getConfig } from './config'
8 import mm from 'micromatch'
9 import _ from 'lodash'
10 import path from 'path'
11 +import { promisify } from 'util'
12
13 export function serveFileNode(node: VfsNode) : Koa.Middleware {
14 const { source, mime } = node
@@ -37,7 +38,7 @@ export function serveFile(source:string, mime?:string, modifier?:(s:string)=>str
38 }
39 if (ctx.method !== 'GET')
40 return ctx.status = METHOD_NOT_ALLOWED
40 - const stats = await fs.stat(source)
41 + const stats = await promisify(stat)(source) // using fs's function instead of fs/promises, because only the former is supported by pkg
42 ctx.set('Last-Modified', stats.mtime.toUTCString())
43 ctx.fileSource = source
44 ctx.status = 200
src/serveFrontend.ts
+13 -13
@@ -5,6 +5,7 @@ import { serveFile } from './serveFile'
5 import { mapPlugins } from './plugins'
6 import { refresh_session } from './api.auth'
7 import { ApiError } from './apis'
8 +import path from 'path'
9
10 function serveProxyFrontend(port?: string) { // used for development
11 if (!port)
@@ -30,26 +31,25 @@ function serveProxyFrontend(port?: string) { // used for development
31 const DEV_STATIC = process.env.DEV ? 'dist/' : ''
32
33 const serveStaticFrontend : Koa.Middleware = async (ctx, next) => {
33 - const BASE = DEV_STATIC + 'frontend/'
34 - let { path, method } = ctx
35 - if (method === 'OPTIONS') {
34 + const isDir = ctx.path.endsWith('/')
35 + const fullPath = path.join(__dirname, '..', DEV_STATIC, 'frontend', isDir ? '/index.html' : ctx.path)
36 + if (ctx.method === 'OPTIONS') {
37 ctx.status = NO_CONTENT
38 ctx.set({ Allow: 'OPTIONS, GET' })
39 return
40 }
40 - if (method !== 'GET')
41 + if (ctx.method !== 'GET')
42 return ctx.status = METHOD_NOT_ALLOWED
42 - if (path.endsWith('/')) { // we don't cache the index as it's small and may prevent plugins change to apply
43 - ctx.body = await treatIndex(ctx, String(await fs.readFile(BASE + 'index.html')))
44 - ctx.type = 'html'
45 - ctx.set('Cache-Control', 'no-store, no-cache, must-revalidate')
46 - } else {
47 - const fullPath = BASE + path.slice(1)
48 - const modifier = path.includes('static/js') ? // webpack
43 + if (!isDir) {
44 + const modifier = fullPath.includes('static/js') ? // webpack
45 (s:string) => s.replace(/(return")(static\/)/g, '$1' + FRONTEND_URI.substring(1) + '$2')
46 : undefined
47 return serveFile(fullPath, 'auto', modifier)(ctx, next)
48 }
49 + // we don't cache the index as it's small and may prevent plugins change to apply
50 + ctx.body = await treatIndex(ctx, String(await fs.readFile(fullPath)))
51 + ctx.type = 'html'
52 + ctx.set('Cache-Control', 'no-store, no-cache, must-revalidate')
53 await next()
54 }
55
@@ -66,8 +66,8 @@ function serveAdminProxy(port?: string) { // used for development
66 }
67
68 const serveAdminStatic : Koa.Middleware = async (ctx, next) => {
69 - const fullPath = 'admin' + (ctx.path.includes('.') ? ctx.path : '/index.html');
70 - return serveFile(DEV_STATIC + fullPath, 'auto')(ctx, next)
69 + const fullPath = path.join(__dirname, '..', DEV_STATIC, 'admin', ctx.path.includes('.') ? ctx.path : '/index.html')
70 + return serveFile(fullPath, 'auto')(ctx, next)
71 }
72
73 async function treatIndex(ctx: Koa.Context, body: string) {