Skip to content

Instantly share code, notes, and snippets.

@jlauemoeller
Last active July 14, 2020 21:25
Show Gist options
  • Star 35 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jlauemoeller/d53ddd028387cd139c31bf2282dd12f4 to your computer and use it in GitHub Desktop.
Save jlauemoeller/d53ddd028387cd139c31bf2282dd12f4 to your computer and use it in GitHub Desktop.
Setting up a Basic Phoenix+Vue+Brunch project

Work in Progress: Phoenix + Vue + Brunch

This documents how I integrate Vue 2.0 with Phoenix 1.x using the default brunch pipeline.

The toolchain

Start out by adding the vue-brunch plugin. You will need a version later than 1.2.3 in order to be able to use the extractCSS option (see later). At the time of writing, 1.2.3 was still the version fetched by npm so I suggest just getting the tip of the dev branch for now (this branch is for Vue 2.0 compatibility anyway):

npm install git+https://github.com/nblackburn/vue-brunch.git#dev --save-dev

This will make it possible to use single-file .vue components, which I find to be a big help in keeping code organized and easy to follow. It will also enable pre-compiled Vue templates, which is a must for large applications.

In brunch-config.js add the following plugin configuration:

  plugins: {
    
    ...
    
    vue: {
      extractCSS: true,
      out: 'priv/static/css/components.css'
    }
    
    ...
  }

This will disable in-line CSS injection which at the moment results in a runtime error in the browser because of a missing Vueify dependency. Alternatively, you can leave out the extractCSS option and explicitly import the missing module to enable inline CSS style injection e.g. in your web/static/js/app.js file:

import "vueify/lib/insert-css"

but in this case I suspect you should consider wrapping the import in a Phoenix <%= if %> statement as it only makes sense in development, and then use the extractCSS option in prod.

The out option tells the Vueify compiler where to place the extracted component CSS -- don't foget to add a proper include statement to your application layout web/templates/layout/app.html.eex:

    <link rel="stylesheet" href="<%= static_path(@conn, "/css/components.css") %>">

At this point you are all set with respect to the toolchain and can just start the brunch watcher alongside the phoenix server, as usual:

npm run watch
mix phoenix.server

The vue-brunch plugin will use Vueify behind the scenes to extract and compile Vue templates from the .vue files and merge the resulting render functions along with the component code itself (also extracted) into the global priv/static/js/app.js file.

The code

I prefer to add all my Vue components as .vue files in a separate directory web/static/components, e.g. web/static/compnents/my-app.vue:

<template>
  <div class="my-app">
    <h1>My Awesome App</h1>
    {{message}}
  </div>
</template>

<script>
// Import other components using a relative path, e.g.
//
// import SecretSauce from './secret-sauce.vue'
// 
// or specific third-party modules installed via npm (and listed in
// the dependencies list in package.json), e.g.
//
// import _ from 'lodash'
//

export default {
  props: ['message'],
  
  // If you reference other components, then you must also list them
  // in the components map. e.g:
  //
  // components: {
  //   SecretSauce
  // }
}
</script>

<style lang="sass">
.my-app {
  margin-left: auto;
  margin-right: auto;

  width: 800px;
  h1 {
    text-align: center;
    margin-top: 50px;
    margin-bottom: 100px;
  }
}
</style>

I then bootstrap the Vue app in web/static/js/app.js, e.g:

'use strict';

import Vue from 'vue'
import MyApp from "../components/my-app.vue"

// Import "globally" used libraries -- importing them from Vue components alone
// seems to trip up brunch at the moment (they won't be included in the final
// app.js file)

import "lodash"  

// Create the main component

Vue.component('my-app', MyApp)

// And create the top-level view model:

new Vue({
  el: '#app',
  data() {
    return {
      // state for the top level component, e.g
      currentMessage: "Hello World"
    }
  },
  render: function (createElement) {
    return createElement(MyApp, {
      props: {
        // props for the top level component, e.g.
        message: this.currentMessage
      }
    })
  }
});

Finally, I add the top-level component tag to the "index" Phoenix template, e.g web/templates/home/index.html.eex:

<div id="app">
  <my-app :message='message'><my-app>
</div>

From there on out its .vue all the way down.

@gballet
Copy link

gballet commented Apr 1, 2017

Thanks for this explanation, that helped me go around a very annoying block. I have found that, for it to work, you must set the modules option in the .babelrc to commonjs, as shown below:

{
  "presets": [
    ["latest", {
      "es2015": { "modules": "commonjs" }
    }]
  ]
}

I had to do this because otherwise my browser would complain about export and import not existing. Have you not been experiencing this issue?

