Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run script before MDX Bundler runs #74

Open
deadcoder0904 opened this issue Jul 28, 2021 · 5 comments
Open

Run script before MDX Bundler runs #74

deadcoder0904 opened this issue Jul 28, 2021 · 5 comments

Comments

@deadcoder0904
Copy link

  • mdx-bundler version: ^5.1.0
  • node version: v16.3.0
  • npm version: 7.15.1

Relevant code or config

I have a gif-to-png.js script that converts GIFs to PNG in development in the src/_posts directory. As to why I use it, I have written about it here.

TL;DR I'm creating a GIF Player that shows static PNG images when someone pauses a GIF & play button to play the GIF because I hate to see GIF loop while reading text.

gif-to-png.js

const fs = require('fs')
const path = require('path')
const sharp = require('sharp')
const fg = require('fast-glob')

const ROOT_PATH = process.cwd()
const POSTS_PATH = path.join(ROOT_PATH, 'src/_posts')

function* walkSync(dir) {
	const files = fs.readdirSync(dir, { withFileTypes: true })
	for (let i = 0; i < files.length; i++) {
		if (files[i].isDirectory()) {
			yield* walkSync(path.join(dir, files[i].name))
		} else {
			yield path.join(dir, files[i].name)
		}
	}
}

const gifToPng = async () => {
	try {
		for (let [i, file] of [...walkSync(POSTS_PATH)].entries()) {
			const extname = path.extname(file)
			if (extname === '.gif') {
				const dirname = path.dirname(file)
				const png = path.resolve(dirname, path.basename(file).replace('.gif', '.png'))
				await sharp(file).png().toFile(png)
			}
		}
	} catch (e) {
		console.error('Error thrown:', e)
	}
}

gifToPng()

What you did:

This makes a copy of PNG in src/_posts folder appropriately by converting the GIF file.

What happened:

It doesn't copy the PNG file to the appropriate location as mdx-bundler probably runs earlier than this.

Reproduction repository:

https://github.com/deadcoder0904/mdx-bundler-gif-png-error

Problem description:

I just want those PNG files in public/ directory. Is there any way to run the scripts before mdx-bundler?

Suggested solution:

No idea. I did try running the script in public directory instead of src/_posts so it renames there but it didn't work.

@Arcath
Copy link
Collaborator

Arcath commented Jul 28, 2021

Looking at it this seems like something an esbuild plugin could do. You could then pass the plugin into mdx-bundler so it can generate the file at the same time.

@deadcoder0904
Copy link
Author

@Arcath just to be clear, do I have to write an esbuild-plugin or remark / rehype plugin?

I already converted the code:

import fs from 'fs'
import path from 'path'
import sharp from 'sharp'
import { Plugin } from 'esbuild'

const ROOT_PATH = process.cwd()
const POSTS_PATH = path.join(ROOT_PATH, 'public')

function* walkSync(dir: fs.PathLike): any {
	const files = fs.readdirSync(dir, { withFileTypes: true })
	for (let i = 0; i < files.length; i++) {
		if (files[i].isDirectory()) {
			yield* walkSync(path.join(dir as string, files[i].name))
		} else {
			yield path.join(dir as string, files[i].name)
		}
	}
}

const gifToPng = async () => {
	try {
		for (let [i, file] of [...walkSync(POSTS_PATH)].entries()) {
			const extname = path.extname(file)
			if (extname === '.gif') {
				console.log(file)
				const dirname = path.dirname(file)
				const png = path.resolve(dirname, path.basename(file).replace('.gif', '.png'))
				await sharp(file).png().toFile(png)
			}
		}
	} catch (e) {
		console.error('Error thrown:', e)
	}
}

export const gifToPngPlugin = (): Plugin => ({
	name: 'gifToPng',
	setup(build) {
		build.onLoad({ filter: /\.gif$/ }, async (args) => {
			const fileName = path.basename(args.path, '.gif')
			let contents = await fs.promises.readFile(args.path, 'utf8')
			console.log({ fileName, contents })

			return {
				contents,
				loader: 'file',
			}
		})
	},
})

And I'm trying to write the plugin but getting an error:

❯ npx esbuild .\src\utils\gif-to-png.ts --platform=node --bundle
node_modules/sharp/lib/utility.js:7:22: error: No loader is configured for ".node" files: node_modules/sharp/build/Release/sharp.node
7 │ const sharp = require('../build/Release/sharp.node');
╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Not sure if ESBuild can run extensions with .node?

@Arcath
Copy link
Collaborator

Arcath commented Jul 31, 2021

it would need to be a esbuild plugin that has a filter of *.gif and then applies your script to it.

@deadcoder0904
Copy link
Author

@Arcath i've already read it. that's where I got this issue from. the issue isn't .gif but of .node as sharp uses that in my code.

see .gif exists in my script but the first line of code is require('sharp') which fails because it internally calls .node. hence, my question, can ESBuild run extensions with .node?

@deadcoder0904
Copy link
Author

oops, found this :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants