Using Metro as a web bundler

If you have ever worked with react-native you should be quite comfortable or at least know what metro is.

If not, taking the words from the official GitHub page:

Image for post
Image for post

Metro is playing in the same field like webpack, parcel and rollup, but the main focus is react-native or at least that was my understanding from all the documentation and experience.

While browsing through the web on Twitter, Medium and others a post on dev.to caught my attention.

First thing that came to my mind: “W

To be honest, I knew that metro could do some web stuff because of react-native-web, but never really cared about it. The main purpose of metro is react-native right?

So I’ve created a small repository on GitHub and tried the code mentioned on dev.to. The setup is quite similar to parcel.

First of all you install metro (I will use yarn in this example):

yarn add -D metro metro-core

Create a package.json file in your directory using:

yarn init -y

Create an index.html in a public directory

<html>
<body>
<script src="index.bundle?platform=web&dev=true&minify=false"></script>
</body>
</html>

and an index.js in your project root

console.log('hello world')

Compared to the Getting Started of parcel, there is already one difference.
This line:

`<script src="index.bundle?platform=web&dev=true&minify=false">

What’s up with the index.bundle and there query parameters?

In metro you can request different types of the bundle

  • .bundle The whole tree of js modules
  • .delta Only available after one successful bundling to receive the differences

So we are telling metro to bundle our application using index as an entry point.

Next up are the query parameters. Most of them are very self explanatory

  • platform Which platform to bundle for. Can be android , ios or web
  • minify Specifies if the bundle should be minified
  • dev Create a development version of the build process.env.NODE_ENV = 'development'

There are also some other options, but not worth mentioning here.

So coming back to our setup, the next step is to create the metro config.
In your project root create a file called metro.config.js

module.exports = {  
server: {
port: 3000,
},
}

This small config file determines the port metro is running on. There are more options to configure, but the documentation lacks examples or use-cases.

At this point you could already start metro, but you wouldn’t see any content of your index.html, because per default metro can’t serve html.

So we need to combine metro with express !

Add express to your project

yarn add -D express

Create a server.js

const Metro = require('metro')
const express = require('express')
const app = express()
const server = require('http').Server(app) Metro.loadConfig().then(async config => {
const connectMiddleware = await
Metro.createConnectMiddleware(config)
const { server: { port } } = config
app.use('/', express.static('public'))
app.use(connectMiddleware.middleware)
server.listen(port)
console.log(`Your 🚆 is holding on http://localhost:${port}`)
connectMiddleware.attachHmrServer(server)
})

And that’s it! You are good to go!

So last step, create a start script in your package.json

"start": "node server.js",

If you run yarn start in your terminal now, you should see that metro is running.
Open http://localhost:3000 in your browser, and metro starts bundling your JavaScript code.

Summary

Using metro as a web bundler feels different and clunky in many aspects.

I would not recommend anyone using metro on the web right now, although you know what you are doing.

My goal is to understand the techniques and internals of metro better and show off the advantages, disadvantages, and other things compared to the more “common” bundlers.

I still need to figure out ways to use css, scss, html, or how to use HMR at all, but my journey with metro will go on.

The documentation of metro is abysmal so source-code digging is your best friend to understand some of the configurations you need to do.

I’ve created and maintain a boilerplate for an easier start

Written by

Hey I’m Tobi! 👋 A software developer living in 🇩🇪 Augsburg. Nowadays I’m working with JavaScript, react, react-native, node.js, GraphQL, …

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store