Skip to content

Commit

Permalink
Patch createRequire() and loadConfig() to handle builtin modules in t…
Browse files Browse the repository at this point in the history
…he standalone CLI

Fix code style
  • Loading branch information
thecrypticace committed Dec 1, 2023
1 parent 317fba1 commit 32b4a67
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 8 deletions.
8 changes: 8 additions & 0 deletions src/lib/load-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ import { transform } from 'sucrase'
import { Config } from '../../types/config'

let jiti: ReturnType<typeof jitiFactory> | null = null

// @internal
// This WILL be removed in some future release
// If you rely on this your stuff WILL break
export function useCustomJiti(_jiti: ReturnType<typeof jitiFactory>) {
jiti = _jiti
}

function lazyJiti() {
return (
jiti ??
Expand Down
50 changes: 50 additions & 0 deletions standalone-cli/patch-require.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const Module = require('node:module')

/**
* @param {Record<string, any>} mods
*/
module.exports.patchRequire = function patchRequire(mods, parentCache) {
function wrapRequire(origRequire) {
return Object.assign(
function (id) {
// Patch require(…) to return the cached module
if (mods.hasOwnProperty(id)) {
return mods[id]
}

return origRequire.apply(this, arguments)
},

// Make sure we carry over other properties of the original require(…)
origRequire,

{
resolve(id) {
// Defer to the "parent" require cache when resolving the module
// This also requires that the module be provided as a "native module" to JITI

// The path returned here is VERY important as it ensures that the `isNativeRe` in JITI
// passes which is required for the module to be loaded via the native require(…) function
// Thankfully, the regex just means that it needs to be in a node_modules folder which is true
// even when bundled using Vercel's `pkg`
if (parentCache.hasOwnProperty(id)) {
return parentCache[id].filename
}

return origRequire.resolve.apply(this, arguments)
},
}
)
}

let origRequire = Module.prototype.require
let origCreateRequire = Module.createRequire

// We have to augment the default "require" in every module
Module.prototype.require = wrapRequire(origRequire)

// And any "require" created by the "createRequire" method
Module.createRequire = function () {
return wrapRequire(origCreateRequire.apply(this, arguments))
}
}
41 changes: 33 additions & 8 deletions standalone-cli/standalone.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
let Module = require('module')
let origRequire = Module.prototype.require
let log = require('tailwindcss/lib/util/log').default

let localModules = {
Expand All @@ -25,11 +23,38 @@ let localModules = {
tailwindcss: require('tailwindcss'),
}

Module.prototype.require = function (id) {
if (localModules.hasOwnProperty(id)) {
return localModules[id]
}
return origRequire.apply(this, arguments)
}
// Swap out the default JITI implementation with one that has the built-in modules above preloaded as "native modules"
// NOTE: This uses a private, internal API of Tailwind CSS and is subject to change at any time
let { useCustomJiti } = require('tailwindcss/lib/lib/load-config')
let { transform } = require('sucrase')

useCustomJiti(() =>
require('jiti')(__filename, {
interopDefault: true,
nativeModules: Object.keys(localModules),
transform: (opts) => {
return transform(opts.source, {
transforms: ['typescript', 'imports'],
})
},
})
)

let { patchRequire } = require('./patch-require.js')
patchRequire(
// Patch require(…) to return the bundled modules above so they don't need to be installed
localModules,

// Create a require cache that maps module IDs to module objects
// This MUST be done before require is patched to handle caching
Object.fromEntries(
Object.keys(localModules).map((id) => [
id,
id === '@tailwindcss/line-clamp'
? `node_modules/@tailwindcss/line-clamp/`
: require.cache[require.resolve(id)],
])
)
)

require('tailwindcss/lib/cli')

0 comments on commit 32b4a67

Please sign in to comment.