Skip to content

[BUG] Error: Could not resolve module "node:module" in jiti after upgrading to Tailwind v4 in Plasmo #1188

Open

Description

@peguimasid

Description

After upgrading to Tailwind v4 using npx @tailwindcss/upgrade@next, the Plasmo build fails with the following error:

🔴 ERROR | Build failed. To debug, run plasmo dev --verbose.
🔴 ERROR | Could not resolve module "node:module" from "/Users/guilhermomasid/Documents/trash/plasmo-tailwind/node_modules/.pnpm/jiti@2.4.2/node_modules/jiti/lib/jiti.cjs"

Steps to Reproduce

  1. Create a new Plasmo extension with TailwindCSS using:
pnpm create plasmo --with-tailwindcss  
  1. Upgrade Tailwind to v4 using:
npx @tailwindcss/upgrade@next 
  1. Run the Plasmo dev server:
pnpm dev  
  1. The build fails with the above error.

Repository

I have created a repository to reproduce the issue: plasmo-tailwind-v4-bug

  • The main branch contains the unmodified Plasmo Tailwind example.
  • The feat/tailwind-v4 branch contains the project after the Tailwind v4 upgrade.
  • A pull request comparing the changes is available here: PR #1.

Expected Behavior

The project should build successfully after upgrading to Tailwind v4.

Actual Behavior

The build fails with a module resolution error related to jiti@2.4.2.

Environment

  • TailwindCSS v4
  • Jiti v2.4.2
  • Node.js version: v22.13.1
  • Package manager: pnpm

Additional Notes

This issue seems related to jiti@2.4.2 and its inability to resolve the node:module package. Any insights or workarounds would be greatly appreciated.

Version

Latest

What OS are you seeing the problem on?

MacOSX

What browsers are you seeing the problem on?

Chrome

Relevant log output

p dev

> plasmo-tailwind@0.0.1 dev /Users/guilhermomasid/Documents/trash/plasmo-tailwind
> plasmo dev

🟣 Plasmo v0.90.2
🔴 The Browser Extension Framework
🔵 INFO   | Starting the extension development server...
🔵 INFO   | Building for target: chrome-mv3
🔵 INFO   | Loaded environment variables from: []
(node:59554) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
🔴 ERROR  | Build failed. To debug, run plasmo dev --verbose.
🔴 ERROR  | Could not resolve module "node:module" from "/Users/guilhermomasid/Documents/trash/plasmo-tailwind/node\_modules/.pnpm/jiti@2.4.2/node\_modules/jiti/lib/jiti.cjs"

(OPTIONAL) Contribution

  • I would like to fix this BUG via a PR

Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I checked the current issues for duplicate problems.

