{"id":24545,"date":"2019-05-14T12:15:07","date_gmt":"2019-05-14T09:15:07","guid":{"rendered":"http:\/\/www.webcodegeeks.com\/?p=24545"},"modified":"2020-05-22T15:35:17","modified_gmt":"2020-05-22T12:35:17","slug":"gotham-from-start-heroku","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/","title":{"rendered":"Gotham &#8211; From Start to Heroku"},"content":{"rendered":"\n<p>In this article, we\u2019ll implement and deploy a Gotham full-stack web framework using the Tera template system, Webpack for a complete front-end asset management, a minimal VueJS and CoffeeScript web app and deploy to Heroku.&nbsp;<a href=\"https:\/\/gotham.rs\/\">Gotham<\/a>&nbsp;is a Rust framework which is focused on safety, speed, concurrency and async everything.&nbsp;<a href=\"https:\/\/webpack.js.org\/\">Webpack<\/a>&nbsp;is a NodeJS website asset preprocessor and bundler which can let you use any of your favorite front end technologies. Combining these technologies allow for a small footprint on the server, which means saving money on infrastructure, very fast performance in page load for higher visitor retention and the full flexibility of client side code available to you for web design without limitations.<\/p>\n\n\n\n<p>Because there is a lot to unpack here, this article will cover a step-by-step guide to launch these features on Heroku and advise you on common issues that need to be considered.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installing the dependencies<\/h2>\n\n\n\n<p>Before we worry about the server environment, we need to be able to run the server on our own system. You will need to install each of the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/www.rust-lang.org\/en-US\/install.html\">Rust<\/a><\/li><li><a href=\"https:\/\/www.ruby-lang.org\/en\/downloads\/\">Ruby<\/a><\/li><li><a href=\"https:\/\/nodejs.org\/en\/download\/\">NodeJS<\/a><\/li><li><a href=\"https:\/\/yarnpkg.com\/en\/\">Yarn<\/a><\/li><li><a href=\"https:\/\/github.com\/ruby\/rake\">Rake<\/a><\/li><li><a href=\"https:\/\/bundler.io\/\">Bundler<\/a><\/li><li><a href=\"https:\/\/github.com\/danielpclark\/webpacker-cli\">WebpackerCli<\/a><\/li><li><a href=\"https:\/\/devcenter.heroku.com\/articles\/heroku-cli\">Heroku Cli<\/a><\/li><\/ul>\n\n\n\n<p>Since the kind of installation you have to go through depends on your operating system, simply follow the steps provided in the links above for each item.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting up the project<\/h2>\n\n\n\n<p>First we generate a Rust project with<\/p>\n\n\n\n<pre class=\"brush:php\">cargo new mouse\ncd mouse\n<\/pre>\n\n\n\n<p>\n\nWe\u2019ll call this project mouse, as in Mighty Mouse. Next we\u2019ll use WebpackerCli to install the initial files for using&nbsp;<a href=\"https:\/\/github.com\/rails\/webpacker\">Webpacker<\/a>&nbsp;in our project.\n\n<\/p>\n\n\n\n<pre class=\"brush:php\">webpacker-cli init\n<\/pre>\n\n\n\n<p>\n\nNext we\u2019ll edit our&nbsp;<code>Cargo.toml<\/code>&nbsp;to add the dependencies we need. Add the following to the end of it.\n\n<\/p>\n\n\n\n<pre class=\"brush:php\">[dependencies]\ngotham = \"0.3.0\"\ngotham_derive = \"0.3.0\"\n\nhyper = \"0.12.13\"\nmime = \"0.3.12\"\nlazy_static = \"1.2\"\ntera = \"0.11\"\nwebpacker = \"~0.3\"\n\n[build-dependencies]\nwebpacker = \"~0.3\"\n<\/pre>\n\n\n\n<p>\n\nNow add the following to your&nbsp;<code>build.rs<\/code>&nbsp;file in the projects main directory.\n\n<\/p>\n\n\n\n<pre class=\"brush:php\">extern crate webpacker;\n\nfn main() {\n    println!(\"Validating dependencies\u2026\");\n    assert!(webpacker::valid_project_dir());\n    \n    println!(\"Compiling assets\u2026\");\n    let _ = webpacker::compile();\n}\n<\/pre>\n\n\n\n<p>Now whenever you run the cargo command to build your project, it will verify your dependencies, bundle and prepare your assets. This is very helpful when you deploy to Heroku as it will tell you which dependencies are missing.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A working project<\/h2>\n\n\n\n<p>The hello world example given on the main page for Gotham is as follows. Put this in your&nbsp;<code>src\/main.rs<\/code>&nbsp;file.<\/p>\n\n\n\n<pre class=\"brush:php\">extern crate gotham;\n\nuse gotham::state::State;\n\nconst HELLO_WORLD: &amp;'static str = \"Hello World!\";\n\npub fn say_hello(state: State) -&gt; (State, &amp;'static str) {\n    (state, HELLO_WORLD)\n}\n\npub fn main() {\n    let addr = \"127.0.0.1:7878\";\n    println!(\"Listening for requests at http:\/\/{}\", addr);\n    gotham::start(addr, || Ok(say_hello))\n}\n<\/pre>\n\n\n\n<p>At this point you can run&nbsp;<code>cargo run<\/code>&nbsp;and use your browser to navigate to&nbsp;<code>http:\/\/127.0.0.1:7878<\/code>&nbsp;to see the hello world example.<\/p>\n\n\n\n<p>From here we\u2019re going to remove the&nbsp;<code>const HELLO_WORLD<\/code>&nbsp;line and the entire&nbsp;<code>say_hello<\/code>&nbsp;method. We\u2019ll add a method named&nbsp;<code>index_page<\/code>, add a method named&nbsp;<code>router<\/code>, and we\u2019ll update the last line of main method to use them.<\/p>\n\n\n\n<pre class=\"brush:php\">extern crate gotham;\nextern crate hyper;\n\nuse gotham::state::State;\nuse gotham::router::builder::{\n    build_simple_router,\n    DefineSingleRoute,\n    DrawRoutes\n};\nuse gotham::router::Router;\nuse hyper::Method;\n\npub fn index_page(state: State) -&gt; (State, (mime::Mime, String)) {\n    let rendered = \"Hello World!\".to_string();\n\n    (state, (mime::TEXT_HTML, rendered))\n}\n\npub fn router() -&gt; Router {\n    build_simple_router(|route| {\n        route.\n            request(vec![Method::GET, Method::HEAD], \"\/\").\n            to(index_page);\n    })  \n}\n\npub fn main() {\n    let addr = \"127.0.0.1:7878\";\n    println!(\"Listening for requests at http:\/\/{}\", addr);\n    gotham::start(addr, router())\n}\n<\/pre>\n\n\n\n<p>This changes introduce mime type support in the method which we now use a router to get to. The router is mapping any request to the root url&nbsp;<code>\/<\/code>&nbsp;to the&nbsp;<code>index_page<\/code>&nbsp;method.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>For this project we\u2019ll follow Rails\u2019 outline for organizing the files for the site.<\/p><\/blockquote>\n\n\n\n<p>Now to demonstrate how to serve static assets in Gotham. Create the following directory structure&nbsp;<code>app\/assets\/stylesheets<\/code>&nbsp;in the root of your project. Create a file in that last directory named&nbsp;<code>application.css<\/code>&nbsp;and give it some styles like so.<\/p>\n\n\n\n<pre class=\"brush:php\">div {\n  margin: 0 12px 0 12px;\n}\n\nfooter {\n  margin-top: 40px;\n  font-size: 6pt;\n}\n<\/pre>\n\n\n\n<p>Towards the top of&nbsp;<code>src\/main.rs<\/code>&nbsp;add&nbsp;<code>use<br>gotham::handler::assets::FileOptions;<\/code>&nbsp;and inside the&nbsp;<code>build_simple_router<\/code>&nbsp;code block add the following route option after the one you currently have in there.<\/p>\n\n\n\n<pre class=\"brush:php\">route.\n    get(\"style\/*\").\n    to_dir(\n        FileOptions::new(\"app\/assets\/stylesheets\").\n            with_cache_control(\"no-cache\").\n            with_gzip(true).\n            build(),\n    );\n<\/pre>\n\n\n\n<p>This will route any requests that try to access the&nbsp;<code>style\/<\/code>&nbsp;path in the url to any file that\u2019s in&nbsp;<code>app\/assets\/stylesheets<\/code>. In our HTML code we\u2019ll link to this style directly. Before that though you can now try to load the url&nbsp;<code>http:\/\/127.0.0.1:7878\/style\/application.css<\/code>&nbsp;after you run&nbsp;<code>cargo run<\/code>&nbsp;and see the styles we\u2019ve entered in.<\/p>\n\n\n\n<p>We\u2019re now ready to introduce HTML pages with the Tera templating system.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tera templating in Gotham<\/h2>\n\n\n\n<p><a href=\"https:\/\/tera.netlify.com\/\">Tera<\/a>&nbsp;is a templating DSL for Rust which serializes Rust objects before processing the views. There\u2019s very little learning curve to using it as it is designed with common template tasks in mind.<\/p>\n\n\n\n<p>We\u2019ll rewrite the&nbsp;<code>index_page<\/code>&nbsp;method to now use Tera and include the stylesheet we\u2019ve created. Also we\u2019ll create a core object to load all our templates from and provide it with a path for our views. In your&nbsp;<code>src\/main.rs<\/code>&nbsp;file update it for the following.<\/p>\n\n\n\n<pre class=\"brush:php\">#[macro_use]\nextern crate lazy_static;\nextern crate tera;\nuse tera::{Context, Tera};\n\nlazy_static! {\n    pub static ref TERA: Tera =\n        Tera::new(\"app\/views\/**\/*.tera\").\n            map_err(|e| {\n                eprintln!(\"Parsing error(s): {}\", e);\n                ::std::process::exit(1);\n            }).\n            unwrap();\n}\n\npub fn index_page(state: State) -&gt; (State, (mime::Mime, String)) {\n    let mut context = Context::new();\n\n    let styles = &amp;[\"style\/application.css\"];\n    let sources: &amp;[&amp;'static str] = &amp;[];\n    context.insert(\"application_styles\", styles);\n    context.insert(\"application_sources\", sources);\n\n    let rendered = TERA.render(\"landing_page\/index.html.tera\", &amp;context).unwrap();\n    (state, (mime::TEXT_HTML, rendered))\n}\n<\/pre>\n\n\n\n<p>In the&nbsp;<code>lazy_static!<\/code>&nbsp;block we create the&nbsp;<code>TERA<\/code>&nbsp;object which will load all the views and templates into an internal hash like lookup system and by which we will use it to render views with given contexts. The context we provide a view will contain the objects the view are to be updated or generated with.<\/p>\n\n\n\n<p>Now we need to create our application template and our landing page for the above code to work. Create the file&nbsp;<code>app\/views\/layouts\/application.html.tera<\/code><\/p>\n\n\n\n<pre class=\"brush:xml\">&lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\"&gt;\n&lt;head&gt;\n  {% block head %}{% for style in application_styles -%}\n    &lt;link rel=\"stylesheet\" href=\"{{ style }}\" \/&gt;\n  {% endfor %}{% for source in application_sources -%}\n    &lt;script src=\"{{ source }}\"&gt;&lt;\/script&gt;\n  {% endfor %}\n  &lt;title&gt;{% block title %}{% endblock title %}&lt;\/title&gt;\n  {% endblock head %}\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;header&gt;\n    {% block header %}{% endblock header %}\n  &lt;\/header&gt;\n  &lt;div id=\"content\"&gt;\n    {% block content %}{% endblock content %}\n  &lt;\/div&gt;\n  &lt;footer&gt;\n    {% block footer %}\u00a9 Copyright 2018{% endblock footer %}\n  &lt;\/footer&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/pre>\n\n\n\n<p>The&nbsp;<code>block<\/code>&nbsp;and&nbsp;<code>endblock<\/code>&nbsp;tags allow you to place default page content into each section while also allowing any pages that inherit this template to optionally overwrite it, or even add to it by calling&nbsp;<code>super<\/code>&nbsp;first. The&nbsp;<code>for<\/code>&nbsp;loops above use a value provided from context insertion from our code \u2014 and those must exist. The&nbsp;<code>for<\/code>loop then iterates over the collection of items provided and can be used to insert text internally with the&nbsp;<code>{{ }}<\/code>&nbsp;syntax.<\/p>\n\n\n\n<p>Now let\u2019s create the index page that inherits from this. Create the file&nbsp;<code>app\/views\/landing_page\/index.html.tera<\/code>&nbsp;and place the following in it.<\/p>\n\n\n\n<pre class=\"brush:xml\">{% extends \"layouts\/application.html.tera\" %}\n\n{% block title %}Mouse{% endblock title %}\n\n{% block content %}\n\n  &lt;h1&gt;Mouse&lt;\/h1&gt;\n  You have arrived.\n\n{% endblock content %}\n<\/pre>\n\n\n\n<p>Here we use Tera\u2019s extend keyword to choose the template we wish to employ and then we replace to blocks from the template,&nbsp;<code>title<\/code>&nbsp;and&nbsp;<code>content<\/code>. Go ahead and spin up the server and try it out;&nbsp;<code>cargo run<\/code>&nbsp;and navigate your browser to&nbsp;<code>http:\/\/127.0.0.1:7878<\/code>. You have now successfully deployed templating.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Adding VueJS and CoffeeScript support<\/h2>\n\n\n\n<p>Most of the tooling for this was done when we added the&nbsp;<strong>webpacker<\/strong>&nbsp;crate, installed&nbsp;<strong>WebpackerCli<\/strong>, and added build hooks in the&nbsp;<code>build.rs<\/code>&nbsp;code. We have three parts now to do<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Routing for the Webpack\u2019d assets<\/li><li>Implement helper methods for looking up assets from the manifest<\/li><li>Install and configure the Webpack dependencies for VueJS &amp; CoffeeScript<\/li><\/ul>\n\n\n\n<p>Routing is simple as we will be following the same technique we used for our stylesheet earlier. We\u2019ll set our webpack\u2019d assets routing url path to a globally available static value for convenience should we ever desire to change it. In our&nbsp;<code>src\/main.rs<\/code>&nbsp;file add:<\/p>\n\n\n\n<pre class=\"brush:php\">pub static ASSET_DIRECTORY: &amp;'static str = \"public\";\n<\/pre>\n\n\n\n<p>\n\nAnd add the following to the&nbsp;<code>build_simple_router<\/code>&nbsp;routing block.\n\n<\/p>\n\n\n\n<pre class=\"brush:php\">route.\n    get(&amp;format!(\"{}\/*\", &amp;ASSET_DIRECTORY)).\n    to_dir(\n        FileOptions::new(\"public\").\n            with_cache_control(\"no-cache\").\n            with_gzip(true).\n            build(),\n    );\n<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>Note the path we use to share publicly doesn\u2019t have to be the same name as the directory in which webpacker prepares the assets.<\/p><\/blockquote>\n\n\n\n<p>Now with the first step done lets work on our manifest and helper methods. In the same&nbsp;<code>lazy_static<\/code>&nbsp;block we defined&nbsp;<code>TERA<\/code>&nbsp;earlier add the following:<\/p>\n\n\n\n<pre class=\"brush:php\">extern crate webpacker;\nuse webpacker::Manifest;\n\nlazy_static! {\n    pub static ref MANIFEST: Manifest =\n        webpacker::manifest(None).unwrap();\n}\n<\/pre>\n\n\n\n<p>\n\nThis creates a hash lookup table for each of our assets that Webpack has preprocessed and prepared. Now let\u2019s add our helper methods to simplify getting a full routing path from a given file name. In&nbsp;<code>src\/main.rs<\/code>&nbsp;add the following.\n\n<\/p>\n\n\n\n<pre class=\"brush:php\">use webpacker::asset_path::AssetPath;\nuse std::ops::Deref;\n\npub fn asset_source(key: &amp;str) -&gt; String {\n    AssetPath::new(ASSET_DIRECTORY, key, MANIFEST.deref()).into()\n}\n\npub fn javascript_pack_tag(key: &amp;str) -&gt; String {\n    let key = format!(\"{}.js\", basename(key));\n    asset_source(&amp;key)\n}\n\npub fn stylesheet_pack_tag(key: &amp;str) -&gt; String {\n    let key = format!(\"{}.css\", basename(key));\n    asset_source(&amp;key)\n}\n\nfn basename&lt;'a&gt;(s: &amp;'a str) -&gt; &amp;'a str {\n    s.rsplit('\/').next().unwrap().\n        split('.').next().unwrap()\n}\n<\/pre>\n\n\n\n<p>When Webpack processes CoffeeScript files the result will be a JavaScript file so we can give our helper method the original filename&nbsp;<code>example.coffee<\/code>&nbsp;and it changes it to&nbsp;<code>example.js<\/code>&nbsp;as the key to lookup from the file manifest which then gives us a full path such as&nbsp;<code>\/packs\/example-779d5e71ab17b09de712.js<\/code>&nbsp;and that source path gets inserted into our webpage providing both pre-processing and cache invalidation. The same thing also occurs with stylesheets from SASS files to CSS. Using these helper methods to provide the full link path to our web document source references provides an up to date code experience for the end user.<\/p>\n\n\n\n<p>Now that we have our asset file manifest helper methods we can include the default JavaScript script that Webpacker added by changing the&nbsp;<code>sources<\/code>&nbsp;line in our&nbsp;<code>index_page<\/code>&nbsp;method to the following:<\/p>\n\n\n\n<pre class=\"brush:php\">let sources = &amp;[&amp;asset_source(\"application.js\")];\n<\/pre>\n\n\n\n<p>Now when you run your program with&nbsp;<code>cargo run<\/code>&nbsp;you can look at the source code of the page and it now includes a valid script inclusion for a versioned&nbsp;<code>application.js<\/code>file.<\/p>\n\n\n\n<p>Now that the second step is done let\u2019s do the third step of installing and configuring CoffeeScript and VueJS for Webpacker. Ideally you can just run&nbsp;<code>webpacker-cli install:vue<\/code>&nbsp;and&nbsp;<code>webpacker-cli install:coffee<\/code>. This will create the configuration files for you but be sure to pay attention as to whether the Yarn dependencies are installed. As of this writing VueJS dependencies are requiring you to manually select the version number for&nbsp;<code>vue-loader<\/code>. The output displays the command you should run to add the Yarn dependencies.<\/p>\n\n\n\n<p>If you want to manually install VueJS then you could do it as follows. Run<\/p>\n\n\n\n<pre class=\"brush:php\">yarn add vue vue-loader@15.4.2 vue-template-compiler<\/pre>\n\n\n\n<p>\n\nCreate the file&nbsp;<code>config\/webpack\/loaders\/vue.js<\/code>&nbsp;and write in the following.\n\n<\/p>\n\n\n\n<pre class=\"brush:php\">module.exports = {\n  test: \/\\.vue$\/,\n  use: [{\n    loader: 'vue-loader'\n  }]\n}\n<\/pre>\n\n\n\n<p>\n\nAnd update the&nbsp;<code>config\/webpack\/environments.js<\/code>&nbsp;file to add:\n\n<\/p>\n\n\n\n<pre class=\"brush:php\">const { VueLoaderPlugin } = require('vue-loader')\nconst vue =  require('.\/loaders\/vue')\n\nenvironment.plugins.append('VueLoaderPlugin', new VueLoaderPlugin())\nenvironment.loaders.append('vue', vue)\n<\/pre>\n\n\n\n<p>Add the above after webpacker is included and before the module exports line. And that\u2019s how easy it is to manually add support for something to Webpacker. Now whenever you write VueJS code in your&nbsp;<code>app\/javascript\/packs<\/code>&nbsp;folder you can include it with the&nbsp;<code>_pack<\/code>&nbsp;helper methods we wrote earlier.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">VueJS and CoffeeScript example<\/h2>\n\n\n\n<p>The install command for WebpackerCli creates some examples under both&nbsp;<code>app\/javascript<\/code>&nbsp;and&nbsp;<code>app\/javascript\/packs<\/code>. We will use the&nbsp;<code>app\/javascript\/app.vue<\/code>example as it is and if you didn\u2019t generate one with the install command here it is below:<\/p>\n\n\n\n<pre class=\"brush:xml\">&lt;template&gt;\n  &lt;div id=\"app\"&gt;\n    &lt;p&gt;{{ message }}&lt;\/p&gt;\n  &lt;\/div&gt;\n&lt;\/template&gt;\n\n&lt;script&gt;\nexport default {\n  data: function () {\n    return {\n      message: \"Hello Vue!\"\n    }   \n  }\n}\n&lt;\/script&gt;\n\n&lt;style scoped&gt;\np {\n  font-size: 2em;\n  text-align: center;\n}\n&lt;\/style&gt;\n<\/pre>\n\n\n\n<p>\n\nNow delete both&nbsp;<code>app\/javascript\/hello_vue.js<\/code>&nbsp;and&nbsp;<code>app\/javascript\/hello_coffee.coffee<\/code>&nbsp;and create the file&nbsp;<code>app\/javascript\/hello.coffee<\/code>&nbsp;and place the following in it.\n\n<\/p>\n\n\n\n<pre class=\"brush:java\">import Vue from 'vue\/dist\/vue.esm'\nimport App from '..\/app.vue'\n\ndocument.addEventListener('DOMContentLoaded', -&gt;\n  element = document.getElementById 'vue-app'\n\n  if element?\n    app = new Vue(\n      el: element\n      render: (h) -&gt; h App \n    ) \n\n  # Vue.config.devtools = true\n)\n<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>In my experimentation the environment JavaScript detects it keeps reporting&nbsp;<strong>production<\/strong>&nbsp;regardless of changing local environment variables so if you\u2019d like to use the VueJS Devtool addon for your browser you should uncomment the devtools line above while you work.<\/p><\/blockquote>\n\n\n\n<p>Now that we have the code to test we need only to include it in our site. Let\u2019s change our&nbsp;<code>styles<\/code>&nbsp;and&nbsp;<code>sources<\/code>&nbsp;values in the&nbsp;<code>index_page<\/code>&nbsp;method in&nbsp;<code>src\/main.rs<\/code>&nbsp;to the following:<\/p>\n\n\n\n<pre class=\"brush:php\">let sources = &amp;[\n    &amp;asset_source(\"application.js\"),\n    &amp;javascript_pack_tag(\"hello\")\n];  \n\nlet styles = &amp;[\n    \"style\/application.css\",\n    &amp;stylesheet_pack_tag(\"hello\")\n]; \n<\/pre>\n\n\n\n<p>\n\nWe\u2019re including both the script and style for our VueJS code by using our&nbsp;<code>_pack<\/code>method helpers for the&nbsp;<code>hello.coffee<\/code>&nbsp;file. Now add the following to&nbsp;<code>app\/views\/landing_page\/index.html.tera<\/code>&nbsp;within the&nbsp;<code>content<\/code>&nbsp;block.\n\n<\/p>\n\n\n\n<pre class=\"brush:xml\">&lt;div id=\"vue-app\"&gt;&lt;\/div&gt;\n<\/pre>\n\n\n\n<p>And now you have a working VueJS &amp; CoffeeScript app when you run&nbsp;<code>cargo<br>run<\/code>&nbsp;and view http:\/\/127.0.0.1:7878 .<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Deploying to Heroku<\/h2>\n\n\n\n<p>To deploy to Heroku you will need to use three separate buildpacks together for NodeJS, Ruby, and Rust. First let\u2019s initialize Heroku in our project. Use the Heroku Cli tool:<\/p>\n\n\n\n<pre class=\"brush:php\">heroku create\nheroku buildpacks:add heroku\/nodejs\nheroku buildpacks:add heroku\/ruby\nheroku buildpacks:add emk\/rust\n<\/pre>\n\n\n\n<p><em>It\u2019s very important to include Rust as the last buildpack.<\/em><\/p>\n\n\n\n<p>Before we can deploy we need to change the way our program hosts it\u2019s IP and PORT. Open the&nbsp;<code>src\/main.rs<\/code>&nbsp;file and change the&nbsp;<code>main<\/code>&nbsp;method to the following.<\/p>\n\n\n\n<pre class=\"brush:php\">use std::env;\n\npub fn main() {\n    let port = env::var(\"PORT\").expect(\"PORT env not found!\");\n    let addr = format!(\"0.0.0.0:{}\", port);\n    println!(\"Listening for requests at {}\", addr);\n    gotham::start(addr, router())\n}\n<\/pre>\n\n\n\n<p>The application won\u2019t work on Heroku without binding to both the address&nbsp;<code>0.0.0.0<\/code>and the port number defined by the environment variable. Now to test it locally you have to assign a port number so the command in bash would look like&nbsp;<code>PORT=7878 cargo run<\/code>.<\/p>\n\n\n\n<p>Next we have to let Heroku know what command to run to run the application. Open up a file name&nbsp;<code>Procfile<\/code>&nbsp;and place the following.<\/p>\n\n\n\n<p>&lt;<\/p>\n\n\n\n<p>pre&gt;<code>web: target\/release\/mouse<\/code><\/p>\n\n\n\n<p>The last part is of course the name of the application which we gave it; mouse. Now you need only to commit the source code with git and upload it to heroku.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>Be sure your&nbsp;<code>.gitignore<\/code>&nbsp;file has lines for&nbsp;<code>node_modules<\/code>&nbsp;and&nbsp;<code>tmp<\/code>&nbsp;as you don\u2019t want to upload those.<\/p><\/blockquote>\n\n\n\n<pre class=\"brush:php\">git add .\ngit commit -m \"Heroku ready\"\ngit push heroku master\n<\/pre>\n\n\n\n<p>After time enough to brew coffee you can now open the deployed website with the command&nbsp;<code>heroku open<\/code>. And viola! You\u2019ve achieved implementing and deploying a fullstack Gotham app.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>As your application grows it will help to organize similar source code categories together in their own separate files&nbsp;<em>(such as moving routing to&nbsp;<code>src\/route.rs<\/code>)<\/em>.<\/p><\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>This how-to should save you tons of time figuring out how to get a fullstack Gotham app ready. You can view the source code for this example&nbsp;<a href=\"https:\/\/github.com\/danielpclark\/Gotham-Fullstack-Example\">here on Github<\/a>.<\/p>\n\n\n\n<p>What you have here is a quicker way to get up and going with a very fast and capable website. Fast being what Rust and Gotham bring to the table and capable being what Webpacker and the entire JavaScript ecosystem bring with it. When you use Rust for your website you get the best performance you can in delivery. Any slowness experienced will be from other factors like unoptimized database queries or network latency. It\u2019s exciting to be working with both powerful and performant technologies when delivering content. Enjoy!<\/p>\n\n\n\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td>\n<p>Published on Web Code Geeks with permission by Daniel P. Clark, partner at our <a href=\"\/\/www.webcodegeeks.com\/join-us\/wcg\/\" target=\"_blank\" rel=\"noopener noreferrer\">WCG program<\/a>. See the original article here: <a href=\"https:\/\/blog.codeship.com\/gotham-from-start-to-heroku\/\/\" target=\"_blank\" rel=\"noopener noreferrer\">Gotham \u2014 From Start to Heroku<\/a><\/p>\n<p>Opinions expressed by Web Code Geeks contributors are their own.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>In this article, we\u2019ll implement and deploy a Gotham full-stack web framework using the Tera template system, Webpack for a complete front-end asset management, a minimal VueJS and CoffeeScript web app and deploy to Heroku.&nbsp;Gotham&nbsp;is a Rust framework which is focused on safety, speed, concurrency and async everything.&nbsp;Webpack&nbsp;is a NodeJS website asset preprocessor and bundler &hellip;<\/p>\n","protected":false},"author":146,"featured_media":927,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[565,244,366],"class_list":["post-24545","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-development","tag-gotham","tag-heroku","tag-rust"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Gotham - From Start to Heroku - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"Interested to learn about Gotham? Check our article implementing and deploying a Gotham full-stack web framework using the Tera template system\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Gotham - From Start to Heroku - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"Interested to learn about Gotham? Check our article implementing and deploying a Gotham full-stack web framework using the Tera template system\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2019-05-14T09:15:07+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-05-22T12:35:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Daniel P. Clark\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Daniel P. Clark\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"15 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/\"},\"author\":{\"name\":\"Daniel P. Clark\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/a79c83c57cba5d8a6e46462149890b5e\"},\"headline\":\"Gotham &#8211; From Start to Heroku\",\"datePublished\":\"2019-05-14T09:15:07+00:00\",\"dateModified\":\"2020-05-22T12:35:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/\"},\"wordCount\":2117,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\",\"keywords\":[\"Gotham\",\"Heroku\",\"Rust\"],\"articleSection\":[\"Web Dev\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/\",\"name\":\"Gotham - From Start to Heroku - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\",\"datePublished\":\"2019-05-14T09:15:07+00:00\",\"dateModified\":\"2020-05-22T12:35:17+00:00\",\"description\":\"Interested to learn about Gotham? Check our article implementing and deploying a Gotham full-stack web framework using the Tera template system\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Web Dev\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/web-development\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Gotham &#8211; From Start to Heroku\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/a79c83c57cba5d8a6e46462149890b5e\",\"name\":\"Daniel P. Clark\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/2342ad14824a1064823dcec81641a12136a3492abae522e473ec723cbfb84bce?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/2342ad14824a1064823dcec81641a12136a3492abae522e473ec723cbfb84bce?s=96&d=mm&r=g\",\"caption\":\"Daniel P. Clark\"},\"description\":\"Daniel P. Clark is a freelance developer, as well as a Ruby and Rust enthusiast. He writes about Ruby on his personal site.\",\"url\":\"https:\/\/www.webcodegeeks.com\/author\/daniel-clark\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Gotham - From Start to Heroku - Web Code Geeks - 2026","description":"Interested to learn about Gotham? Check our article implementing and deploying a Gotham full-stack web framework using the Tera template system","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/","og_locale":"en_US","og_type":"article","og_title":"Gotham - From Start to Heroku - Web Code Geeks - 2026","og_description":"Interested to learn about Gotham? Check our article implementing and deploying a Gotham full-stack web framework using the Tera template system","og_url":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_published_time":"2019-05-14T09:15:07+00:00","article_modified_time":"2020-05-22T12:35:17+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","type":"image\/jpeg"}],"author":"Daniel P. Clark","twitter_card":"summary_large_image","twitter_creator":"@webcodegeeks","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Daniel P. Clark","Est. reading time":"15 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/"},"author":{"name":"Daniel P. Clark","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/a79c83c57cba5d8a6e46462149890b5e"},"headline":"Gotham &#8211; From Start to Heroku","datePublished":"2019-05-14T09:15:07+00:00","dateModified":"2020-05-22T12:35:17+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/"},"wordCount":2117,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","keywords":["Gotham","Heroku","Rust"],"articleSection":["Web Dev"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/","url":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/","name":"Gotham - From Start to Heroku - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","datePublished":"2019-05-14T09:15:07+00:00","dateModified":"2020-05-22T12:35:17+00:00","description":"Interested to learn about Gotham? Check our article implementing and deploying a Gotham full-stack web framework using the Tera template system","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/web-development\/gotham-from-start-heroku\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Web Dev","item":"https:\/\/www.webcodegeeks.com\/category\/web-development\/"},{"@type":"ListItem","position":3,"name":"Gotham &#8211; From Start to Heroku"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/a79c83c57cba5d8a6e46462149890b5e","name":"Daniel P. Clark","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/2342ad14824a1064823dcec81641a12136a3492abae522e473ec723cbfb84bce?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2342ad14824a1064823dcec81641a12136a3492abae522e473ec723cbfb84bce?s=96&d=mm&r=g","caption":"Daniel P. Clark"},"description":"Daniel P. Clark is a freelance developer, as well as a Ruby and Rust enthusiast. He writes about Ruby on his personal site.","url":"https:\/\/www.webcodegeeks.com\/author\/daniel-clark\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/24545","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/146"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=24545"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/24545\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/927"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=24545"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=24545"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=24545"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}