137 lines
3.4 KiB
JavaScript
137 lines
3.4 KiB
JavaScript
|
const { SourceMapGenerator } = require('source-map')
|
||
|
const path = require('path')
|
||
|
const { createHash } = require('crypto')
|
||
|
|
||
|
const markdownExtensions = [
|
||
|
'md',
|
||
|
'markdown',
|
||
|
'mdown',
|
||
|
'mkdn',
|
||
|
'mkd',
|
||
|
'mdwn',
|
||
|
'mkdown',
|
||
|
'ron',
|
||
|
]
|
||
|
const mdx = ['.mdx']
|
||
|
const md = markdownExtensions.map((/** @type {string} */ d) => '.' + d)
|
||
|
|
||
|
const own = {}.hasOwnProperty
|
||
|
|
||
|
const marker = {}
|
||
|
const cache = new WeakMap()
|
||
|
|
||
|
/**
|
||
|
* A webpack loader for mdx-rs. This is largely based on existing @mdx-js/loader,
|
||
|
* replaces internal compilation logic to use mdx-rs instead.
|
||
|
*/
|
||
|
function loader(value, bindings, callback) {
|
||
|
const defaults = this.sourceMap ? { SourceMapGenerator } : {}
|
||
|
const options = this.getOptions()
|
||
|
const config = { ...defaults, ...options }
|
||
|
const hash = getOptionsHash(options)
|
||
|
const compiler = this._compiler || marker
|
||
|
|
||
|
let map = cache.get(compiler)
|
||
|
|
||
|
if (!map) {
|
||
|
map = new Map()
|
||
|
cache.set(compiler, map)
|
||
|
}
|
||
|
|
||
|
let process = map.get(hash)
|
||
|
|
||
|
if (!process) {
|
||
|
process = createFormatAwareProcessors(bindings, config).compile
|
||
|
map.set(hash, process)
|
||
|
}
|
||
|
|
||
|
process({ value, path: this.resourcePath }).then(
|
||
|
(code) => {
|
||
|
// TODO: no sourcemap
|
||
|
callback(null, code, null)
|
||
|
},
|
||
|
(error) => {
|
||
|
const fpath = path.relative(this.context, this.resourcePath)
|
||
|
error.message = `${fpath}:${error.name}: ${error.message}`
|
||
|
callback(error)
|
||
|
}
|
||
|
)
|
||
|
}
|
||
|
|
||
|
function getOptionsHash(options) {
|
||
|
const hash = createHash('sha256')
|
||
|
let key
|
||
|
|
||
|
for (key in options) {
|
||
|
if (own.call(options, key)) {
|
||
|
const value = options[key]
|
||
|
|
||
|
if (value !== undefined) {
|
||
|
const valueString = JSON.stringify(value)
|
||
|
hash.update(key + valueString)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hash.digest('hex').slice(0, 16)
|
||
|
}
|
||
|
|
||
|
function createFormatAwareProcessors(bindings, compileOptions = {}) {
|
||
|
const mdExtensions = compileOptions.mdExtensions || md
|
||
|
const mdxExtensions = compileOptions.mdxExtensions || mdx
|
||
|
|
||
|
let cachedMarkdown
|
||
|
let cachedMdx
|
||
|
|
||
|
return {
|
||
|
extnames:
|
||
|
compileOptions.format === 'md'
|
||
|
? mdExtensions
|
||
|
: compileOptions.format === 'mdx'
|
||
|
? mdxExtensions
|
||
|
: mdExtensions.concat(mdxExtensions),
|
||
|
compile,
|
||
|
}
|
||
|
|
||
|
function compile({ value, path: p }) {
|
||
|
const format =
|
||
|
compileOptions.format === 'md' || compileOptions.format === 'mdx'
|
||
|
? compileOptions.format
|
||
|
: path.extname(p) &&
|
||
|
(compileOptions.mdExtensions || md).includes(path.extname(p))
|
||
|
? 'md'
|
||
|
: 'mdx'
|
||
|
|
||
|
const options = {
|
||
|
parse: compileOptions.parse,
|
||
|
development: compileOptions.development,
|
||
|
providerImportSource: compileOptions.providerImportSource,
|
||
|
jsx: compileOptions.jsx,
|
||
|
jsxRuntime: compileOptions.jsxRuntime,
|
||
|
jsxImportSource: compileOptions.jsxImportSource,
|
||
|
pragma: compileOptions.pragma,
|
||
|
pragmaFrag: compileOptions.pragmaFrag,
|
||
|
pragmaImportSource: compileOptions.pragmaImportSource,
|
||
|
filepath: p,
|
||
|
}
|
||
|
|
||
|
const compileMdx = (input) => bindings.mdx.compile(input, options)
|
||
|
|
||
|
const processor =
|
||
|
format === 'md'
|
||
|
? cachedMarkdown || (cachedMarkdown = compileMdx)
|
||
|
: cachedMdx || (cachedMdx = compileMdx)
|
||
|
|
||
|
return processor(value)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = function (code) {
|
||
|
const callback = this.async()
|
||
|
const { loadBindings } = require('next/dist/build/swc')
|
||
|
|
||
|
loadBindings().then((bindings) => {
|
||
|
return loader.call(this, code, bindings, callback)
|
||
|
})
|
||
|
}
|