ci: add log level option to css bundler plugin

This commit is contained in:
Julien Oculi 2024-02-06 10:22:30 +01:00
parent 4e7e7b05c7
commit 9415d50564
6 changed files with 53 additions and 18 deletions

View file

@ -3,6 +3,6 @@ import { cssBundler } from './plugins/css_bundler/plugin.ts'
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
cssBundler(import.meta.resolve('./src/stylesheets')), cssBundler(import.meta.resolve('./src/stylesheets'), { logLevel: 'error' }),
], ],
}) })

View file

@ -1,13 +1,24 @@
import { Plugin } from '$fresh/server.ts' import { Plugin } from '$fresh/server.ts'
import { fromFileUrl } from '$std/path/mod.ts' import { fromFileUrl } from '$std/path/mod.ts'
import { bundleCss } from './src/bundler.ts' import { bundleCss } from './src/bundler.ts'
import { Logger } from './src/helpers.ts'
import { cssHandler } from './src/middleware.ts' import { cssHandler } from './src/middleware.ts'
export function cssBundler(sourceDir: string, pattern = /main.css/): Plugin { export function cssBundler(
sourceDir: string,
{ pattern = /main.css/, logLevel }: {
pattern?: RegExp
logLevel?: 'disabled' | 'info' | 'error'
},
): Plugin {
const logger = new Logger({
logLevel: logLevel === 'info' ? 2 : logLevel === 'error' ? 1 : 0,
})
return { return {
name: 'css_bundler', name: 'css_bundler',
middlewares: [{ middlewares: [{
middleware: { handler: cssHandler(sourceDir) }, middleware: { handler: cssHandler(sourceDir, logger) },
path: '/', path: '/',
}], }],
async buildStart(config) { async buildStart(config) {
@ -18,7 +29,9 @@ export function cssBundler(sourceDir: string, pattern = /main.css/): Plugin {
//Get all source stylesheets //Get all source stylesheets
for await (const entry of Deno.readDir(fromFileUrl(sourceDir))) { for await (const entry of Deno.readDir(fromFileUrl(sourceDir))) {
if (entry.isFile && entry.name.match(pattern)) { if (entry.isFile && entry.name.match(pattern)) {
tasks.push(bundleCss(sourceDir, outDir, entry.name, config.dev)) tasks.push(
bundleCss(sourceDir, outDir, entry.name, config.dev, logger),
)
} }
} }

View file

@ -3,11 +3,12 @@ import { bundleAsync } from 'lightningcss'
import { cssImports, cssUrls, Logger, uInt8ArrayConcat } from './helpers.ts' import { cssImports, cssUrls, Logger, uInt8ArrayConcat } from './helpers.ts'
export async function builder( export async function builder(
{ filename, dev, assetDir, remote }: { { filename, dev, assetDir, remote, logger }: {
filename: string filename: string
dev: boolean dev: boolean
assetDir: string assetDir: string
remote?: string remote?: string
logger: Logger
}, },
) { ) {
const { code, map } = await bundleAsync({ const { code, map } = await bundleAsync({
@ -22,13 +23,13 @@ export async function builder(
if (pathOrUrl.startsWith('https://')) { if (pathOrUrl.startsWith('https://')) {
//use cache for remote //use cache for remote
if (cssImports.has(pathOrUrl)) { if (cssImports.has(pathOrUrl)) {
Logger.info('using cache for', `${pathOrUrl}`) logger.info('using cache for', `${pathOrUrl}`)
const filepath = cssImports.get(pathOrUrl)! const filepath = cssImports.get(pathOrUrl)!
return Deno.readTextFile(filepath) return Deno.readTextFile(filepath)
} }
//update cache for new remote //update cache for new remote
Logger.info('fetching and caching', `${pathOrUrl}`) logger.info('fetching and caching', `${pathOrUrl}`)
const response = await fetch(pathOrUrl) const response = await fetch(pathOrUrl)
const file = await response.arrayBuffer() const file = await response.arrayBuffer()
const filename = encodeURIComponent(pathOrUrl.toString()) const filename = encodeURIComponent(pathOrUrl.toString())
@ -42,6 +43,7 @@ export async function builder(
dev, dev,
assetDir, assetDir,
remote: pathOrUrl, remote: pathOrUrl,
logger,
}) })
if (map) { if (map) {
@ -66,21 +68,21 @@ export async function builder(
resolve(specifier, from) { resolve(specifier, from) {
if (remote) { if (remote) {
const url = new URL(specifier, remote) const url = new URL(specifier, remote)
Logger.info('resolve remote imports', url.toString()) logger.info('resolve remote imports', url.toString())
return url.toString() return url.toString()
} }
//resolve local files normally //resolve local files normally
if (!specifier.startsWith('https://') && !from.startsWith('https://')) { if (!specifier.startsWith('https://') && !from.startsWith('https://')) {
Logger.info('resolve local file', specifier) logger.info('resolve local file', specifier)
return resolve(parse(from).dir, specifier) return resolve(parse(from).dir, specifier)
} }
//construct asset url //construct asset url
const baseUrl = from.startsWith('https://') ? from : toFileUrl(from) const baseUrl = from.startsWith('https://') ? from : toFileUrl(from)
const url = new URL(specifier, baseUrl) const url = new URL(specifier, baseUrl)
Logger.info('resolve remote file', url.toString()) logger.info('resolve remote file', url.toString())
return url.toString() return url.toString()
}, },

View file

@ -7,15 +7,16 @@ export async function bundleCss(
assetDir: string, assetDir: string,
pathname: string, pathname: string,
dev: boolean, dev: boolean,
logger: Logger,
) { ) {
const filename = fromFileUrl(join(sourceDir, pathname)) const filename = fromFileUrl(join(sourceDir, pathname))
Logger.info('bundling', filename) logger.info('bundling', filename)
//prevent Deno from exiting before bundle //prevent Deno from exiting before bundle
setTimeout(() => {}, 3_000) setTimeout(() => {}, 3_000)
try { try {
const { code, map } = await builder({ filename, dev, assetDir }) const { code, map } = await builder({ filename, dev, assetDir, logger })
if (map) { if (map) {
//# sourceMappingURL=fresh_dev_client.js.map //# sourceMappingURL=fresh_dev_client.js.map
@ -35,7 +36,7 @@ export async function bundleCss(
await Deno.writeFile(join(assetDir, pathname), code) await Deno.writeFile(join(assetDir, pathname), code)
} }
} catch (error) { } catch (error) {
Logger.error('error during bundle, cleaning cache', error) logger.error('error during bundle, cleaning cache', error)
cssImports.clear() cssImports.clear()
} }
} }

View file

@ -1,7 +1,14 @@
export class Logger { export class Logger {
static readonly #name = 'bundle_css' readonly #name = 'bundle_css'
#logLevel: 0 | 1 | 2
constructor({ logLevel }: { logLevel: 0 | 1 | 2 }) {
this.#logLevel = logLevel
}
info(message: string, path?: string) {
if (this.#logLevel < 2) return
static info(message: string, path?: string) {
console.log( console.log(
`%c[${this.#name}]%c ${message} %c${path ?? ''}`, `%c[${this.#name}]%c ${message} %c${path ?? ''}`,
'color: blue; font-weight: bold', 'color: blue; font-weight: bold',
@ -10,7 +17,9 @@ export class Logger {
) )
} }
static error(message: string, error?: Error) { error(message: string, error?: Error) {
if (this.#logLevel < 1) return
console.error( console.error(
`%c[${this.#name}]%c ${message} %c${error?.toString() ?? ''}`, `%c[${this.#name}]%c ${message} %c${error?.toString() ?? ''}`,
'color: red; font-weight: bold', 'color: red; font-weight: bold',

View file

@ -3,8 +3,12 @@ import { contentType } from '$fresh/src/server/deps.ts'
import { ensureDir } from '$std/fs/ensure_dir.ts' import { ensureDir } from '$std/fs/ensure_dir.ts'
import { join, parse } from '$std/path/mod.ts' import { join, parse } from '$std/path/mod.ts'
import { bundleCss } from './bundler.ts' import { bundleCss } from './bundler.ts'
import { Logger } from './helpers.ts'
export function cssHandler(sourceDir: string): MiddlewareHandler { export function cssHandler(
sourceDir: string,
logger: Logger,
): MiddlewareHandler {
return async (_, ctx) => { return async (_, ctx) => {
const assetDir = join(ctx.config.build.outDir, '/static') const assetDir = join(ctx.config.build.outDir, '/static')
await ensureDir(assetDir) await ensureDir(assetDir)
@ -24,7 +28,13 @@ export function cssHandler(sourceDir: string): MiddlewareHandler {
}) })
} }
await bundleCss(sourceDir, assetDir, ctx.url.pathname, ctx.config.dev) await bundleCss(
sourceDir,
assetDir,
ctx.url.pathname,
ctx.config.dev,
logger,
)
const file = await Deno.readFile(filename) const file = await Deno.readFile(filename)
return new Response(file, { return new Response(file, {
headers: { headers: {