Skip to content

ENOTDIR: not a directory with whatwg-url.mjs/webidl2js-wrapper #492

@hermesalvesbr

Description

@hermesalvesbr

Environment

Environment

Operating System: Linux (Ubuntu)
Node Version: v22.14.0
Nuxt Version: 3.16.1
Nitro Version: 2.11.7
Package Manager: npm@10.9.2 (also tested with Bun@1.2.7)
Preset: cloudflare-pages
Compatibility Date: 2025-03-12 (also tested with 2025-03-20)

Reproduction

Nuxt 3.16.1 with Nitro 2.11.7
ℹ Building for Nitro preset: cloudflare-pages
✔ Generated public dist
[nitro] ℹ Building Nuxt Nitro server (preset: cloudflare-pages, compatibility date: 2025-03-12)
[nitro] ERROR Error: ENOTDIR: not a directory, stat '/home/hermes/Projetos-linux/cidadeMobile/node_modules/nitropack/node_modules/unenv/dist/runtime/npm/whatwg-url.mjs/webidl2js-wrapper'
undefined
[ERROR] ENOTDIR: not a directory, stat '.../unenv/dist/runtime/npm/whatwg-url.mjs/webidl2js-wrapper'
error: script "build" exited with code 1

Describe the bug

When building a Nuxt 3.16.1 project with Nitro 2.11.7 using the cloudflare-pages preset, the build fails with the following error:

[nitro] ERROR Error: ENOTDIR: not a directory, stat '.../node_modules/nitropack/node_modules/unenv/dist/runtime/npm/whatwg-url.mjs/webidl2js-wrapper'

The error occurs during the "Building Nuxt Nitro server" step, indicating that unenv (via nitropack) is attempting to treat webidl2js-wrapper as a directory when it should be a file, or the file is missing/corrupted in the unenv@1.10.0 structure. This happens consistently both locally (Ubuntu, Node 22.14.0, Bun 1.2.7 or npm 10.9.2) and on Cloudflare Pages deployment. The issue persists despite forcing unenv@1.10.0 in resolutions and excluding whatwg-url/webidl2js-wrapper in nitro.externals.inline.

I suspect this is a bug in how unenv@1.10.0 structures or resolves whatwg-url.mjs/webidl2js-wrapper for the cloudflare-pages preset. I’m happy to submit a PR if guided on where to start—thanks!

Additional context

import { fileURLToPath } from 'node:url'
import vuetify from 'vite-plugin-vuetify'
import svgLoader from 'vite-svg-loader'

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  runtimeConfig: {
    alibabaApiKey: import.meta.env.NUXT_ALIBABA_API_KEY,
    public: {
      API_BASE_URL: import.meta.env.NUXT_PUBLIC_API_BASE_URL || 'http://localhost:8055',
    },
  },
  features: {
    inlineStyles: false,
  },
  app: {
    head: {
      titleTemplate: '%s - Cidade Transparente',
      title: 'Softagon',

      link: [{
        rel: 'icon',
        type: 'image/x-icon',
        href: `/favicon.ico`,
      }],
    },
  },

  devtools: {
    enabled: false,
  },

  css: [
    '@core/scss/template/index.scss',
    '@styles/styles.scss',
    '@/plugins/iconify/icons.css',
    'notivue/notification.css', // Added Notivue notification styles
    'notivue/animations.css', // Added Notivue animations styles
    '@mdi/font/css/materialdesignicons.css', // Adicionado para suportar ícones MDI
  ],

  components: [
    {
      path: '@/@core/components',
      pathPrefix: false,
    },
    {
      path: '~/components/global',
      global: true,
    },
    {
      path: '~/components',
    },
  ],

  plugins: ['@/plugins/vuetify/index.ts', '@/plugins/iconify/index.ts'],

  imports: {
    dirs: ['./@core/utils', './@core/composable/', './plugins/*/composables/*'],
  },

  experimental: {
    typedPages: true,
  },

  typescript: {
    tsConfig: {
      compilerOptions: {
        paths: {
          '@/*': ['../*'],
          '@themeConfig': ['../themeConfig.ts'],
          '@layouts/*': ['../@layouts/*'],
          '@layouts': ['../@layouts'],
          '@core/*': ['../@core/*'],
          '@core': ['../@core'],
          '@images/*': ['../assets/images/*'],
          '@styles/*': ['../assets/styles/*'],
          '@validators': ['../@core/utils/validators'],
          '@db/*': ['../server/fake-db/*'],
          '@api-utils/*': ['../server/utils/*'],
        },
      },
    },
  },

  vue: {
    compilerOptions: {
      isCustomElement: tag => tag === 'swiper-container' || tag === 'swiper-slide',
    },
  },

  vite: {
    define: { 'process.env': {} },

    resolve: {
      alias: {
        '@': fileURLToPath(new URL('.', import.meta.url)),
        '@themeConfig': fileURLToPath(new URL('./themeConfig.ts', import.meta.url)),
        '@core': fileURLToPath(new URL('./@core', import.meta.url)),
        '@layouts': fileURLToPath(new URL('./@layouts', import.meta.url)),
        '@images': fileURLToPath(new URL('./assets/images/', import.meta.url)),
        '@styles': fileURLToPath(new URL('./assets/styles/', import.meta.url)),
        '@configured-variables': fileURLToPath(new URL('./assets/styles/variables/_template.scss', import.meta.url)),
        '@db': fileURLToPath(new URL('./server/fake-db/', import.meta.url)),
        '@api-utils': fileURLToPath(new URL('./server/utils/', import.meta.url)),
      },
    },

    plugins: [
      svgLoader(),
      vuetify({
        styles: {
          configFile: 'assets/styles/variables/_vuetify.scss',
        },
      }),
    ],

    // Optimização do build para remover componentes relacionados ao layout horizontal
    build: {
      rollupOptions: {
        external: [
          '@layouts/components/HorizontalNav.vue',
          '@layouts/components/HorizontalNavGroup.vue',
          '@layouts/components/HorizontalNavLayout.vue',
          '@layouts/components/HorizontalNavLink.vue',
          '@layouts/components/HorizontalNavPopper.vue',
        ],
      },
    },
  },

  build: {
    transpile: ['vuetify'],
  },

  modules: ['@vueuse/nuxt', '@nuxtjs/i18n', '@nuxtjs/device', '@pinia/nuxt', 'notivue/nuxt'],
  i18n: {
    bundle: {
      optimizeTranslationDirective: false,
    },
  },
  notivue: {
    pauseOnHover: true,
    pauseOnTouch: true,
    pauseOnTabChange: true,
    enqueue: true,
    limit: 3,
    position: 'top-center',
    notifications: {
      global: {
        duration: 2500,
      },
    },
  },
  nitro: {
    preset: 'cloudflare-pages',
    prerender: {
      crawlLinks: true,
      routes: ['/'],
      ignore: ['/api', '/servicos/**'],
    },
    externals: {
      inline: ['canva', 'whatwg-url', 'unenv/runtime/npm/whatwg-url', 'webidl2js-wrapper'],
    },
    minify: false,
    buildDir: '.output',
    publicAssets: [
      {
        dir: '.output/public',
        maxAge: 60 * 60 * 24 * 365,
      },
    ],
  },
  compatibilityDate: '2025-03-20',
})

{
  "name": "cidade-transparente",
  "type": "module",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "nuxt dev",
    "build": "nuxt build",
    "lint": "eslint . -c .eslintrc.cjs --fix --ext .ts,.js,.cjs,.vue,.tsx,.jsx",
    "build:icons": "tsx plugins/iconify/build-icons.ts",
    "postinstall": "nuxt prepare && npm run build:icons",
    "generate": "nuxt generate",
    "gen:types": "node directus/scripts/genTypes.ts"
  },
  "dependencies": {
    "@casl/ability": "^6.7.3",
    "@casl/vue": "^2.2.2",
    "@directus/sdk": "^19.1.0",
    "@floating-ui/dom": "^1.6.13",
    "@formkit/drag-and-drop": "^0.4.2",
    "@mdi/font": "^7.4.47",
    "@nuxthub/core": "^0.8.22",
    "@nuxtjs/i18n": "^9.4.0",
    "@sindresorhus/is": "^7.0.1",
    "@tiptap/extension-highlight": "^2.11.6",
    "@tiptap/extension-image": "^2.11.6",
    "@tiptap/extension-link": "^2.11.6",
    "@tiptap/extension-placeholder": "^2.11.6",
    "@tiptap/extension-table": "^2.11.6",
    "@tiptap/extension-table-cell": "^2.11.6",
    "@tiptap/extension-table-header": "^2.11.6",
    "@tiptap/extension-table-row": "^2.11.6",
    "@tiptap/extension-text-align": "^2.11.6",
    "@tiptap/extension-underline": "^2.11.6",
    "@tiptap/pm": "^2.11.6",
    "@tiptap/starter-kit": "^2.11.6",
    "@tiptap/vue-3": "^2.11.6",
    "@vue-pdf-viewer/viewer": "^2.3.1",
    "@vueuse/core": "^13.0.0",
    "@vueuse/math": "^13.0.0",
    "@vueuse/nuxt": "^13.0.0",
    "cookie-es": "^2.0.0",
    "destr": "^2.0.3",
    "echarts": "^5.6.0",
    "eslint-plugin-regexp": "^2.7.0",
    "jsdom": "^26.0.0",
    "jwt-decode": "^4.0.0",
    "maska": "^3.1.1",
    "next-auth": "4.24.11",
    "notivue": "^2.4.5",
    "nuxt": "^3.16.1",
    "ofetch": "^1.4.1",
    "openai": "^4.90.0",
    "pinia": "^3.0.1",
    "roboto-fontface": "^0.10.0",
    "shepherd.js": "^14.5.0",
    "swiper": "^11.2.6",
    "ufo": "^1.5.4",
    "unpdf": "^0.12.1",
    "unplugin-vue-define-options": "^3.0.0-beta.7",
    "vue-echarts": "^7.0.3",
    "vue-flatpickr-component": "^12.0.0",
    "vue3-perfect-scrollbar": "^2.0.0",
    "vuetify": "^3.7.19",
    "webfontloader": "^1.6.28"
  },
  "devDependencies": {
    "@antfu/eslint-config": "^4.11.0",
    "@directus/types": "^13.1.0",
    "@iconify-json/bx": "^1.2.2",
    "@iconify-json/fa": "^1.2.1",
    "@iconify-json/mdi": "^1.2.3",
    "@iconify-json/tabler": "^1.2.17",
    "@iconify/tools": "^4.1.2",
    "@iconify/utils": "^2.3.0",
    "@iconify/vue": "^4.3.0",
    "@intlify/unplugin-vue-i18n": "^6.0.5",
    "@nuxtjs/device": "^3.2.4",
    "@pinia/nuxt": "^0.10.1",
    "@sidebase/nuxt-auth": "^0.10.1",
    "@stylistic/stylelint-config": "^2.0.0",
    "@stylistic/stylelint-plugin": "^3.1.2",
    "@types/jsdom": "^21.1.7",
    "@types/node": "^22.13.14",
    "@types/webfontloader": "^1.6.38",
    "@typescript-eslint/eslint-plugin": "^8.28.0",
    "@typescript-eslint/parser": "^8.28.0",
    "directus-typeforge": "^0.10.2",
    "eslint": "^9.23.0",
    "eslint-import-resolver-typescript": "^4.3.1",
    "eslint-plugin-import": "^2.31.0",
    "eslint-plugin-vue": "^10.0.0",
    "postcss-html": "^1.8.0",
    "postcss-scss": "^4.0.9",
    "sass": "^1.86.0",
    "stylelint": "^16.17.0",
    "stylelint-config-standard-scss": "^14.0.0",
    "tsx": "^4.19.3",
    "typescript": "^5.8.2",
    "vite": "^6.2.3",
    "vite-plugin-vuetify": "^2.1.0",
    "vite-svg-loader": "^5.1.0"
  },
  "overrides": {
    "postcss": "^8"
  },
  "resolutions": {
    "postcss": "^8"
  }
}

