diff --git a/packages/eleventy-config/src/lib/eleventy-config.ts b/packages/eleventy-config/src/lib/eleventy-config.ts index 126f59e..4b89b25 100644 --- a/packages/eleventy-config/src/lib/eleventy-config.ts +++ b/packages/eleventy-config/src/lib/eleventy-config.ts @@ -10,8 +10,27 @@ import { minifyHtml } from './minify-html.js'; import { postcssBuild } from './postcss.js'; import { trim } from './util/trim.js'; +type EleventyOptions = { + directories: { + root: string; + shortcode: string; + style: string; + jsOutput: string; + output: string; + data: string; + layouts: string; + includes: string; + }; + files: { + baseFileName: string; + templateFormats?: string[]; + markDownTemplateEngine: string; + htmlTemplateEngine: string; + } +}; + /** - * Configures Eleventy with nexi app specification and html minify, postcss, workbox, etc. + * Configures Eleventy with nexim app specification and html minify, postcss, workbox, etc. * * @param eleventyConfig - The eleventy config * @returns The eleventyConfig return type @@ -24,29 +43,46 @@ import { trim } from './util/trim.js'; * import {eleventyConfiguration} from '@nexim/eleventy-config'; * * export default function (eleventyConfig) { - * return eleventyConfiguration(eleventyConfig); + * return eleventyConfiguration(eleventyConfig,{ + * directories: { + * root: 'site', + * shortcode: 'shortcode', + * style: 'style', + * jsOutput: 'dist/es', + * output: 'dist', + * data: '_data', + * layouts: '_layout', + * includes: '_include', + * }, + * files: { + * baseFileName: 'index', + * // optional + * // have default value ['md', 'njk', '11ty.js'], + * templateFormatsExtensions: [], + * markDownTemplateEngine: 'md', + * htmlTemplateEngine: 'njk', + * }); * } * ``` */ /* eslint-disable @typescript-eslint/no-explicit-any */ -export function eleventyConfiguration(eleventyConfig: any) { +export function eleventyConfiguration(eleventyConfig: any,options: EleventyOptions) { eleventyConfig.addPassthroughCopy({ assets: '/', 'assets/img/meta/favicon.ico': '/favicon.ico', }); // templates root Directory - - eleventyConfig.addWatchTarget('site'); + eleventyConfig.addWatchTarget(options.directories.root); // shortcodes Directory - eleventyConfig.addWatchTarget('shortcode'); + eleventyConfig.addWatchTarget(options.directories.shortcode); // styles Directory - eleventyConfig.addWatchTarget('style'); + eleventyConfig.addWatchTarget(options.directories.style); // build target typescript Directory - eleventyConfig.addWatchTarget('dist/es'); + eleventyConfig.addWatchTarget(options.directories.jsOutput); /** * Watch javascript dependencies @@ -91,8 +127,17 @@ export function eleventyConfiguration(eleventyConfig: any) { /** * Set after eventListener for build css and service worker */ - eleventyConfig.on('eleventy.after', postcssBuild); - eleventyConfig.on('eleventy.after', generateServiceWorker); + const configureBuilding = postcssBuild({inputDir: options.directories.style, outputDir: options.directories.output + '/css'}); + eleventyConfig.on('eleventy.after', configureBuilding); + + const generateServiceWorkerWithOptions = generateServiceWorker({ + outputDir: options.directories.output, + deploymentServiceWorkerContent: "console.log('service worker not build in deployment.')", + nameOfServiceWorker: 'service-worker.js', + maximumFileSize: 1 * 1024 * 1024, // 1MB + mode: 'production', + }); + eleventyConfig.on('eleventy.after', generateServiceWorkerWithOptions); /** * Add template cjs to extension @@ -103,18 +148,18 @@ export function eleventyConfiguration(eleventyConfig: any) { * Set data root directory and base name of file */ eleventyConfig.setDataFileSuffixes([ '.data' ]); - eleventyConfig.setDataFileBaseName('index'); + eleventyConfig.setDataFileBaseName(options.files.baseFileName); /** * Add Html, Nunjucks, Markdown, Tsx, Jsx, for template engines */ - eleventyConfig.templateFormats = [ 'md', 'njk', '11ty.js' ]; + eleventyConfig.templateFormats = [ 'md', 'njk', '11ty.js', ...(options.files.templateFormats ?? []) ]; return { // if your site lives in a subdirectory, change this pathPrefix: '/', - markdownTemplateEngine: 'md', - htmlTemplateEngine: 'njk', + markdownTemplateEngine: options.files.markDownTemplateEngine, + htmlTemplateEngine: options.files.htmlTemplateEngine, handlebarsHelpers: {}, nunjucksFilters: {}, @@ -132,11 +177,11 @@ export function eleventyConfiguration(eleventyConfig: any) { }, dir: { - input: 'site', - output: 'dist', - includes: '_include', - data: '_data', - layouts: '_layout', + data: options.directories.data, + input: options.directories.root, + output: options.directories.output, + layouts: options.directories.layouts, + includes: options.directories.includes, }, }; } diff --git a/packages/eleventy-config/src/lib/minify-html.ts b/packages/eleventy-config/src/lib/minify-html.ts index c250301..0f0100b 100644 --- a/packages/eleventy-config/src/lib/minify-html.ts +++ b/packages/eleventy-config/src/lib/minify-html.ts @@ -1,6 +1,5 @@ -import { type Options, minify } from '@swc/html'; - -import { logger } from './logger.js'; +import {type Options, minify} from '@swc/html'; +import {logger} from './logger.js'; const swcHtmlOptions: Options = { forceSetHtml5Doctype: true, @@ -42,3 +41,48 @@ export async function minifyHtml(this: any, content: string): Promise { return content; } } + +/** + * Options for the eleventyMinifyHtmlPlugin. + */ +export type EleventyMinifyHtmlPluginOptions = { + /** + * The this of this. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this: any; + + /** + * The content for minifying by the plugin. + */ + content: string; +}; + +/** + * Eleventy plugin for minifying HTML content. + * + * @param eleventyConfig - The Eleventy configuration object. + * @param options - The options for the plugin. + * + * @example + * ```js + * // eleventy.config.mjs + * + * import {eleventyMinifyHtmlPlugin} from '@nexim/eleventy-config'; + * + * export default function (eleventyConfig) { + * eleventyConfig.addPlugin(eleventyMinifyHtmlPlugin, {content}); + * // ... + * } + * ``` + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function eleventyMinifyHtmlPlugin(eleventyConfig: any, options: EleventyMinifyHtmlPluginOptions): void { + // TODO: better event handling to just copy for the first time + + const minifyingHtml = minifyHtml(options.content); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + eleventyConfig.addTransform('minifyHtml', minifyingHtml); +} + diff --git a/packages/eleventy-config/src/lib/postcss.ts b/packages/eleventy-config/src/lib/postcss.ts index a314608..edc837f 100644 --- a/packages/eleventy-config/src/lib/postcss.ts +++ b/packages/eleventy-config/src/lib/postcss.ts @@ -30,11 +30,12 @@ if (!platformInfo.development) { const postCss = /* @__PURE__ */ postcss(postCssPlugins); -export async function postcssBuild(): Promise { - logger.logMethod?.('postcssBuild'); +export async function postcssBuild(options: {inputDir: string, outputDir: string}): Promise { + postCssPlugins[0] = /* @__PURE__ */ postcssImport({ root: options.inputDir }); - const inputDir = basePath; - const outputDir = 'dist/css/'; + logger.logMethod?.('postcssBuild'); + const inputDir = options.inputDir; + const outputDir = options.outputDir; const startTime = Date.now(); if (!existsSync(outputDir)) { @@ -88,3 +89,50 @@ export async function postcssBuild(): Promise { const calculatedTime = String(endTime - startTime); logger.logOther?.(`PostCSS build done in ${calculatedTime}ms`); } + +/** + * Options for the eleventyMinifyHtmlPlugin. + */ +type EleventyPostCssPluginOptions = { + /** + * The Css Input Directory. + */ + inputDir: string; + + /** + * The Css Output Directory. + */ + outputDir: string; +}; + +/** + * Eleventy plugin for Building Css with PostCss. + * + * @param eleventyConfig - The Eleventy configuration object. + * @param options - The options for the plugin. + * + * @example + * ```js + * // eleventy.config.mjs + * + * import {eleventyPostCssBuildPlugin} from '@nexim/eleventy-config'; + * + * export default function (eleventyConfig) { + * eleventyConfig.addPlugin(eleventyPostCssBuildPlugin, {outputDir: 'dist/css', inputDir: 'style'}); + * // ... + * } + * ``` + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function eleventyPostCssBuildPlugin(eleventyConfig: any, options: EleventyPostCssPluginOptions): void { + // TODO: better event handling to just copy for the first time + + const configureBuilding = postcssBuild({ + inputDir: options.inputDir, + outputDir: options.outputDir, + }); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + eleventyConfig.on('eleventy.after', configureBuilding); +} + diff --git a/packages/eleventy-config/src/lib/workbox.ts b/packages/eleventy-config/src/lib/workbox.ts index 0488c1f..54540ae 100644 --- a/packages/eleventy-config/src/lib/workbox.ts +++ b/packages/eleventy-config/src/lib/workbox.ts @@ -3,29 +3,32 @@ import { logger } from './logger.js'; import { platformInfo } from '@alwatr/platform-info'; import { writeFile } from 'fs/promises'; -const deploymentServiceWorkerContent = "console.log('service worker not build in deployment.')"; -const serviceWorkerDest = 'dist/service-worker.js'; - -export async function generateServiceWorker(): Promise { +export async function generateServiceWorker(options:{ + outputDir: string, + deploymentServiceWorkerContent: string, + nameOfServiceWorker: string, + maximumFileSize: number, + mode: 'production' | 'development', +}): Promise { const isDevelopment = platformInfo.development; logger.logMethodArgs?.('generateServiceWorker', { isDevelopment }); if (isDevelopment) { - await writeFile(serviceWorkerDest, deploymentServiceWorkerContent); + await writeFile(options.outputDir + options.nameOfServiceWorker, options.deploymentServiceWorkerContent); return null; } const buildResult = await generateSW({ - globDirectory: 'dist', - maximumFileSizeToCacheInBytes: 1 * 1024 * 1024, // 1MB + globDirectory: options.outputDir, + maximumFileSizeToCacheInBytes: options.maximumFileSize, cleanupOutdatedCaches: true, inlineWorkboxRuntime: false, clientsClaim: true, skipWaiting: true, globPatterns: [ '**/*.{woff,woff2,js,css,webmanifest,html}', 'index.html', 'favicon.ico' ], - swDest: serviceWorkerDest, + swDest: options.outputDir + options.nameOfServiceWorker, sourcemap: false, - mode: 'production', + mode: options.mode, runtimeCaching: [ { urlPattern: /\.(?:png|jpg|jpeg|svg|gif)$/, @@ -69,3 +72,73 @@ export async function generateServiceWorker(): Promise { logger.logOther?.(`Generated a service worker, which will pre-cache ${count} files, totaling ${preCacheSize}kb.`); return buildResult; } + +/** + * Options for the eleventyCopyFontPlugin. + */ +export type EleventyWorkBoxPluginOptions = { + /** + * The output directory for the service worker. + */ + outputDir: string; + + /** + * The content for the deployment service worker. + */ + deploymentServiceWorkerContent: string, + + /** + * The name of the service worker. + */ + nameOfServiceWorker: string, + + /** + * The maximum file size for the service worker. + */ + maximumFileSize: number, + + /** + * The mode for the service worker. + */ + mode: 'production' | 'development', +}; + +/** + * Eleventy plugin for minifying HTML content. + * + * @param eleventyConfig - The Eleventy configuration object. + * @param options - The options for the plugin. + * + * @example + * ```js + * // eleventy.config.mjs + * + * import {eleventyWorkBoxPlugin} from '@nexim/eleventy-config'; + * + * export default function (eleventyConfig) { + * eleventyConfig.addPlugin(eleventyWorkBoxPlugin, { + * outputDir: 'dist', + * deploymentServiceWorkerContent: "console.log('service worker not build in deployment.')", + * nameOfServiceWorker: 'service-worker.js', + * maximumFileSize: 1 * 1024 * 1024, // 1MB, + * mode: 'production', + * }); + * // ... + * } + * ``` + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function eleventyWorkBoxPlugin(eleventyConfig: any, options: EleventyWorkBoxPluginOptions): void { + // TODO: better event handling to just copy for the first time + + const generateServiceWorkerWithOptions = generateServiceWorker({ + outputDir: options.outputDir, + deploymentServiceWorkerContent: options.deploymentServiceWorkerContent, + nameOfServiceWorker: options.nameOfServiceWorker, + maximumFileSize: options.maximumFileSize, + mode: options.mode, + }); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + eleventyConfig.on('eleventy.after', generateServiceWorkerWithOptions); +}