Search code examples
asp.net-mvcrazorvue.jsorchardcms

Working with 'single file' Vue.js components in Orchard / ASP.NET MVC / Razor


I have a large website that is hosted in Azure and using Orchard as a CMS. There are several custom modules we have developed within the Orchard framework that are basically just ASP.NET MVC that play nice inside Orchard. Nothing too fancy.

Not being a full time web guy (I usually do desktop apps) I am struggling with a few noob problems trying to get my first 'single file' Vue.js component working. I think my problems stem from some simple syntactical and/or url/filepath problems. But I've been trying permutations blindly without much luck, so I am hoping someone will point me in the right direction.

To begin, here is my working starting point

My simplified razor (index.cshtml) file:

@{

    Script.Require("jQuery").AtHead();

    Style.Include("https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css").AtHead();
    Script.Include("https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js").AtHead();

    Script.Include("https://cdn.jsdelivr.net/npm/vue/dist/vue.js").AtHead();
}

<div id="my-vue-app" class="container">

    <h2>This is a simple razor page</h2>

    <div v-for="shop in pizzaShops">
        <p>{{ shop.id }} - {{ shop.name }}</p>
    </div>

</div>

<!-- Right now, I am placing the js as a sibling of the view.  Placing the js into -->
<!-- the scripts folder feels disjointed right now.  The paths to the view is --> 
<!-- driven by Orchard naming and filepath conventions.  Being a prototype, I'm not -->
<!-- to hung up on this right now. -->
<script src="~/modules/mymodule/views/myviewfolder/index.js"></script>

My simplified Vue app (index.js) file:

const pizzaShops = [
    {
        id: 1,
        name: 'Pizza The Hut'
    },
    {
        id: 2,
        name: 'Little Geezers'
    },
    {
        id: 3,
        name: 'Pappa Runs'
    },
    {
        id: 4,
        name: 'Tri-ominoes'
    }
];

const app = new Vue({
    el: '#my-vue-app',
    data: {
        pizzaShops
    }
});

When I compile and run the files above, everything works as expected and my view contains the output you would expect:

Better Components! Better Pizza Pizza!

1 - Pizza The Hut
2 - Little Geezers
3 - Pappa Runs
4 - Tri-ominoes

Now when I try to introduce my 'single file' Vue component things go off the rails.

Here is my simplified 'single-file' Vue component (pizzashop.vue):

<template>
  <div>
    <h1>static content</h1>
  </div>
</template>

<script>
  export default {
     name: 'pizzaShopComponent'
  }
</script>

<style scoped>
</style>

and my updated view (index.cshtml)

<div id="my-vue-app" class="container">

    <h2>Better Components! Better Pizza Pizza!</h2>

    <div v-for="shop in pizzaShops">
        <p>{{ shop.id }} - {{ shop.name }}</p>
    </div>

    <pizzaShopComponent v-for="shop in pizzaShops" :shop="shop"></pizzaShopComponent>

</div>

Now I think all I need to do is connect the dots in my index.js, like this:

import pizzaShopComponent from './pizzashop.vue'

const pizzaShops = [
  //ommitted for brevity
];

const app = new Vue({
    el: '#my-vue-app',
    data: {
        pizzaShops
    },
    components: {
        pizzaShopComponent
    }
});

but this results in my ouput changing to:

Better Components! Better Pizza Pizza!

{{ shop.id }} - {{ shop.name }}

and this console message

SyntaxError: import declarations may only appear at top level of a module

I tried adding type="module" like this:

<script type="module" src="~/modules/mymodule/views/myviewfolder/index.js"></script>

Which does fix/suppress the console message but I still have this output:

Better Components! Better Pizza Pizza!

{{ shop.id }} - {{ shop.name }}

Can anyone tell me where I am going wrong? It seems like this should work?


Solution

  • Single File vue components require a build tool like webpack to generate a javascript file that you can then use within the browser. They have example templates to help get you started with .vue files: https://github.com/vuejs-templates

    But you don't need to be using .vue files, you can easily leverage components without the single file stuff: https://v2.vuejs.org/v2/guide/components.html