diff options
| author | Leonardo Bishop <me@leonardobishop.com> | 2023-08-28 22:47:13 +0100 |
|---|---|---|
| committer | Leonardo Bishop <me@leonardobishop.com> | 2023-08-28 22:47:13 +0100 |
| commit | d5802a34218a56357a7ae88eff1d3cfa86d41bc7 (patch) | |
| tree | 8b11b7e490c33513d7581fa95b828c4064d17ecd | |
| parent | 7c9abacf956c0e135c1094e38087e018dd572965 (diff) | |
Add SCSS support
| -rw-r--r-- | app/builder/buildProject.ts | 51 | ||||
| -rw-r--r-- | app/builder/processCss.ts | 22 | ||||
| -rw-r--r-- | app/config/cleanCss.ts | 3 | ||||
| -rw-r--r-- | package-lock.json | 43 | ||||
| -rw-r--r-- | package.json | 2 |
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" |
