Discourse-webpack: A boilerplate for developing JS-heavy Discourse components

Edit by @david: Discourse’s theming system now has built-in support for multiple JS files. This webpack method is no longer required.

Hi! So while I was developing my handsfree-discourse component, I hit a few problems around file management. My main issue is that I needed a way to break up my code across multiple files. The other issue was that I needed to include 3rd party libraries without having to ask admins to enable CORS or trigger additional HTTP requests.

To solve these issues I made discourse-webpack, a boilerplate to quickly scaffold JS-heavy components! Features include:

  • Local dev server with live reloading
  • Includes a commit script to keep your source code and compiled code in separate branches!

The rest of this topic explains how to use it and why it works. I literally just finished testing this for a few other components I’m working on, so let me know if you run into any problems or have any specific requests!

Discourse Webpack

Quickly scaffold JavaScript-heavy components for your Discourse Community, complete with a commit script to keep your source code and build code in separate branches to help you keep shipping fast!


First, make sure you have NodeJS >= 8 and git installed locally on your machine. Then, type each of the lines below:

# Download this repository
git clone https://github.com/browsehandsfree/discourse-webpack

# Move into the directory
cd discourse-webpack

# Install dependencies
npm install

You’ll then need to edit the following in package.json, replacing all of our links with yours. Specifically:

  name: 'your-project',
  repository: {
    url: 'git+https://github.com/username/repo'
  author: '',
  bugs: {
    url: 'https://github.com/username/repo/issues'
  homepage: 'https://example.com'

Most importantly of all, make sure repository.url is correct and is prefaced with git+. When you run npm run discourse, it’ll commit and push to that repo.

Also, don’t forget to set your Discourse’s about.json, which is located in /src/discourse/about.json


After npm install, you’ll end up with the following directory structure:

|- node_modules/        # Dependencies
|- src/                 # The main source files
|--|- discourse/        # Discourse theme files
|--|--|- common/
|--|--|- desktop/
|--|--|- mobile/
|--|- main.css          # The main stylesheet
|--|- main.js           # The main Javascript entry
|--|- sandbox.html      # Sandbox for local development
|- .gitignore
|- discourse-push.js    # Special commit script
|- README.md
|- webpack.config.js    # Webpack config
|- yarn.lock

Command Line Scripts

Additionally, you have access to the following commands from the project root:

# Launch a dev server on localhost:8080
# - Supports livereload
# - Uses `/src/sandbox.html` to help you debug locally
npm run dev

# Compile your component into `/dist`
npm run build

# Compile your component into `/dist`
# - Then commits `/dist` into the `discourse` branch
npm run discourse

How it works

Once you’ve downloaded the repo and installed dependencies it’s time to start developing! Use npm run dev to start a livereload server on localhost:8080.

Visiting that URL will load the HTML file located in /src/sandbox.html. This file isn’t actually used within Discourse, and is just here to help you develop your scripts locally (outside the context of Discourse).

The main webpack entry point is /src/main.js. From there, you can import other scripts and webpack will bundle everything together and inject them into the following files:

  • /src/sandbox.html
  • /src/discourse/common/body_tag.html

main.js is compiled and injected into sandbox.html automatically, but is manually injected inline with body_tag.html because of the following code:

  <%= compilation.assets['main.js'].source() %>

If you wanted to inject your script into another template, like after_header.html, you would just copy that script tag into that template instead. This allows you to use keep the HTML and JavaScript for that template separated while developing…but concatenated when deployed!


When you compile with npm run build, what’s happening is:

  • First, /src/main.js and dependencies are bundled
  • Then, all files in /src/discourse/ are copied over to /dist/
  • At the same time, main.js is injected inline in any template file that contains:
  <%= compilation.assets['main.js'].source() %>


When you run npm run discourse, the /discourse-push.js script is called and does the following:

  • First it’ll compile, as if with npm run build
  • Then, it’ll initialize a new git repo inside of /dist
  • It then commits /dist into your projects discourse branch (it’ll create the branch if it doesn’t exist)

Using the discourse branch

Each of the following /relative/urls/ are relative to your forum’s base URL, eg, https://example.com/relative/urls/

Install the component

Install your component by visiting /admin/customize/themes and “Import from the web” from your projects repository, eg: https://github.com/my-awesome/discourse-component.

Then set the branch to discourse. It won’t work if you leave it at master, since Discourse will try to load the uncompiled files (if it works at all).


Debugging theme specific files on your own host

If you’re new to Discourse and would like to fork this project, the following reads might be helpful.


Discourse now has native support for “JS heavy” theme components

@labofoz I would be interested to know whether you think this is enough to avoid the need for discourse-webpack?