aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/builder/buildProject.ts51
-rw-r--r--app/builder/processCss.ts22
-rw-r--r--app/config/cleanCss.ts3
-rw-r--r--package-lock.json43
-rw-r--r--package.json2
5 files changed, 118 insertions, 3 deletions
diff --git a/app/builder/buildProject.ts b/app/builder/buildProject.ts
index 71fdf73..03cc58e 100644
--- a/app/builder/buildProject.ts
+++ b/app/builder/buildProject.ts
@@ -3,6 +3,8 @@ import { Page, PageDirectory } from './pageDirectory.js';
import fs from 'fs';
import path from 'path';
import { logger } from '../logger.js';
+import glob from 'glob';
+import { process as processCss } from './processCss.js';
export async function buildPages(): Promise<{ success: boolean, errors: number, pageDirectory: PageDirectory}> {
// Recreate output directory
@@ -42,15 +44,62 @@ export async function buildPages(): Promise<{ success: boolean, errors: number,
logger.info(`Rendered ${pagesRendered} of ${pagesCount} pages.`);
+ //TODO move to util
+ const ensureParentDirExists = (file: string) => {
+ const joinedOutputPath = path.join(process.env.OUTPUT_DIR, 'static', file);
+ const dir = path.dirname(joinedOutputPath);
+ if (!fs.existsSync(dir)) {
+ fs.mkdirSync(dir, { recursive: true });
+ }
+ return joinedOutputPath;
+ };
// Copy static files
logger.info(`Copying static files...`);
try {
- fs.cpSync(`${process.env.STATIC_DIR}`, `${process.env.OUTPUT_DIR}/static`, { recursive: true });
+ const files = glob.sync(`**/*`, {
+ cwd: process.env.STATIC_DIR,
+ nodir: true,
+ ignore: ['**/*.scss', '**/*.css']
+ })
+
+ for (const file of files) {
+ const outputPath = ensureParentDirExists(file);
+ const joinedPath = path.join(process.env.STATIC_DIR, file);
+ fs.copyFileSync(joinedPath, outputPath);
+ }
+
logger.info(`Done.`);
} catch (e) {
logger.error(`Failed to copy static files: ${e.message}`);
}
+
+ // Process CSS files
+ const cssFiles = glob.sync(`**/*.{css,scss}`, {
+ cwd: process.env.STATIC_DIR,
+ nodir: true,
+ });
+ if (cssFiles.length > 0) {
+ logger.info(`Processing CSS files...`);
+
+ for (const file of cssFiles) {
+ const outputPath = ensureParentDirExists(file);
+ const joinedPath = path.join(process.env.STATIC_DIR, file);
+ let processedCss: string;
+ try {
+ processedCss = await processCss(joinedPath);
+ } catch (e) {
+ logger.error(`Failed to process CSS file ${joinedPath}`);
+ logger.error(e.message);
+ continue;
+ }
+ const newOutputPath = outputPath.replace(/\.scss$/, '.css');
+ fs.writeFileSync(newOutputPath, processedCss);
+ }
+
+ logger.info(`Done.`);
+ }
+
return { success: pagesFailed == 0, errors: pagesFailed, pageDirectory: pageDirectory};
}
diff --git a/app/builder/processCss.ts b/app/builder/processCss.ts
new file mode 100644
index 0000000..24aa3cf
--- /dev/null
+++ b/app/builder/processCss.ts
@@ -0,0 +1,22 @@
+import fs from 'fs';
+import * as sass from 'sass';
+import CleanCSS from 'clean-css';
+
+const cleanCss = new CleanCSS({ returnPromise: true });
+
+export async function process(file: string): Promise<string> {
+ const scss = file.endsWith('.scss');
+
+ const content = fs.readFileSync(file, 'utf-8').toString();
+
+ let css: string;
+ if (scss) {
+ css = sass.compileString(content).css;
+ } else {
+ css = content;
+ }
+
+ const minified = (await cleanCss.minify(css)).styles;
+
+ return minified;
+}
diff --git a/app/config/cleanCss.ts b/app/config/cleanCss.ts
new file mode 100644
index 0000000..eabaf8a
--- /dev/null
+++ b/app/config/cleanCss.ts
@@ -0,0 +1,3 @@
+import CleanCSS from "clean-css";
+
+export const minify = new CleanCSS({ returnPromise: true }).minify;
diff --git a/package-lock.json b/package-lock.json
index 2d29526..ced5197 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "panulat",
"version": "1.2",
"dependencies": {
+ "@types/clean-css": "^4.2.6",
"@types/html-minifier-terser": "^7.0.0",
"axios": "^1.4.0",
"chokidar": "^3.5.3",
@@ -22,6 +23,7 @@
"html-minifier-terser": "^7.2.0",
"marked": "^6.0.0",
"marked-gfm-heading-id": "^3.0.6",
+ "sass": "^1.66.1",
"uglify-js": "^3.17.4",
"winston": "^3.3.3",
"ws": "^8.13.0"
@@ -251,6 +253,15 @@
"@types/node": "*"
}
},
+ "node_modules/@types/clean-css": {
+ "version": "4.2.6",
+ "resolved": "https://registry.npmjs.org/@types/clean-css/-/clean-css-4.2.6.tgz",
+ "integrity": "sha512-Ze1tf+LnGPmG6hBFMi0B4TEB0mhF7EiMM5oyjLDNPE9hxrPU0W+5+bHvO+eFPA+bt0iC1zkQMoU/iGdRVjcRbw==",
+ "dependencies": {
+ "@types/node": "*",
+ "source-map": "^0.6.0"
+ }
+ },
"node_modules/@types/connect": {
"version": "3.4.35",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
@@ -338,8 +349,7 @@
"node_modules/@types/node": {
"version": "20.4.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.8.tgz",
- "integrity": "sha512-0mHckf6D2DiIAzh8fM8f3HQCvMKDpK94YQ0DSVkfWTG9BZleYIWudw9cJxX8oCk9bM+vAkDyujDV6dmKHbvQpg==",
- "dev": true
+ "integrity": "sha512-0mHckf6D2DiIAzh8fM8f3HQCvMKDpK94YQ0DSVkfWTG9BZleYIWudw9cJxX8oCk9bM+vAkDyujDV6dmKHbvQpg=="
},
"node_modules/@types/qs": {
"version": "6.9.7",
@@ -1928,6 +1938,11 @@
"node": ">= 4"
}
},
+ "node_modules/immutable": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
+ "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA=="
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -2724,6 +2739,22 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
+ "node_modules/sass": {
+ "version": "1.66.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz",
+ "integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==",
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
@@ -2870,6 +2901,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
diff --git a/package.json b/package.json
index 3af100c..a953c9c 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
},
"author": "Leonardo Bishop",
"dependencies": {
+ "@types/clean-css": "^4.2.6",
"@types/html-minifier-terser": "^7.0.0",
"axios": "^1.4.0",
"chokidar": "^3.5.3",
@@ -23,6 +24,7 @@
"html-minifier-terser": "^7.2.0",
"marked": "^6.0.0",
"marked-gfm-heading-id": "^3.0.6",
+ "sass": "^1.66.1",
"uglify-js": "^3.17.4",
"winston": "^3.3.3",
"ws": "^8.13.0"