5

I'm trying to use vue-router based on the examples, such as

let routes = [
    { path: '/',  component: MainComponent },
];

let router = new VueRouter({routes});

new Vue({  router  }).$mount('#app');

but I always get this error:

vue.runtime.esm.js:619 [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available.

Can I fix this by using the render function? I tried,

let routes = [];

But still fails.

4 Answers 4

5

Ok, I spent a half day on this and I finally got it working: vue-router + webpack + runtime-only vue.

This tutorial was the most helpful. What I learned:

If you use vue-cli, the vue version is in the webpack.base.conf.js

  • vue.esm.js will include the compiler
  • vue.runtime.esm.js will NOT include the compiler

If you want to use runtime, you must change your main.js. Do NOT use this

new Vue({
    el: '#app',
    router,
    template: '<App/>',      //  <== This is bad
    components: { App }
});

and instead DO use this

Vue.use(VueRouter);          // <== very important
new Vue({
    router,
    render(createElement) {
        return createElement(App);
    }
}).$mount('#app');

You can use either $mount or the el: with runtime. Both work, but the $mount gives you more flexibility. And of course the router is created the usual way

let routes = [
    { path: '/', component: MainComponent },    
];
let router = new VueRouter({ routes }); 

And if you are still seeing the error

[Vue warn]: You are using the runtime-only build of Vue

in the console, then make double sure that you never ever in your code use any templates with strings. Even inside your *.vue files, if you try to do

const Foo = { template: '<div>foo</div>' };

it will fail. Instead you must either use <template> tags, or else you must use createElement. Good luck!

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, great solution!!! I added the app.js code: <template> <div id="app"> <router-view></router-view> </div> </template> <script> export default { name: 'app' } </script>
what is App inside createElement(App) here? For me it's one of the components and that's the one that gets rendered, routes do not seem to matter.
1

The accepted solution is right in that you cannot use string template with runtime only Vue, and you have to implement the render function. However, if you want to render components at the top level instead of using router-view, you can get the matched component and render it manually:

const routes = [
  { path: '/about', component: About },
  { path: '/index', component: App },
  { path: "*", component: App }
]

new Vue({
  router,
  render: h => {
    return h(router.getMatchedComponents()[0])
  },
}).$mount('#app')

Comments

1

It appears to be impossible to use the runtime, based on these two MREs (one with, one without runtime). If nothing else, you can use these snippets if you choose to post an issue on their github or the vue forums, or another answer can use them as a template to prove me incorrect. This assumes you're not using vue-cli. With vue-cli you need to opt-in to including the compiler in your builds. See https://cli.vuejs.org/config/#runtimecompiler and https://v2.vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only

Fails (console warning - vue runtime)

let routes = [
  {
    path: "",
    component: {
      render(h) {
        return h("div", "hello world");
      }
    }
  }
];

let router = new VueRouter({ routes });

new Vue({ router }).$mount("#app");
<script src="https://unpkg.com/vue/dist/vue.runtime.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
  <router-view></router-view>
</div>

Works (no console warning - full vue)

let routes = [
  {
    path: "",
    component: {
      render(h) {
        return h("div", "hello world");
      }
    }
  }
];

let router = new VueRouter({ routes });

new Vue({ router }).$mount("#app");
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
  <router-view></router-view>
</div>

Comments

0

For Vue 3 (here with TypeScript), the trick is to use the h component render function as the result of the setup function as the top-level component instead of the default createApp({}) which appears to be interpreted as a template.

So I have:

    const app = createApp({
        setup() {
            const component = computed((): Component => {
                const res = router.currentRoute.value.matched
                if (res.length > 0 && res[0].components)
                    return res[0].components.default
                else
                    return Loading
            })
            return () => h(component.value)
        }
    })
    ...

vue-router's Router exposes a ready-to-render component in property currentRoute.value.matched[0].components.default. Be sure to check for a match and for the component to be loaded (this works for lazy components as well imported using () => import('path/to/Component.vue')).

Obviously, the router is integrated into the app and and the app mounted this way, with the router being created using createRouter:

    ...
    const router = createRouter({
        history: createWebHistory(),
        routes: [
            ...
        ]
    })
    app.use(router)
    app.mount('#app')

In the index note that <router-view/> is not used. Probably was the only thing using the runtime compiler, think about a waste of space as the recommended option in the docs! The little extra effort in the root component to make it static is definitely worth it. The index looks like this:

<!DOCTYPE html>
<html class="dark" data-theme="dark">
    <head>
        <meta charset="utf-8"/>
        <title>Title</title>
        <script type="module" src="/src/main.ts"></script>
    </head>
    <body>
        <div id="app">
        </div>
    </body>
</html>

Tested with Vite, allows to have vue: 'vue/dist/vue.runtime.esm-bundler.js'. Pretty compact!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.