Activity

  1. thekayshawn commented on Feb 17, 2025

    @thekayshawn

    +1 on this, got a monorepo setup with 4 apps using the same shared design system with tailwind v4, have to make the PR wait until this gets resolved otherwise our extension will break.

  2. Jemeni11 commented on Feb 17, 2025

    @Jemeni11

    Same here ✋

  3. BalutaAlex commented on Feb 17, 2025

    @BalutaAlex
    Contributor

    Probably related to parcel-bundler/parcel#9244. The issue has been fixed in newer parcel versions it seems so we should get forward with updating to a newer parcel version

  4. shinauri commented on Mar 6, 2025

    @shinauri

    Has anyone been able to solve the problem?

  5. Xheldon commented on Mar 7, 2025

    @Xheldon

    Has anyone been able to solve the problem?

  6. ctrhub commented on Mar 7, 2025

    @ctrhub

    Fixed this issue by downgrading these packages to the following versions:

    "dependencies": {
        "plasmo": "0.90.3",
        "react": "18.2.0",
        "react-dom": "18.2.0",
        "tailwind-merge": "2.5.5",
        "tailwindcss-animate": "1.0.7"
      },
      "devDependencies": {
        "@ianvs/prettier-plugin-sort-imports": "4.1.1",
        "@types/chrome": "0.0.258",
        "@types/node": "20.11.5",
        "@types/react": "18.2.48",
        "@types/react-dom": "18.2.18",
        "autoprefixer": "10.4.20",
        "postcss": "8.4.49",
        "prettier": "3.2.4",
        "tailwindcss": "3.4.17",
        "typescript": "5.3.3"
      },

    Also created postcss.config.js in the root folder:

    export default {
      plugins: {
        tailwindcss: {},
        autoprefixer: {},
      },
    }

    And created globals.css in the root folder:

    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    @layer base {
      :root {
        --background: 0 0% 100%;
      }
      .dark {
        --background: 0 0% 4%;
      }
    }
    @layer base {
      * {
        @apply border-border;
      }
      body {
        @apply antialiased bg-background text-foreground;
        font-family: var(--font-geist-sans);
      }
    }
  7. peguimasid commented on Mar 7, 2025

    @peguimasid
    Author

    @ctrhub The issue here is specifically related to upgrading Tailwind to version 4. The code you provided is using Tailwind version 3, which currently works fine with Plasmo.

  8. ObinnaAka commented on Mar 18, 2025

    @ObinnaAka

    So I found a hacky way around it. You can go into your node_modules folder and look for the file at ...node\_modules/@tailwindcss/node/node\_modules/jiti/dist/jiti.cjs

    You want to manually remove the node:... prefix. You'll need to do this about a dozen more times throughout the node package.

    This is a naming convention in recent node versions. I'm working to find a more permanent/reasonable solution (probably involving an alias is my guess)

  9. ObinnaAka commented on Mar 18, 2025

    @ObinnaAka

    Got the answer. You have to patch the package (for now)

    In my case, I use bun.sh, so:

    bun patch jiti@2.4.2

    but with npm, it would be

    npm install --save-dev patch-package postinstall-postinstall
    
    # After manually making your change to node_modules
    npx patch-package @tailwindcss/node
    

    And then you want to manually go into your node modules and perform the steps above: find the references to "node:modules" that are mentioned in the error message and replace it with "modules".

    You'll need to do it for some other "node:... references as well. Just follow the plasmo console error message.

    Hopefully we get a better fix soon.

  10. shawnlikescode commented on Mar 19, 2025

    @shawnlikescode

    Got the answer. You have to patch the package (for now)

    In my case, I use bun.sh, so:

    bun patch jiti@2.4.2

    but with npm, it would be

    npm install --save-dev patch-package postinstall-postinstall
    
    # After manually making your change to node_modules
    npx patch-package @tailwindcss/node
    

    And then you want to manually go into your node modules and perform the steps above: find the references to "node:modules" that are mentioned in the error message and replace it with "modules".

    You'll need to do it for some other "node:... references as well. Just follow the plasmo console error message.

    Hopefully we get a better fix soon.

    I can't find the file you're talking about. Can you explain some more?

  11. ObinnaAka commented on Mar 19, 2025

    @ObinnaAka

    All good! I'll go in depth.

    So for example, the original post had this error

    🔴 ERROR | Build failed. To debug, run plasmo dev --verbose.
    🔴 ERROR | Could not resolve module "node:module" from "/Users/guilhermomasid/Documents/trash/plasmo-tailwind/node_modules/.pnpm/jiti@2.4.2/node_modules/jiti/lib/jiti.cjs"
    

    You want to go to the file at this path (replace it with your own path)

    /Users/ ...<your own path>... /node_modules/.pnpm/jiti@2.4.2/node_modules/jiti/lib/jiti.cjs

    And then you want to search for "node:modules" inside the file, and replace it with "modules"

    You will need to repeat this with other similar import like
    "node:os"
    "node:fs"
    "node:..."

    Make sure your plasmo dev server keeps running when you do this. The error message will tell you what file needs to be changed next. Once you've changed all the references, then your extension should build!

    After that, then you can follow the instructions above to patch you package.json

    Hope this helps!

    Got the answer. You have to patch the package (for now)

    In my case, I use bun.sh, so:

    bun patch jiti@2.4.2

    but with npm, it would be

    npm install --save-dev patch-package postinstall-postinstall
    
    # After manually making your change to node_modules
    npx patch-package @tailwindcss/node
    

    And then you want to manually go into your node modules and perform the steps above: find the references to "node:modules" that are mentioned in the error message and replace it with "modules".

    You'll need to do it for some other "node:... references as well. Just follow the plasmo console error message.

    Hopefully we get a better fix soon.

  12. shawnlikescode commented on Mar 19, 2025

    @shawnlikescode

    All good! I'll go in depth.

    So for example, the original post had this error

    🔴 ERROR | Build failed. To debug, run plasmo dev --verbose.
    🔴 ERROR | Could not resolve module "node:module" from "/Users/guilhermomasid/Documents/trash/plasmo-tailwind/node_modules/.pnpm/jiti@2.4.2/node_modules/jiti/lib/jiti.cjs"
    

    You want to go to the file at this path (replace it with your own path)

    /Users/ ...<your own path>... /node_modules/.pnpm/jiti@2.4.2/node_modules/jiti/lib/jiti.cjs

    And then you want to search for "node:modules" inside the file, and replace it with "modules"

    You will need to repeat this with other similar import like "node:os" "node:fs" "node:..."

    Make sure your plasmo dev server keeps running when you do this. The error message will tell you what file needs to be changed next. Once you've changed all the references, then your extension should build!

    After that, then you can follow the instructions above to patch you package.json

    Hope this helps!

    Got the answer. You have to patch the package (for now)
    In my case, I use bun.sh, so:
    bun patch jiti@2.4.2
    but with npm, it would be

    npm install --save-dev patch-package postinstall-postinstall
    
    # After manually making your change to node_modules
    npx patch-package @tailwindcss/node
    

    And then you want to manually go into your node modules and perform the steps above: find the references to "node:modules" that are mentioned in the error message and replace it with "modules".
    You'll need to do it for some other "node:... references as well. Just follow the plasmo console error message.
    Hopefully we get a better fix soon.

    Thank you!

    Can you share one of the edits?

    I tried I still get an error in the file.

    🔴 ERROR | Build failed. To debug, run plasmo dev --verbose.
    🔴 ERROR | Could not resolve module "modules" from "*/node_modules/.pnpm/jiti@2.4.2/node_modules/jiti/lib/jiti.cjs"

    // original const { createRequire } = require("node:module");
    const { createRequire } = require("modules");
    const _createJiti = require("../dist/jiti.cjs");
    const transform = require("../dist/babel.cjs");
    
    function onError(err) {
      throw err; /* ↓ Check stack trace ↓ */
    }
    
    const nativeImport = (id) => import(id);
    
    function createJiti(id, opts = {}) {
      if (!opts.transform) {
        opts = { ...opts, transform };
      }
      return _createJiti(id, opts, {
        onError,
        nativeImport,
        createRequire,
      });
    }
    
    module.exports = createJiti;
    module.exports.createJiti = createJiti;
  13. ObinnaAka commented on Mar 19, 2025

    @ObinnaAka

    Oh, stop and restart your dev server each time. Apologies, I should have clarified.

    I don't think Parcel picks up changes in the node_modules folder without a restart

  14. 5 remaining items

  15. tinacious commented on Apr 13, 2025

    @tinacious

    Got the answer. You have to patch the package (for now)

    In my case, I use bun.sh, so:

    bun patch jiti@2.4.2

    but with npm, it would be

    npm install --save-dev patch-package postinstall-postinstall
    
    # After manually making your change to node_modules
    npx patch-package @tailwindcss/node
    

    And then you want to manually go into your node modules and perform the steps above: find the references to "node:modules" that are mentioned in the error message and replace it with "modules".

    You'll need to do it for some other "node:... references as well. Just follow the plasmo console error message.

    Hopefully we get a better fix soon.

    Thanks @ObinnaAka for this! I am using pnpm and did the following:

    1. Ran pnpm patch jiti@2.4.2.
    2. In the patch code that pnpm created for me at node_modules/.pnpm_patches/jiti@2.4.2, I did a find and replace, finding all "node: and replacing with " (so as to remove the node: as suggested).
    3. Committed the patch with pnpm patch-commit node_modules/.pnpm_patches/jiti@2.4.2.

    Works great, thanks! I appreciate you taking the time to share your fix.

  16. constantx commented on Apr 23, 2025

    @constantx

    The patch approach is not very sustainable, nor working in my case. Any plan to support tailwind v4?

  17. vantezzen commented on Apr 24, 2025

    @vantezzen
    Contributor

    For anyone unfamiliar with patching in pnpm, here's a more detailed guide for Plasmo and Tailwind 4: https://gist.github.com/vantezzen/f799643aebbfd5522ce87bababb85c5d

  18. added a commit that references this issue on May 3, 2025
  19. Emmanuel-Tyty commented on May 4, 2025

    @Emmanuel-Tyty

    i added this to the tailwind config mode: "jit",

  20. vslowslow commented on Jun 24, 2025

    @vslowslow

    any update on this isse?

  21. coder-xiaotian commented on Jul 1, 2025

    @coder-xiaotian

    same problem

  22. erayerdin commented on Jul 5, 2025

    @erayerdin

    Yep, still the same problem

  23. rowan-fan commented on Sep 27, 2025

    @rowan-fan

    Same problem

  24. architgarg commented on Oct 11, 2025

    @architgarg

    +1

  25. architgarg commented on Oct 11, 2025

    @architgarg

    Based on the comments I ended up writing a script that would patch the files everytime after install. Also helpful if you are sharing code with a team and they need to do the same patch.

    scripts/patch.js:

    #!/usr/bin/env node
    
    /**
     * Plasmo + Tailwind v4 Compatibility Patch
     *
     * Automatically fixes "node:" import issues in jiti and @tailwindcss/oxide
     * that cause Plasmo builds to fail when using Tailwind CSS v4.
     *
     * @see https://github.com/PlasmoHQ/plasmo/issues/1188
     */
    
    const fs = require('fs');
    const path = require('path');
    
    // Console colors
    const c = {
      reset: '\x1b[0m',
      red: '\x1b[31m',
      green: '\x1b[32m',
      yellow: '\x1b[33m',
      blue: '\x1b[34m',
      cyan: '\x1b[36m'
    };
    
    const log = (msg, color = 'reset') => console.log(`${c[color]}${msg}${c.reset}`);
    
    /**
     * Find package files that need patching
     */
    const findPackageFiles = () => {
      const nodeModules = path.resolve('node_modules');
      if (!fs.existsSync(nodeModules)) return [];
    
      const files = [];
      const pnpmPath = path.join(nodeModules, '.pnpm');
    
      // Helper to safely read directory
      const readDir = (dir) => {
        try {
          return fs.existsSync(dir) ? fs.readdirSync(dir) : [];
        } catch {
          return [];
        }
      };
    
      // Helper to check file exists
      const fileExists = (filePath) => {
        try {
          return fs.existsSync(filePath);
        } catch {
          return false;
        }
      };
    
      // Find jiti files
      const findJitiFiles = (basePath) => {
        const jitiPath = path.join(basePath, 'jiti');
        if (!fileExists(jitiPath)) return [];
    
        const targets = [
          'dist/jiti.cjs',
          'dist/babel.cjs',
          'lib/jiti.cjs'
        ];
    
        return targets
          .map(target => path.join(jitiPath, target))
          .filter(fileExists);
      };
    
      // Find oxide files
      const findOxideFiles = (basePath) => {
        const oxidePath = path.join(basePath, '@tailwindcss', 'oxide', 'index.js');
        return fileExists(oxidePath) ? [oxidePath] : [];
      };
    
      // Search pnpm structure
      if (fileExists(pnpmPath)) {
        readDir(pnpmPath).forEach(entry => {
          if (entry.startsWith('jiti@')) {
            const packagePath = path.join(pnpmPath, entry, 'node_modules');
            files.push(...findJitiFiles(packagePath));
          }
    
          if (entry.startsWith('@tailwindcss+oxide@') || entry.startsWith('%40tailwindcss+oxide@')) {
            const packagePath = path.join(pnpmPath, entry, 'node_modules');
            files.push(...findOxideFiles(packagePath));
          }
        });
      }
    
      // Search regular node_modules
      files.push(...findJitiFiles(nodeModules));
      files.push(...findOxideFiles(nodeModules));
    
      return [...new Set(files)]; // Remove duplicates
    };
    
    /**
     * Patch a single file
     */
    const patchFile = (filePath) => {
      try {
        if (!fs.existsSync(filePath)) {
          log(`⚠️  File not found: ${path.basename(filePath)}`, 'yellow');
          return false;
        }
    
        const content = fs.readFileSync(filePath, 'utf8');
        const hasNodeImports = content.includes('require("node:') || content.includes("require('node:");
    
        if (!hasNodeImports) {
          log(`✅ ${path.basename(filePath)} - already patched`, 'green');
          return true;
        }
    
        // Apply patches for both quote styles
        const patched = content
          .replace(/require\("node:([^"]+)"\)/g, 'require("$1")')
          .replace(/require\('node:([^']+)'\)/g, "require('$1')");
    
        fs.writeFileSync(filePath, patched, 'utf8');
        log(`✅ ${path.basename(filePath)} - patched successfully`, 'green');
        return true;
      } catch (error) {
        log(`❌ ${path.basename(filePath)} - error: ${error.message}`, 'red');
        return false;
      }
    };
    
    /**
     * Main execution
     */
    const main = () => {
      log('🔧 Plasmo + Tailwind v4 compatibility patch', 'cyan');
    
      const files = findPackageFiles();
    
      if (files.length === 0) {
        log('⚠️  No files found to patch', 'yellow');
        log('   This might mean packages are not installed or using different structure', 'yellow');
        return;
      }
    
      log(`   Found ${files.length} files to check`, 'blue');
    
      const results = files.map(patchFile);
      const successful = results.filter(Boolean).length;
    
      log(''); // Empty line
    
      if (successful === files.length) {
        log('🎉 All files patched successfully!', 'green');
        log('   Tailwind v4 should now work with Plasmo', 'green');
      } else {
        log(`⚠️  ${successful}/${files.length} files patched`, 'yellow');
      }
    
      if (successful === 0) {
        log('💡 Try running: pnpm install && node scripts/patch-jiti.js', 'blue');
      }
    };
    
    // Execute if run directly
    if (require.main === module) {
      main();
    }
    
    module.exports = { main, patchFile, findPackageFiles };

    Then in package.json:

    "scripts": {
        "dev": "plasmo dev",
        "build": "plasmo build",
        "package": "plasmo package",
        "postinstall": "node scripts/patch.js" // add this
    },
  26. showwwwww commented on Oct 12, 2025

    @showwwwww

    Based on the comments I ended up writing a script that would patch the files everytime after install. Also helpful if you are sharing code with a team and they need to do the same patch.

    scripts/patch.js:

    #!/usr/bin/env node

    /**

    const fs = require('fs');
    const path = require('path');

    // Console colors
    const c = {
    reset: '\x1b[0m',
    red: '\x1b[31m',
    green: '\x1b[32m',
    yellow: '\x1b[33m',
    blue: '\x1b[34m',
    cyan: '\x1b[36m'
    };

    const log = (msg, color = 'reset') => console.log(${c[color]}${msg}${c.reset});

    /**

    • Find package files that need patching
      */
      const findPackageFiles = () => {
      const nodeModules = path.resolve('node_modules');
      if (!fs.existsSync(nodeModules)) return [];

    const files = [];
    const pnpmPath = path.join(nodeModules, '.pnpm');

    // Helper to safely read directory
    const readDir = (dir) => {
    try {
    return fs.existsSync(dir) ? fs.readdirSync(dir) : [];
    } catch {
    return [];
    }
    };

    // Helper to check file exists
    const fileExists = (filePath) => {
    try {
    return fs.existsSync(filePath);
    } catch {
    return false;
    }
    };

    // Find jiti files
    const findJitiFiles = (basePath) => {
    const jitiPath = path.join(basePath, 'jiti');
    if (!fileExists(jitiPath)) return [];

    const targets = [
      'dist/jiti.cjs',
      'dist/babel.cjs',
      'lib/jiti.cjs'
    ];
    
    return targets
      .map(target => path.join(jitiPath, target))
      .filter(fileExists);
    

    };

    // Find oxide files
    const findOxideFiles = (basePath) => {
    const oxidePath = path.join(basePath, '@tailwindcss', 'oxide', 'index.js');
    return fileExists(oxidePath) ? [oxidePath] : [];
    };

    // Search pnpm structure
    if (fileExists(pnpmPath)) {
    readDir(pnpmPath).forEach(entry => {
    if (entry.startsWith('jiti@')) {
    const packagePath = path.join(pnpmPath, entry, 'node_modules');
    files.push(...findJitiFiles(packagePath));
    }

      if (entry.startsWith('@tailwindcss+oxide@') || entry.startsWith('%40tailwindcss+oxide@')) {
        const packagePath = path.join(pnpmPath, entry, 'node_modules');
        files.push(...findOxideFiles(packagePath));
      }
    });
    

    }

    // Search regular node_modules
    files.push(...findJitiFiles(nodeModules));
    files.push(...findOxideFiles(nodeModules));

    return [...new Set(files)]; // Remove duplicates
    };

    /**

    • Patch a single file
      */
      const patchFile = (filePath) => {
      try {
      if (!fs.existsSync(filePath)) {
      log(⚠️ File not found: ${path.basename(filePath)}, 'yellow');
      return false;
      }

      const content = fs.readFileSync(filePath, 'utf8');
      const hasNodeImports = content.includes('require("node:') || content.includes("require('node:");

      if (!hasNodeImports) {
      log(✅ ${path.basename(filePath)} - already patched, 'green');
      return true;
      }

      // Apply patches for both quote styles
      const patched = content
      .replace(/require("node:([^"]+)")/g, 'require("$1")')
      .replace(/require('node:([^']+)')/g, "require('$1')");

      fs.writeFileSync(filePath, patched, 'utf8');
      log(✅ ${path.basename(filePath)} - patched successfully, 'green');
      return true;
      } catch (error) {
      log(❌ ${path.basename(filePath)} - error: ${error.message}, 'red');
      return false;
      }
      };

    /**

    • Main execution
      */
      const main = () => {
      log('🔧 Plasmo + Tailwind v4 compatibility patch', 'cyan');

    const files = findPackageFiles();

    if (files.length === 0) {
    log('⚠️ No files found to patch', 'yellow');
    log(' This might mean packages are not installed or using different structure', 'yellow');
    return;
    }

    log( Found ${files.length} files to check, 'blue');

    const results = files.map(patchFile);
    const successful = results.filter(Boolean).length;

    log(''); // Empty line

    if (successful === files.length) {
    log('🎉 All files patched successfully!', 'green');
    log(' Tailwind v4 should now work with Plasmo', 'green');
    } else {
    log(⚠️ ${successful}/${files.length} files patched, 'yellow');
    }

    if (successful === 0) {
    log('💡 Try running: pnpm install && node scripts/patch-jiti.js', 'blue');
    }
    };

    // Execute if run directly
    if (require.main === module) {
    main();
    }

    module.exports = { main, patchFile, findPackageFiles };
    Then in package.json:

    "scripts": {
    "dev": "plasmo dev",
    "build": "plasmo build",
    "package": "plasmo package",
    "postinstall": "node scripts/patch.js" // add this
    },

    Perfectly resolve! I admit you're the best handsome man in 2025!!!

  27. Ying-Luan commented on Dec 20, 2025

    @Ying-Luan

    Based on the comments I ended up writing a script that would patch the files everytime after install. Also helpful if you are sharing code with a team and they need to do the same patch.根据大家的反馈,我最终编写了一个脚本,每次安装后都会自动修补文件。如果你与团队共享代码,而他们也需要进行同样的修补,这个脚本也很有用。

    scripts/patch.js:scripts/patch.js :

    #!/usr/bin/env node

    /**

    const fs = require('fs');
    const path = require('path');

    // Console colors
    const c = {
    reset: '\x1b[0m',
    red: '\x1b[31m',
    green: '\x1b[32m',
    yellow: '\x1b[33m',
    blue: '\x1b[34m',
    cyan: '\x1b[36m'
    };

    const log = (msg, color = 'reset') => console.log(${c[color]}${msg}${c.reset});

    /**

    • Find package files that need patching
      */
      const findPackageFiles = () => {
      const nodeModules = path.resolve('node_modules');
      if (!fs.existsSync(nodeModules)) return [];

    const files = [];
    const pnpmPath = path.join(nodeModules, '.pnpm');

    // Helper to safely read directory
    const readDir = (dir) => {
    try {
    return fs.existsSync(dir) ? fs.readdirSync(dir) : [];
    } catch {
    return [];
    }
    };

    // Helper to check file exists
    const fileExists = (filePath) => {
    try {
    return fs.existsSync(filePath);
    } catch {
    return false;
    }
    };

    // Find jiti files
    const findJitiFiles = (basePath) => {
    const jitiPath = path.join(basePath, 'jiti');
    if (!fileExists(jitiPath)) return [];

    const targets = [
      'dist/jiti.cjs',
      'dist/babel.cjs',
      'lib/jiti.cjs'
    ];
    
    return targets
      .map(target => path.join(jitiPath, target))
      .filter(fileExists);
    

    };

    // Find oxide files
    const findOxideFiles = (basePath) => {
    const oxidePath = path.join(basePath, '@tailwindcss', 'oxide', 'index.js');
    return fileExists(oxidePath) ? [oxidePath] : [];
    };

    // Search pnpm structure
    if (fileExists(pnpmPath)) {
    readDir(pnpmPath).forEach(entry => {
    if (entry.startsWith('jiti@')) {
    const packagePath = path.join(pnpmPath, entry, 'node_modules');
    files.push(...findJitiFiles(packagePath));
    }

      if (entry.startsWith('@tailwindcss+oxide@') || entry.startsWith('%40tailwindcss+oxide@')) {
        const packagePath = path.join(pnpmPath, entry, 'node_modules');
        files.push(...findOxideFiles(packagePath));
      }
    });
    

    }

    // Search regular node_modules
    files.push(...findJitiFiles(nodeModules));
    files.push(...findOxideFiles(nodeModules));

    return [...new Set(files)]; // Remove duplicates
    };

    /**

    • Patch a single file
      */
      const patchFile = (filePath) => {
      try {
      if (!fs.existsSync(filePath)) {
      log(⚠️ File not found: ${path.basename(filePath)}, 'yellow');
      return false;
      }

      const content = fs.readFileSync(filePath, 'utf8');
      const hasNodeImports = content.includes('require("node:') || content.includes("require('node:");

      if (!hasNodeImports) {
      log(✅ ${path.basename(filePath)} - already patched, 'green');
      return true;
      }

      // Apply patches for both quote styles
      const patched = content
      .replace(/require("node:([^"]+)")/g, 'require("$1")')
      .replace(/require('node:([^']+)')/g, "require('$1')");

      fs.writeFileSync(filePath, patched, 'utf8');
      log(✅ ${path.basename(filePath)} - patched successfully, 'green');
      return true;
      } catch (error) {
      log(❌ ${path.basename(filePath)} - error: ${error.message}, 'red');
      return false;
      }
      };

    /**

    • Main execution
      */
      const main = () => {
      log('🔧 Plasmo + Tailwind v4 compatibility patch', 'cyan');

    const files = findPackageFiles();

    if (files.length === 0) {
    log('⚠️ No files found to patch', 'yellow');
    log(' This might mean packages are not installed or using different structure', 'yellow');
    return;
    }

    log( Found ${files.length} files to check, 'blue');

    const results = files.map(patchFile);
    const successful = results.filter(Boolean).length;

    log(''); // Empty line

    if (successful === files.length) {
    log('🎉 All files patched successfully!', 'green');
    log(' Tailwind v4 should now work with Plasmo', 'green');
    } else {
    log(⚠️ ${successful}/${files.length} files patched, 'yellow');
    }

    if (successful === 0) {
    log('💡 Try running: pnpm install && node scripts/patch-jiti.js', 'blue');
    }
    };

    // Execute if run directly
    if (require.main === module) {
    main();
    }

    module.exports = { main, patchFile, findPackageFiles };
    Then in package.json:  然后在 package.json 文件中:

    "scripts": {
    "dev": "plasmo dev",
    "build": "plasmo build",
    "package": "plasmo package",
    "postinstall": "node scripts/patch.js" // add this
    },

    Perfectly solved! Brilliant solution, thank you so much for the help!

  28. wodepig commented on Apr 10, 2026

    @wodepig

    Fortunately, I didn't replace it manually, but looked down for the code that was automatically replaced.🤣 solution, thank you

  29. derick-kibiwott commented on Jul 7, 2026

    @derick-kibiwott

    I found this helpful if you are using turborepo because the folder structure is different:

    #!/usr/bin/env node
    
    /**
     * Plasmo + Tailwind v4 Compatibility Patch (Monorepo-aware)
     *
     * Fixes "node:" import issues in jiti and @tailwindcss/oxide.
     * Run from ANYWHERE in your monorepo — it finds the root automatically.
     */
    
    const fs = require("fs")
    const path = require("path")
    
    const c = {
      reset: "\x1b[0m",
      red: "\x1b[31m",
      green: "\x1b[32m",
      yellow: "\x1b[33m",
      blue: "\x1b[34m",
      cyan: "\x1b[36m",
      gray: "\x1b[90m"
    }
    
    const log = (msg, color = "reset") => console.log(`${c[color]}${msg}${c.reset}`)
    
    /**
     * Find monorepo root by looking for pnpm-workspace.yaml or root package.json
     */
    function findMonorepoRoot(startDir = process.cwd()) {
      let current = path.resolve(startDir)
    
      while (current !== path.dirname(current)) {
        if (fs.existsSync(path.join(current, "pnpm-workspace.yaml"))) {
          return current
        }
        // Also check for root package.json without workspace file (some setups)
        if (fs.existsSync(path.join(current, "package.json"))) {
          const pkg = JSON.parse(
            fs.readFileSync(path.join(current, "package.json"), "utf8")
          )
          if (
            pkg.workspaces ||
            fs.existsSync(path.join(current, "pnpm-workspace.yaml"))
          ) {
            return current
          }
        }
        current = path.dirname(current)
      }
    
      // Fallback: just use cwd
      return process.cwd()
    }
    
    /**
     * Recursively find all files matching a pattern in a directory
     */
    function findFiles(dir, matcher) {
      const results = []
    
      try {
        const entries = fs.readdirSync(dir, { withFileTypes: true })
        for (const entry of entries) {
          const fullPath = path.join(dir, entry.name)
          if (entry.isDirectory()) {
            results.push(...findFiles(fullPath, matcher))
          } else if (matcher(fullPath)) {
            results.push(fullPath)
          }
        }
      } catch {
        // Permission denied or not a directory
      }
    
      return results
    }
    
    /**
     * Find jiti files in pnpm store
     */
    function findJitiFiles(rootNodeModules) {
      const files = []
      const pnpmDir = path.join(rootNodeModules, ".pnpm")
    
      if (!fs.existsSync(pnpmDir)) {
        log("No .pnpm directory found. Are you using pnpm?", "yellow")
        return files
      }
    
      const entries = fs.readdirSync(pnpmDir)
    
      for (const entry of entries) {
        // pnpm stores packages as "jiti@2.7.0" or "jiti@2.7.0_something" (peer deps)
        if (entry.startsWith("jiti@")) {
          const packageRoot = path.join(pnpmDir, entry, "node_modules", "jiti")
    
          const targets = [
            path.join(packageRoot, "dist", "jiti.cjs"),
            path.join(packageRoot, "dist", "babel.cjs"),
            path.join(packageRoot, "lib", "jiti.cjs")
          ]
    
          for (const target of targets) {
            if (fs.existsSync(target)) {
              files.push(target)
            }
          }
        }
      }
    
      return files
    }
    
    /**
     * Find @tailwindcss/oxide files
     */
    function findOxideFiles(rootNodeModules) {
      const files = []
      const pnpmDir = path.join(rootNodeModules, ".pnpm")
    
      if (!fs.existsSync(pnpmDir)) return files
    
      const entries = fs.readdirSync(pnpmDir)
    
      for (const entry of entries) {
        // Handle both @tailwindcss+oxide@ and %40tailwindcss+oxide@
        if (entry.includes("tailwindcss") && entry.includes("oxide")) {
          const packageRoot = path.join(
            pnpmDir,
            entry,
            "node_modules",
            "@tailwindcss",
            "oxide"
          )
          const target = path.join(packageRoot, "index.js")
    
          if (fs.existsSync(target)) {
            files.push(target)
          }
        }
      }
    
      return files
    }
    
    /**
     * Patch a single file
     */
    function patchFile(filePath) {
      try {
        if (!fs.existsSync(filePath)) {
          log(`⚠️  Not found: ${filePath}`, "yellow")
          return false
        }
    
        const content = fs.readFileSync(filePath, "utf8")
    
        // Check if already patched
        if (
          !content.includes('require("node:') &&
          !content.includes("require('node:")
        ) {
          log(
            `⏭️  ${path.relative(process.cwd(), filePath)} — no node: imports found`,
            "gray"
          )
          return true
        }
    
        const patched = content
          .replace(/require\("node:([^"]+)"\)/g, 'require("$1")')
          .replace(/require\('node:([^']+)'\)/g, "require('$1')")
    
        fs.writeFileSync(filePath, patched, "utf8")
        log(`✅ Patched: ${path.relative(process.cwd(), filePath)}`, "green")
        return true
      } catch (error) {
        log(`❌ Error patching ${filePath}: ${error.message}`, "red")
        return false
      }
    }
    
    /**
     * Main
     */
    function main() {
      const root = findMonorepoRoot()
      const rootNodeModules = path.join(root, "node_modules")
    
      log("🔧 Plasmo + Tailwind v4 compatibility patch", "cyan")
      log(`   Monorepo root: ${root}`, "blue")
      log(`   Node modules: ${rootNodeModules}`, "blue")
      log("")
    
      if (!fs.existsSync(rootNodeModules)) {
        log("❌ node_modules not found. Run pnpm install first.", "red")
        process.exit(1)
      }
    
      const jitiFiles = findJitiFiles(rootNodeModules)
      const oxideFiles = findOxideFiles(rootNodeModules)
      const allFiles = [...new Set([...jitiFiles, ...oxideFiles])]
    
      if (allFiles.length === 0) {
        log("⚠️  No jiti or @tailwindcss/oxide files found.", "yellow")
        log("   Possible reasons:", "yellow")
        log("   • Packages aren't installed (run pnpm install)", "yellow")
        log("   • Different package versions than expected", "yellow")
        log("   • pnpm virtual store is in a non-standard location", "yellow")
        return
      }
    
      log(`   Found ${allFiles.length} file(s) to check`, "blue")
      log("")
    
      const results = allFiles.map(patchFile)
      const patched = results.filter(Boolean).length
    
      log("")
      if (patched === allFiles.length) {
        log(`🎉 All ${allFiles.length} files OK!`, "green")
      } else {
        log(`⚠️  ${patched}/${allFiles.length} files processed`, "yellow")
      }
    }
    
    if (require.main === module) {
      main()
    }
    
    module.exports = { main, findMonorepoRoot, patchFile }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions