<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="53698" data-post-id="53698">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="peerreynders" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/peerreynders/120/5826_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  peerreynders
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Seems to me lots of blogs about Phoenix get into Brunch like it’s somehow an essential part of Phoenix - <strong>it isn’t</strong>. When it comes to the development workflow there is one loose “connection” to Brunch in <code>my_app/config/dev.exs</code> - the <code>watchers</code> configuration. It contains the command to start up the process responsible for building bundles whenever the primary files change. Phoenix <a href="https://hexdocs.pm/phoenix_live_reload/Phoenix.LiveReloader.html" rel="noopener nofollow ugc">LiveReload</a> is then responsible for supplying the re-built files to the browser via a hidden <code>&lt;iframe&gt;</code> which <a href="https://github.com/phoenixframework/phoenix_live_reload/blob/v1.1.2/priv/static/phoenix_live_reload.js" rel="noopener nofollow ugc">coordinates the necessary updates in the browser</a>.</p>
<p>Vue with Webpack (instead of Brunch) can make use of the same mechanism. To demonstrate, start with a simple Vue.js component project:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">$ tree assets
assets
├── build
│   └── webpack.dev.conf.js
├── images
├── index.html
├── js
├── package.json
└── src
    ├── App.vue
    ├── assets
    │   └── phoenix.png
    └── main.js

</code></pre>
<p><code>assets/index.html</code>:</p>
<pre data-code-wrap="html"><code class="lang-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;!-- assets/index.html --&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;title&gt;Vue.js Demo Page&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id="app"&gt;&lt;/div&gt;
    &lt;script src="js/app.js"&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p><code>assets/src/App.vue</code>:</p>
<pre data-code-wrap="html"><code class="lang-html">&lt;template&gt;
  &lt;div class="foo"&gt;
    &lt;img src="./assets/phoenix.png"&gt;
    &lt;h1&gt;{{ msg }}&lt;/h1&gt;
    &lt;button id="change-message" @click="changeMessage"&gt;Change message&lt;/button&gt;
    &lt;p&gt;{{ passedProp }}&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
  export default {
    name: 'hello',
    data() {
      return {
        msg: 'Welcome to Your Vue.js App'
      };
    },
    props: ['passedProp'],
    methods: {
      changeMessage() {
        this.msg = 'new message';
      }
    }
  };
&lt;/script&gt;

&lt;style&gt;
  .foo {
    font-family: 'Avenir', Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
  }
&lt;/style&gt;
</code></pre>
<p><code>assets\src\main.js</code>:</p>
<pre data-code-wrap="javascript"><code class="lang-javascript">// src/main.js
import Vue from 'vue';
import App from './App';

Vue.config.productionTip = false;

new Vue({
  el: '#app',
  template: '&lt;App passedProp="Greetings!" /&gt;',
  components: { App }
});
</code></pre>
<p><code>assets/build/webpack.dev.conf.js</code>:</p>
<pre data-code-wrap="javascript"><code class="lang-javascript">// build/web.config.dev.js
const path = require('path');
const webpack = require('webpack');
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');

const PATHS = {
  assetsRoot: '/',
  assetsSubDirectory: '/'
};

function assetsPath(filePath) {
  return path.posix.join(PATHS.assetsSubDirectory, filePath);
}

function resolve (dir) {
  return path.join(__dirname, '..', dir);
}

module.exports = {
  entry: {
    app: './src/main.js'
  },
  output: {
    filename: 'js/[name].js',
    path: resolve(PATHS.assetsRoot)
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src')
    }
  },
  module: {
    rules :[
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        query: {
          presets: ['env']
        },
        include:[resolve('src')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 20000,
          name: assetsPath('images/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  // cheap-module-eval-source-map is faster for development
  devtool: '#cheap-module-eval-source-map',
  plugins: [
    new webpack.NoEmitOnErrorsPlugin(),
    new FriendlyErrorsPlugin()
  ],
  watchOptions: {
    ignored: /node_modules/
  }
};
</code></pre>
<p><code>assets/package.json</code>:</p>
<pre data-code-wrap="json"><code class="lang-json">{
  "name": "assets",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "devbuild": "node ./node_modules/webpack/bin/webpack.js  --config ./build/webpack.dev.conf.js",
    "watch": "./node_modules/.bin/webpack --watch-stdin --config ./build/webpack.dev.conf.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.0",
    "css-loader": "^0.28.7",
    "file-loader": "^1.1.5",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "url-loader": "^0.6.2",
    "vue-loader": "^13.0.5",
    "vue-style-loader": "^3.0.3",
    "vue-template-compiler": "^2.4.4",
    "webpack": "^3.6.0"
  },
  "dependencies": {
    "vue": "^2.4.4"
  }
}
</code></pre>
<p>Check this project with:</p>
<pre data-code-wrap="bash"><code class="lang-bash">assets $ npm i

...
added 623 packages in 10.714s

assets $ npm run watch

&gt; assets@1.0.0 watch /Users/wheatley/sbox/vue/phx/assets
&gt; webpack --watch-stdin --config ./build/webpack.dev.conf.js


Webpack is watching the files…
...
^C assets $
</code></pre>
<p>At this point it should be possible to view <code>assets/index.html</code> through a browser from the filesystem.</p>
<p>Now create a new Phoenix 1.3 project:</p>
<pre data-code-wrap="bash"><code class="lang-bash">assets $ cd ..
       $ mix phx.new my_app --no-brunch --no-ecto
</code></pre>
<p>and create a new directory <code>my_app/assets</code> and copy the following files into it:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">my_app/assets
├── build
│   └── webpack.dev.conf.js
├── package.json
└── src
    ├── App.vue
    ├── assets
    │   └── phoenix.png
    └── main.js
</code></pre>
<p>Modify <code>my_app/assets/build/webpack.dev.conf.js</code></p>
<pre data-code-wrap="javascript"><code class="lang-javascript">// build/web.config.dev.js
const path = require('path');
const webpack = require('webpack');
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');

const PATHS = {
  assetsRoot: '../priv/static', // CHANGED
  assetsSubDirectory: '/'
};

function assetsPath(filePath) {
  return path.posix.join(PATHS.assetsSubDirectory, filePath);
}

function resolve (dir) {
  return path.join(__dirname, '..', dir);
}

module.exports = {
  entry: {
    app: './src/main.js'
  },
  output: {
    filename: 'js/[name].js',
    path: resolve(PATHS.assetsRoot)
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'phoenix': resolve('../deps/phoenix/priv/static/phoenix.js'),                // ADDED
      'phoenix_html': resolve('../deps/phoenix_html/priv/static/phoenix_html.js'), // ADDED
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src')
    }
  },
  module: {
    rules :[
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        query: {
          presets: ['env']
        },
        include:[resolve('src')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 20000,
          name: assetsPath('images/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  // cheap-module-eval-source-map is faster for development
  devtool: '#cheap-module-eval-source-map',
  plugins: [
    new webpack.NoEmitOnErrorsPlugin(),
    new FriendlyErrorsPlugin()
  ],
  watchOptions: {
    ignored: /node_modules/
  }
};
</code></pre>
<p>Note the modified <code>PATHS.assetsRoot</code> and the additions to <code>resolve.alias</code>.</p>
<p>Modify <code>my_app/assets/src/main.js</code>:</p>
<pre data-code-wrap="javascript"><code class="lang-javascript">// src/main.js
import Vue from 'vue';
import App from './App';

import 'phoenix_html';            // ADDED
// import socket from "./socket";

Vue.config.productionTip = false;

new Vue({
  el: '#app',
  template: '&lt;App passedProp="Greetings!" /&gt;',
  components: { App }
});
</code></pre>
<p>Install the supporting packages:</p>
<pre data-code-wrap="bash"><code class="lang-bash">assets $ npm i
...
added 623 packages in 11.886s
</code></pre>
<p>Give it a quick check:</p>
<pre data-code-wrap="bash"><code class="lang-bash">$ npm run watch

&gt; assets@1.0.0 watch /Users/wheatley/sbox/vue/phx/my_app/assets
&gt; webpack --watch-stdin --config ./build/webpack.dev.conf.js


Webpack is watching the files…
...
^C assets $ 
</code></pre>
<p>Now modify <code>watchers</code> in <code>my_app/config/dev.exs</code>:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">config :my_app, MyAppWeb.Endpoint,
  http: [port: 4000],
  debug_errors: true,
  code_reloader: true,
  check_origin: false,
  watchers: [node: ["node_modules/webpack/bin/webpack.js", # CHANGED
                  "--watch-stdin",
                  "--config", "./build/webpack.dev.conf.js",
                  cd: Path.expand("../assets", __DIR__)]
            ]
</code></pre>
<p>to kick off Webpack watching the frontend source files.</p>
<p>The same thing can be accomplished by specifying a suitable <code>npm run</code> script, however this rather verbose incantantion is necessary for some MS Windows installations.</p>
<p>Replace <code>my_app/lib/my_app_web/templates/layout/app.html.eex</code> with</p>
<pre data-code-wrap="html"><code class="lang-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
    &lt;meta name="description" content=""&gt;
    &lt;meta name="author" content=""&gt;

    &lt;title&gt;Hello MyApp!&lt;/title&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;%= render @view_module, @view_template, assigns %&gt;
    &lt;script src="&lt;%= static_path(@conn, "/js/app.js") %&gt;"&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>and <code>my_app/lib/my_app_web/templates/page/index.html.eex</code> with</p>
<pre data-code-wrap="html"><code class="lang-html">&lt;div id="app"&gt;&lt;/div&gt;
</code></pre>
<p>Finally start Phoenix</p>
<pre data-code-wrap="bash"><code class="lang-bash">assets $ cd ..
my_app $ mix phx.server
Compiling 12 files (.ex)
Generated my_app app
[info] Running MyAppWeb.Endpoint with Cowboy using http://0.0.0.0:4000

Webpack is watching the files…

 DONE  Compiled successfully in 924ms20:40:49
...
  [14] ../deps/phoenix_html/priv/static/phoenix_html.js 1.23 kB {0} [built]
    + 6 hidden modules

</code></pre>
<p>Now open the browser at <code>http://localhost:4000/</code> to see the “Hello MyApp!” page.</p>
<p>If you modify the message text in <code>my_app/assets/src/App.vue</code> Phoenix LiveReloader will update the page in the browser shortly after you save the file (and the bundle has been rebuilt).</p>
<p>With a basic setup like this it should be possible to go further by “scavenging” features from other non-Phoenix Vue “donor” projects like the ones generated by <code>vue-cli</code>, e.g. <code>$ vue init webpack my-project</code>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="53698" data-batch-url="/posts/batch_likers">
                        8
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-53698" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="53698"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
    <div class="postbit" id="53796" data-post-id="53796">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="OvermindDL1" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/OvermindDL1/120/2677_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  OvermindDL1
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Brunch and webpack both are horrid and I don’t use them in my work project, I just use raw npm scripts (which is really what phoenix should do by default as it shows how you could plug in anything then).  ^.^</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="53796" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-53796" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="53796"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="53869" data-post-id="53869">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="peerreynders" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/peerreynders/120/5826_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  peerreynders
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I think adopters simply need to be reminded that there is no Brunch “lock-in” with Phoenix  - i.e. there is the freedom to use the frontend technologies that are the most appropriate for the job.</p>
<p>Brunch seems to be most appropriate for projects that primarily rely on server side EEx templates with some JavaScript widgets thrown in, using modules for code organization. Brunch is beginner-friendly for <em>learning Phoenix</em> with reference to the guides and the book - but IMO isn’t the right entry into the “modern JavaScript toolchain” - ultimately you have to start with npm/node. But JavaScript tooling is only a tangential concern to Phoenix’s role and existence and people need to stop assuming that every “out-of-the-box default” is automatically the best solution for their particular situation (while “Batteries included” products tend to be more popular, they can lead to “square peg in a round hole” solutions if defaults aren’t properly adapted).</p>
<p>Now Vue.js tooling strikes me as having a strong affinity/bias towards Webpack as a module bundler/build tool, so trying to use any other means (including Brunch) could possibly risk grief in the future. That being said Webpack is primarily optimized for “client-side generated DOM” based solutions, so the utility of server side EEx templates is somewhat limited; beyond <code>--no-brunch</code> <a href="https://groups.google.com/forum/#!topic/phoenix-talk/1Uzg0VOgMBk" rel="noopener nofollow ugc"><code>--no-html</code></a> may also be appropriate (possibly serving the frontend separately). However there could be use cases for Vue.js (with Webpack) + EEx templates as Vue.js promotes itself as “incrementally adoptable”.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="53869" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-53869" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="53869"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="53891" data-post-id="53891">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tme_317" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tme_317
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Wholly agree with <a class="mention" href="/u/peerreynders" rel="nofollow">@peerreynders</a> last point, there is definitely a use case for Vue.js + Webpack + EEx templates… and that’s exactly what I am doing.  As you said Vue.js is “incrementally adoptable” which works great as many pages just need a “sprinkle” of JS while other “pages” work better as a full SPA.</p>
<p>Webpack’s code splitting can easily build a larger bundle.js (including Vue itself and other required libraries used by most pages) which you can include in your layout and also generate small per-page javascript files for client-side code which differ for each page.  You can define Vue instances targeting divs generated by EEx and pass initial data down in <code>&lt;script&gt;</code> tags or pull it using Phoenix JSON or the channels API.</p>
<p>When you do this you can also use Phoenix/Vue.js for other areas of your app as a full SPA.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="53891" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-53891" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="53891"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="53978" data-post-id="53978">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="OvermindDL1" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/OvermindDL1/120/2677_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  OvermindDL1
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Something like <a href="https://hex.pm/packages/mbu" rel="nofollow"><code>mbu</code></a> would also be nice (perhaps integrated into mix itself) as it can handle non-elixir resources (with auto building via file watchers and all) quite easily, without any javascript build system needed (it’s built in elixir instead, even if you just have it delegate to webpack or so).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="53978" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-53978" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="53978"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="54032" data-post-id="54032">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="ndarilek" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  ndarilek
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Another option is using something like <a href="https://nuxtjs.org" rel="noopener nofollow ugc">Nuxt.js</a>. My latest designs ,make the assets/ folder a Nuxt app. I rip out Phoenix’s view layer entirely, and can use one of several options for serving app assets:</p>
<ul>
<li>Use <code>nuxt generate</code> to compile app assets to static HTML/JS which is output to priv/static. I then use the static plug along with a bit of code to serve index.html in place of 404s. This makes the app release self-contained, but of course leaves the option of proxying something like /api to the app and hosting static assets in some other cache-friendly way.</li>
<li>Run the Nuxt server directly and use Phoenix for /api or whatever. This gives you SSR for free, along with a pretty nice and fast dev setup, much quicker than regenerating static assets on each change. Note that, for the latter, Phoenix can start the dev server directly but it isn’t cleaned up on exit. <a href="https://github.com/nuxt/nuxt.js/pull/1658" rel="noopener nofollow ugc">This PR</a> fixes that, if anyone wants to poke it along that might be helpful.</li>
</ul>
<p>I like this design because it starts simple and scales up. The easiest use case just involves serving everything out of a self-contained release. More complicated use cases spin up one or more Node servers in separate containers, then use SSR or other techniques if desired.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="54032" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-54032" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="54032"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="54069" data-post-id="54069">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bkolobara" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bkolobara/120/6752_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bkolobara
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I have converged to a similar setup in most of my web projects. If you can avoid server-side rendering having a SPA and treating the backend as an api makes things much simpler. Even better with GraphQL.</p>
<p>I like to keep my frontend and backend in different folders. Usually the fronted is a pure npm project and the backend is a mix project. This has multiple benefits:</p>
<ul>
<li>Idiomatic Webpack, TypeScript and ReactRouter setup with hot reloading on the frontend. No need to worry about how to fit it into Elixir’s folder structure or introducing additional boilerplate into Elixir to make the hot reloading work.</li>
<li>The Webpack Dev Server proxies all /api call to the Elixir application running on another port.</li>
<li>In production all the static files are hosted on a CDN (404s are redirected to index.html and /api calls are proxied to the production Elixir instance).</li>
<li>If something doesn’t work googling becomes much easier. With already complex toolchains like JSX + TypeScript I prefer to stick to the simplest structure and avoid pushing it into another folder structure, in this case Elixir’s.</li>
</ul> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="54069" data-batch-url="/posts/batch_likers">
                        7
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-54069" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="54069"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="58621" data-post-id="58621">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Emily" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Emily/120/2422_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Emily
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>It’s been some time since this was posted.  Phoenix updated, VueJS updated.  Who knows what has changed with Brunch &amp; Wepack.  (I’m behind the curve.)</p>
<p>With that mind, I’m about to start another VueJS + Phoenix project.</p>
<p>I’m going to give this solution a go…</p>
<p><a href="https://medium.com/front-end-hacking/phoenix-and-vue-js-b974d8b91cb6" class="onebox" target="_blank" rel="noopener nofollow ugc">https://medium.com/front-end-hacking/phoenix-and-vue-js-b974d8b91cb6</a></p>
<p>It would require switching from Brunch to Webpack.</p>
<p>Am I creating any problems from myself moving from Brunch?</p>
<p>Is there any other simple solutions you would use instead for integrating VueJS?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="58621" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-58621" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="58621"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="58623" data-post-id="58623">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="wmnnd" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/wmnnd/120/4985_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  wmnnd
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>There are no inherent downsides to replacing Brunch since it’s really not very tightly integrated into Phoenix. No features of Phoenix rely on the assumption that you’re using Brunch.</p>
<p>However, if you don’t feel like setting up more complicated JS tooling, I think <code>vue-brunch</code> does a fine enough job of building Vue applications without any additional config.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="58623" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-58623" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="58623"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #29"></div>
  </section>
</div>
    <div class="postbit" id="58625" data-post-id="58625">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="acrolink" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/acrolink/120/8985_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  acrolink
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="Emily" data-post="29" data-topic="5108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/emily/48/2422_2.png" class="avatar"> Emily:</div>
<blockquote>
<p>With that mind, I’m about to start another VueJS + Phoenix project.</p>
</blockquote>
</aside>
<p>I do it this way.. Create an API only Phoenix application with <code>mix phx.new my_app --no-html --no-brunch</code> and use <code>VueJS</code> for all front-end UI. This is fine as long as your application is small - medium sized (since all front-end logic will ultimately be contained in a single JS file, you simply don’t want to end with a 4 MB JS file).</p>
<p>If its is a complex big project, then use normal Phoenix HTML pages with some <code>VueJS</code> integration on page level.</p>
<p>Note: I use <code>webpack</code> for the <code>VueJS</code> application.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="58625" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/how-to-get-phoenix-vuejs-working-together/5108/31">Post #30</a>
	                </div>
	            </div>
              <div id="likers-container-58625" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="58625"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #30"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/5108/load_more?page=4">Load more posts (12 remaining)</a>
</div></template></turbo-stream>