More docker updates
Minifying CSS
This commit is contained in:
parent
219841a148
commit
8b21ff6e68
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,3 +3,5 @@ node_modules
|
||||
dist
|
||||
src/*.js
|
||||
src/**/*.js
|
||||
public/index.html
|
||||
public/main.*.css
|
18
default.conf
Normal file
18
default.conf
Normal file
@ -0,0 +1,18 @@
|
||||
server {
|
||||
listen 4173;
|
||||
|
||||
root /app;
|
||||
|
||||
location /app {
|
||||
try_files $uri $uri/ =404;
|
||||
|
||||
# Cache settings for static content
|
||||
expires 7d; # Cache static content for 7 days
|
||||
add_header Cache-Control "public, max-age=604800, immutable";
|
||||
}
|
||||
|
||||
# Additional configurations can be added here if needed
|
||||
# For example, error handling, logging, etc.
|
||||
error_page 404 /index.html;
|
||||
error_page 500 502 503 504 /index.html;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
# Build site using Node JS
|
||||
FROM node:21-slim
|
||||
|
||||
# Install nginx
|
||||
RUN apt-get update && apt-get install -y nginx
|
||||
|
||||
ARG BUILD_DATE
|
||||
@ -19,6 +20,9 @@ RUN npm i
|
||||
|
||||
COPY . .
|
||||
|
||||
# Copy the nginx config to the correct folder
|
||||
COPY default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
ENV NODE_ENV production
|
||||
|
||||
ENV TITLE "My Website"
|
||||
@ -37,4 +41,4 @@ EXPOSE 4173
|
||||
RUN chmod +x /app/docker-entrypoint.sh
|
||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||
|
||||
CMD ["npm", "run", "start"]
|
||||
CMD ["npm", "run", "build"]
|
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
|
||||
<title>My Website</title>
|
||||
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
|
||||
<link rel="stylesheet" crossorigin="" href="./main.css" />
|
||||
<link rel="stylesheet" href="./main.css" crossorigin="" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
33
package-lock.json
generated
33
package-lock.json
generated
@ -9,10 +9,14 @@
|
||||
"version": "1.4.0",
|
||||
"dependencies": {
|
||||
"@types/node": "^20.10.5",
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier": "^4.0.0",
|
||||
"prettier": "^3.1.1",
|
||||
"tailwindcss": "^3.3.6",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/clean-css": "^4.2.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
@ -106,6 +110,16 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/clean-css": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/clean-css/-/clean-css-4.2.11.tgz",
|
||||
"integrity": "sha512-Y8n81lQVTAfP2TOdtJJEsCoYl1AnOkqDqMvXb9/7pfgZZ7r8YrEyurrAvAoAjHOGXKRybay+5CsExqIH6liccw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz",
|
||||
@ -224,14 +238,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/clean-css": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
|
||||
"integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
|
||||
"integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==",
|
||||
"dependencies": {
|
||||
"source-map": "~0.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.0"
|
||||
"node": ">= 10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
@ -408,6 +422,17 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/html-minifier/node_modules/clean-css": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz",
|
||||
"integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==",
|
||||
"dependencies": {
|
||||
"source-map": "~0.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-minifier/node_modules/commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
|
11
package.json
11
package.json
@ -8,12 +8,14 @@
|
||||
"version": "1.4.0",
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
"build": "tsc && node ./dist/static.js && npm run html && npm run tailwind",
|
||||
"html": "html-minifier --remove-comments --collapse-whitespace --input-dir ./dist --output-dir ./dist --file-ext html",
|
||||
"tailwind": "npx tailwindcss -i ./src/tailwind.css -o ./dist/main.css"
|
||||
"build": "tsc && node ./dist/index.js && npm run html && npm run tailwind && npm run css-cache-break",
|
||||
"html": "html-minifier --remove-comments --collapse-whitespace --input-dir ./public --output-dir ./public --file-ext html",
|
||||
"tailwind": "npx tailwindcss -i ./src/tailwind.css -o ./public/main.css",
|
||||
"css-cache-break": "node ./dist/css-cache-break.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^20.10.5",
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier": "^4.0.0",
|
||||
"prettier": "^3.1.1",
|
||||
"tailwindcss": "^3.3.6",
|
||||
@ -27,5 +29,8 @@
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": true
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/clean-css": "^4.2.11"
|
||||
}
|
||||
}
|
||||
|
23
src/css-cache-break.ts
Normal file
23
src/css-cache-break.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import CleanCSS from "clean-css";
|
||||
import * as path from "path";
|
||||
import { sbReadFile, sbRename, sbWriteFile } from "./shared/files";
|
||||
|
||||
const mainCSSFilename = `main.${new Date().getTime()}.css`;
|
||||
|
||||
const cssFileInPath = path.join(__dirname, "../", "./public", "main.css");
|
||||
const cssFileOutPath = path.join(__dirname, "../", "./public", mainCSSFilename);
|
||||
const indexFileInOutPath = path.join(__dirname, "../", "./public", "index.html");
|
||||
|
||||
async function start(): Promise<void> {
|
||||
await sbRename(cssFileInPath, cssFileOutPath);
|
||||
const css = await sbReadFile(cssFileOutPath);
|
||||
await sbWriteFile(cssFileOutPath, new CleanCSS().minify(css).styles);
|
||||
|
||||
const index = await sbReadFile(indexFileInOutPath);
|
||||
const cssLink = `<link rel="stylesheet" href="./main.css" crossorigin="">`;
|
||||
const cssLinkReplacement = `<link rel="stylesheet" href="./${mainCSSFilename}" crossorigin="" />`;
|
||||
|
||||
await sbWriteFile(indexFileInOutPath, index.replace(cssLink, cssLinkReplacement));
|
||||
}
|
||||
|
||||
start();
|
21
src/index.ts
Normal file
21
src/index.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import * as path from "path";
|
||||
import { IndexPage } from "./pages/index";
|
||||
import { sbReadFile, sbWriteFile } from "./shared/files";
|
||||
import { PAGEICON, PAGETITLE } from "./variables";
|
||||
|
||||
const indexFileInPath = path.join(__dirname, "../", "index.html");
|
||||
const indexFileOutPath = path.join(__dirname, "../", "./public", "index.html");
|
||||
|
||||
async function start(): Promise<void> {
|
||||
const index = await sbReadFile(indexFileInPath);
|
||||
|
||||
const newText = IndexPage({ icon: PAGEICON, title: PAGETITLE });
|
||||
const rootDiv = '<div id="root"></div>';
|
||||
const rootDivReplacement = '<div id="root">$1</div>';
|
||||
|
||||
const newIndex = index.replace(rootDiv, rootDivReplacement.replace("$1", newText));
|
||||
|
||||
await sbWriteFile(indexFileOutPath, newIndex);
|
||||
}
|
||||
|
||||
start();
|
38
src/shared/files.ts
Normal file
38
src/shared/files.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import * as fs from "fs/promises";
|
||||
|
||||
export async function sbReadFile(fileName: string): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const index = await fs.readFile(fileName);
|
||||
|
||||
return resolve(index.toString());
|
||||
} catch (exception) {
|
||||
console.error(`Could not read file: ${fileName}`);
|
||||
reject(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function sbWriteFile(fileName: string, contents: string): Promise<boolean> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
await fs.writeFile(fileName, contents);
|
||||
return resolve(true);
|
||||
} catch (exception) {
|
||||
console.error(`Could not write file: ${fileName}`);
|
||||
reject(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function sbRename(fileNameOld: string, fileNameNew: string): Promise<boolean> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
await fs.rename(fileNameOld, fileNameNew);
|
||||
return resolve(true);
|
||||
} catch (exception) {
|
||||
console.error(`Could not rename file: ${fileNameOld} to ${fileNameNew}`);
|
||||
reject(exception);
|
||||
}
|
||||
});
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
import * as fs from "fs/promises";
|
||||
import * as path from "path";
|
||||
import { IndexPage } from "./pages/index";
|
||||
import { PAGEICON, PAGETITLE } from "./variables";
|
||||
|
||||
const indexFileInPath = path.join(__dirname, "../", "index.html");
|
||||
const indexFileOutPath = path.join(__dirname, "../", "./dist", "index.html");
|
||||
|
||||
async function readIndexPage(): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const index = await fs.readFile(indexFileInPath);
|
||||
|
||||
return resolve(index.toString());
|
||||
} catch (exception) {
|
||||
console.error("Could not read index.html file");
|
||||
reject(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function writeIndexPage(contents: string): Promise<boolean> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
await fs.writeFile(indexFileOutPath, contents);
|
||||
return resolve(true);
|
||||
} catch (exception) {
|
||||
console.error("Could not write index.html file");
|
||||
reject(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function start(): Promise<void> {
|
||||
const index = await readIndexPage();
|
||||
|
||||
const newText = IndexPage({ icon: PAGEICON, title: PAGETITLE });
|
||||
const rootDiv = '<div id="root"></div>';
|
||||
const rootDivReplacement = '<div id="root">$1</div>';
|
||||
|
||||
const newIndex = index.replace(rootDiv, rootDivReplacement.replace("$1", newText));
|
||||
|
||||
await writeIndexPage(newIndex);
|
||||
}
|
||||
|
||||
start();
|
@ -8,5 +8,5 @@
|
||||
"resolveJsonModule": true,
|
||||
"module": "CommonJS"
|
||||
},
|
||||
"include": ["src/static.ts"]
|
||||
"include": ["src/index.ts", "src/css-cache-break.ts"]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user