@brandonparsons
Copy link

@jlauemoeller Same question as gballet!

@Grantimus9
Copy link

@jlauemoeller - this is very helpful. Did you have any trouble with getting all of Babel's modules to load? I'm now working on getting vue-apollo integrated so that I can use a GraphQL interface between frontend and backend, and getting this error:

Uncaught Error: Cannot find module 'babel-runtime/helpers/taggedTemplateLiteral' from 'web/static/components/my-app.vue'

which I suspect has something to do with how I should be calling module includes. Any ideas? (repo for reference: https://github.com/Grantimus9/vuegraphqlphx)

@JodderHL
Copy link

JodderHL commented Apr 26, 2017

You can now use npm install vue-brunch --save-dev without the whole URL as it seems (2.0.1 is current version).

With your command I got:

npm install git+https://github.com/nblackburn/vue-brunch.git#dev --save-dev
npm ERR! git rev-list -n1 dev: fatal: ambiguous argument 'dev': unknown revision or path not in the working tree.
npm ERR! git rev-list -n1 dev: Use '--' to separate paths from revisions, like this:
npm ERR! git rev-list -n1 dev: 'git <command> [<revision>...] -- [<file>...]'

As there is no longer a #dev branch

@mithereal
Copy link

how do you use the .vue files after following your guide i get the error
i am placing in web/static/customer/components/app.vue

npm run watch

> @ watch /home/mithereal/Projects/broker/apps/site
> brunch watch --stdin

10 May 15:55:27 - info: compiling
10 May 15:55:27 - warn: web/static/customer/components/app.vue compiled, but not written. Check your templates.joinTo config
10 May 15:55:28 - info: compiled 45 files into 14 files, copied 40 in 5.4 sec

@abuisman
Copy link

abuisman commented Jun 7, 2017

Thanks for the tutorial.

I got promted to install babel-plugin-transform-runtime as well as vue-brunch so I ran:

npm install --save-dev babel-plugin-transform-runtime

And it works, but I am not sure if this is the right way to go. Any thoughts?

@dcy
Copy link

dcy commented Jun 18, 2017

Hi! The brunch-config.js of Phoenix1.3:

  // Configure your plugins
  plugins: {
    babel: {
      // Do not use ES6 compiler in vendor code
      ignore: [/vendor/]
    },
    vue: {
      extractCSS: true,
      out: 'priv/static/css/compoments.css'
    }
  },

It will be:

15:49:17 - error: ENOENT: no such file or directory, open 'priv/static/css/components.css'

@oherst
Copy link

oherst commented Jul 20, 2017

To prevent:

error: ENOENT: no such file or directory, open 'priv/static/css/components.css'

Change this bit like so:

vue: {
      extractCSS: true,
      out: '../priv/static/css/components.css'
    }

@ray-sh
Copy link

ray-sh commented Aug 9, 2017

Can't find components.css after add vue config in brunch-config.js
find . -name "*.css"
./node_modules/convert-source-map/test/fixtures/map-file-comment-double-slash.css
./node_modules/convert-source-map/test/fixtures/map-file-comment-inline.css
./node_modules/convert-source-map/test/fixtures/map-file-comment.css
./priv/static/css/app.css
./web/static/css/app.css
./web/static/css/phoenix.css

@GrantZukowski
Copy link

GrantZukowski commented Sep 18, 2018

I appreciate what you are trying to do here, but npm install git+https://github.com/nblackburn/vue-brunch.git#dev --save-dev doesn't even work.

npm ERR! git rev-list -n1 dev: fatal: ambiguous argument 'dev': unknown revision or path not in the working tree.
npm ERR! git rev-list -n1 dev: Use '--' to separate paths from revisions, like this:
npm ERR! git rev-list -n1 dev: 'git <command> [<revision>...] -- [<file>...]'
npm ERR! git rev-list -n1 dev: 
npm ERR! Linux 4.4.0-92-generic
npm ERR! argv "/usr/bin/node" "/usr/bin/npm" "install" "git+https://github.com/nblackburn/vue-brunch.git#dev" "--save-dev"
npm ERR! node v6.14.4
npm ERR! npm  v3.10.10
npm ERR! code 128

npm ERR! Command failed: git rev-list -n1 dev
npm ERR! fatal: ambiguous argument 'dev': unknown revision or path not in the working tree.
npm ERR! Use '--' to separate paths from revisions, like this:
npm ERR! 'git <command> [<revision>...] -- [<file>...]'
npm ERR! 
npm ERR! 
npm ERR! If you need help, you may report this error at:
npm ERR!     <https://github.com/npm/npm/issues>

npm ERR! Please include the following file with any support request:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment