Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

RickGoemans's avatar

Keep having to import vue from 'vue/dist/vue.esm-bundler.js'

I've recently started a new project with Laravel 10 and Vite where I want to build a administrator GUI in Vue since that's what I'm used to in other projects where I have a separate Nuxt project. But since this is a simple hosted project I want to make it inside the same project.

So I've added the Vue and @vitejs/plugin-vue dependencies which results in my package.json being this:

{
    "private": true,
    "scripts": {
        "dev": "vite",
        "build": "vite build"
    },
    "devDependencies": {
        "@tailwindcss/forms": "^0.5.3",
        "@vitejs/plugin-vue": "^4.0.0",
        "autoprefixer": "^10.4.13",
        "axios": "^1.1.2",
        "laravel-vite-plugin": "^0.7.2",
        "postcss": "^8.4.18",
        "sass": "^1.58.3",
        "tailwindcss": "^3.2.7",
        "vite": "^4.0.0",
        "vue": "^3.2.41"
    },
    "dependencies": {
        "@fortawesome/fontawesome-free": "^6.3.0",
        "flowbite": "^1.6.5",
        "lightgallery": "^2.7.1"
    }
}

Next I've created a tsconfig.json file with these contents:

{
    "compilerOptions": {
        "allowJs": true,
        "module": "ESNext",
        "moduleResolution": "bundler",
        "jsx": "preserve",
        "strict": true,
        "isolatedModules": true,
        "target": "ESNext",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "noEmit": true,
        "skipLibCheck": true,
        "paths": {
            "@/*": [
                "./resources/scripts/*"
            ]
        }
    },
    "include": [
        "resources/scripts/**/*.ts",
        "resources/scripts/**/*.d.ts",
        "resources/scripts/**/*.vue"
    ]
}

In my resources/scripts/admin.ts (which is loaded on the /admin route) the following:

import { createApp } from 'vue/dist/vue.esm-bundler.js' // This works
import { createApp } from 'vue' // This doesn't work
import Home from '../Components/Home.vue'

const app = createApp({
    components: {
        Home,
    }
})

app.mount('#app')

And here's the blade file being used on that route:

<x-layouts.admin>
    <p>Admin</p>
    <home></home>
</x-layouts.admin>

With this Home.vue component:

<template>
    <p>Home</p>
</template>

<script setup lang="ts">
</script>

If I use the first line in admin.ts, it successfully renders the Home.vue component (which for now just prints a paragraph as you can see) , but with the second one it doesn't. Is there some misconfiguration that I should correct to have it just working with the "normal" import? The reason I'm asking is that I don't want to continue adding more packages (like Pinia) which might result in even more errors before continueing. Even the basic composition API like import { ref, onMounted } from 'vue' don't work when I don't correct the import.

Any help would be appreciated because there is no clean documentation (that I can find) on this without the addition of IntertiaJs which I don't consider useful for now.

0 likes
3 replies
LaryAI's avatar
Level 58

The issue seems to be related to the way Vite handles Vue imports. Instead of importing Vue from the 'vue' package, you need to import it from 'vue/dist/vue.esm-bundler.js'. However, this can be cumbersome and can lead to issues with other Vue packages that expect the standard import.

To fix this, you can configure Vite to use the standard Vue import by adding the following to your vite.config.js file:

import vue from '@vitejs/plugin-vue'

export default {
  plugins: [
    vue({
      template: {
        compilerOptions: {
          isCustomElement: tag => tag.startsWith('x-')
        }
      }
    })
  ],
  optimizeDeps: {
    include: ['vue']
  }
}

This will tell Vite to use the standard Vue import and optimize the dependency tree to include only the necessary Vue packages.

Once you've made this change, you can import Vue in your code like this:

import { createApp } from 'vue'

This should work without any issues.

RickGoemans's avatar

I've resolved it by adding an alias to my vite.config.js resulting in:

import {defineConfig} from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
	resolve: {
		alias: {
			'vue': 'vue/dist/vue.esm-bundler.js',
		},
	},
	plugins: [
		laravel({
			input: [
				'resources/sass/app.scss',
				'resources/scripts/app.ts',
				'resources/scripts/admin.ts',
			],
			refresh: true,
		}),
		vue({
			template: {
				compilerOptions: {
					isCustomElement: (tag) => tag.startsWith('x-')
				},
				transformAssetUrls: {
					base: null,
					includeAbsolute: false,
				},
			},
		}),
	],
	optimizeDeps: {
		include: [
			'vue',
		],
	},
})

And I've adjust my tsconfig.json because it would still show errors in my IDE on the imports:

{
    "compilerOptions": {
        "allowJs": true,
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "isolatedModules": true,
        "jsx": "preserve",
        "module": "ESNext",
        "moduleResolution": "Node", // This resolves the IDE "errors" when importing
        "noEmit": true,
        "noImplicitAny": true,
        "noUnusedLocals": true,
        "paths": {
            "@/*": [
                "./resources/scripts/*"
            ]
        },
        "resolveJsonModule": true,
        "skipLibCheck": true,
        "strict": true,
        "target": "ESNext",
        "types": [
            "vite/client"
        ]
    },
    "include": [
        "resources/scripts/**/*.ts",
        "resources/scripts/**/*.d.ts",
        "resources/scripts/**/*.vue"
    ]
}

Please or to participate in this conversation.