Logs

Below is the output from running `bun run build` on my project with Nuxt 3.16.1, Nitro 2.11.7, and `unenv@1.10.0` forced via `resolutions`. The error occurs during the Nitro server build step with the `cloudflare-pages` preset:


bun update v1.2.7 (5c0fa6dc)

$ nuxt prepare && bun run build:icons
✔ Types generated in .nuxt                                                       nuxi  8:33:07 PM
$ tsx plugins/iconify/build-icons.ts
Saved CSS to /home/hermes/Projetos-linux/cidadeMobile/plugins/iconify/icons.css!

↑ eslint-import-resolver-typescript 4.2.7 → 4.3.1
+ unenv@1.10.0

ℹ Prerendered 17 routes in 15.808 seconds                                        nitro 8:35:50 PM
✔ Generated public dist                                                          nitro 8:35:50 PM
[nitro 8:35:50 PM] ℹ Building Nuxt Nitro server (preset: cloudflare-pages, compatibility date: 2025-03-12)
node_modules/openai/core.mjs (1:30): The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten
node_modules/openai/core.mjs (1:38): The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten
node_modules/openai/core.mjs (7:30): The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten
node_modules/openai/core.mjs (7:38): The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten

[nitro 8:35:52 PM]  ERROR  Error: ENOTDIR: not a directory, stat '/home/hermes/Projetos-linux/cidadeMobile/node_modules/nitropack/node_modules/unenv/dist/runtime/npm/whatwg-url.mjs/webidl2js-wrapper'

undefined

[8:35:52 PM]  ERROR  ENOTDIR: not a directory, stat '/home/hermes/Projetos-linux/cidadeMobile/node_modules/nitropack/node_modules/unenv/dist/runtime/npm/whatwg-url.mjs/webidl2js-wrapper'

[8:35:52 PM]  ERROR  ENOTDIR: not a directory, stat '/home/hermes/Projetos-linux/cidadeMobile/node_modules/nitropack/node_modules/unenv/dist/runtime/npm/whatwg-url.mjs/webidl2js-wrapper'

error: script "build" exited with code 1


This log shows the build failing at the Nitro step, with the `ENOTDIR` error pointing to `unenv/dist/runtime/npm/whatwg-url.mjs/webidl2js-wrapper`. The same error occurs with npm (`npm run build`) and on Cloudflare Pages deployment.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions