Meteor + Webpack: ES6 modules, hot-code-patching, fixes load order & more

I’ve been using Webpack with Meteor recently and it’s been working out rather well. There’s a project here: Meteor-Webpack-React from @jedwards that provides a nice boilerplate to setup the configurations for you. It basically builds a client & server bundle and drops them into the meteor folder.

  • No loading order problems (lib folder etc…)
  • ES6 Modules
  • No wrapping libraries! just - npm install moment --save-dev !
  • Easy NPM usagage for client and server (great for React components)
  • Works with Blaze example branch
  • Hot Patch Functions/Modules that change (not an entire page refresh)
  • Fast patching for large projects
  • Require CSS/Sass/Less files
  • Total control of build process
  • Split into many ‘on demand’ chunks instead of 1 large js file
  • All meteor packages/files still work… they’re just global

If you’re using Redux then the hot-loading will enable you to change code without losing all of your local state :smiley:

I made a quick video tutorial on how to run it and to explain how it works (mostly the latter, it’s a 1min install). It’s more less a rough draft as I didn’t have time to edit it: Using Webpack with Meteor - YouTube


and an example of hot-patching (as opposed to a hot full-reload)

34 Likes

@ccorcos You may like this for the latest coffeescript loader: https://github.com/webpack/coffee-loader

1 Like

Awesome, I’ma use this, thank you good sir

1 Like

I love coffeescript! :smile: Nice work with this btw. How far are you from getting this work with React Native?

Also, how does this work with the packaging system? Can I write packages as ES6 modules?

1 Like

So… technically we could drop in the app code folder into React Native without any issues. The problem is dropping in the Meteor client bundle.

Meteor assuming the browser if available on the client. Since RN is not using the browser some issues like ready events cause it to blow up. Once Meteor can be polyfilled it should be a drop-in process for webpack (drop in meteor client core and the app code).

In the mean time for RN i’m using the Node DDP adapter for any realtime needs and a REST API for the rest (mostly because it’s legacy and was there already).

Cordova however should work well. The dev script just needs an argument to run on ios or android to watch and the build should work without any changes.

Also, how does this work with the packaging system?

So the load order from what I understand is:

  • meteor client core
  • meteor packages
  • your app code (client.main.js & server.main.js)

So with this you can install packages like normal and just assume they’re available in the global scope.

You can require a global package or thing if you create a webpack alias to use the global version. Then you would require import {map, reduce} from 'underscore'; and webpack would resolve to the global _ that Meteor exports.

Can I write packages as ES6 modules?

So you can’t write true ES6 modules with the Meteor packages… however you can create your own module and upload it to NPM (public or private) and then use that. You’ll lose the ability to require other packages so you’d have to assume they were there. I’ve done this with a private package for team use and it works well.

There are def. some cons with skipping the Meteor build step but at least I don’t have the feeling of being held back and being behind the times (was getting ready to drop Meteor because of the globals in large projects were an issue).

4 Likes

Wow, cool, thanks for promoting this Adam! I still haven’t messed with Redux, that sounds awesome.

1 Like

Just watched your whole video - thanks so much for taking the time! Looks awesome.

Do you think this type of build would work with meteor’s galaxy when it launches? I’m wondering how this affects deploying to production for meteor apps.

Cheers!

1 Like

Thanks! Hope it wasn’t too drawn out! In time i’d like to re-do it with more info and less time.

I’m assuming it will. You can deploy with this to meteor.com as well:

./prod let bundle, then kill (this just creates the bunde in meteor_core)
./met deploy mysite.meteor.com

or without the ./met helper script you can cd meteor_core && meteor deploy mysite.meteor.com

I’m assuming Galaxy will be similar as well.

Make that && instead of & lest somebody copy-pastes that and gets funky results!

And thanks for the video, that looks great! So basically this is like a project scaffold that you can use as a starting point for a project, using the webpack-meteor stuff?

1 Like

Ah great catch!

Yea it basically takes care of all the un-interesting parts of webpack and wiring that up to Meteor. There isn’t much intentionally so that you don’t have to delete as much. It basically has a Hello World along with an example each of Meteor methods, user accounts, collections, etc…

Also not noted in the readme or screencast… If something doesn’t work in the webpack environment you can always put it into meteor_core the same as you do today. I’m doing this for tests and Sass for a legacy project and it works great since things are global by default for the legacy stuff.

1 Like

Hey, sorry for the delay, just started a full-time job! Not using Meteor here just yet… :wink:

  1. One of the big things about using RN this way is that you dont get the whole hot code deploys. Any thoughts on that front?

  2. I was talking to Sashko at the devshop (I just moved to SF) and we were talking about Electron, RN, Neo4j, and other platforms and how awesome it would be to support them in the build system, and he said if I came at him with a very specific list of functions and requirements, he’d look into it. Since you’re so familiar with RN, want to compile a list of build system hooks he could implement to get a smooth RN integration?

  3. What sort of polyfills are we talking here? It doesn’t seem like it would be too hard to either create those polyfills, or perhaps refactoring the meteor api to abstract these functions based on the platforms…

  1. Yep, there’s some work being done to be able to hot code reload the JS in the React Native app like Cordova does. However it’s still experimental. This will be ideal (for me even with the 4-5 day delay it’s still more productive).

  2. I wish I had the time to really dig into this but basically the react-native packager can be run by node (with npm start) to build the app in different states (dev/prod). You can also use Webpack but is not officially supported.

  3. Harrison ( @hharnisc ) started to work on it but it doesn’t look active anymore. I wanted to help but took on a new client and am swamped. Also issues to MDG and RN were pretty much dismissed, so it looks like a 3rd party polyfill is the only way for now.

The ones that are documented to fail are:

  • document.readyState
  • document.addEventListener -“DOMContentLoaded”
  • document.attachEvent
    • “onreadystatechange”
  • window.attachEvent <- might need some of the window functionality as well
    • “load”
  • window.addEventListener
    • “load”

“Because these types of environments don’t have a document they can start running code right away.”

https://github.com/meteor/meteor/issues/4501
https://github.com/facebook/react-native/issues/1495

It would be really nice to get the client bundle working in React Native :smiley:

Just pushed a PR to cut the reload speed down a lot.
Hot loads with cheap source maps take around 0.6 seconds (hard to time with a stopwatch).
With good source maps hot loads are around 1.3 seconds.

An app with around 100-ish files takes 1.6 seconds with good maps and 1.2 with cheap maps (they don’t look quite 1:1 with your source). I migrated the app in under 4 hours (not stopping time for coffee or cleaning up linting warning, etc…). The best part is not having to go back and re-fill out forms when you change a file… reallly nice

Looking forward to test with a much larger app (~500 files) which is currently taking 15 seconds to reload (with 1.1 and browserify).

Does webpack have any benefits in terms of incremental loading, or is a multi-app structure still the way to go?

1 Like

It’s super flexible in this regard. Are you referring to having multiple apps for something like Cordova and a desktop? Or something like an admin dashboard and a user facing site? Or to just give the user the JS they need and then async. load more as they go about the site?

Either way you can do this but they would have different setups. For both of the 2nd & 3rd examples you can use webpack ‘chunks’ to split the code. Instagram uses this on their desktop app.

I haven’t had a chance to do this yet but will be soon. The last step of a large multi step form needs to download a larger lib so this will work perfect for me. I’ll make sure I record a video tutorial after I do :smile:

Here’s the docs on how to do it… they’re comprehensive but a bit tough to skim:
http://webpack.github.io/docs/code-splitting.html

1 Like

oh man, looks like i’ve got some reading! keep us posted if you get around to the video, it’d be interesting to see any meteor-specific gotchas.
My use case is more inline with the 2nd & 3rd examples. I just hate sending out 5MB of code when over 90% of views aren’t making it past the landing page. Ideally, I’d patch in the code async as different modules are visited, but I’m OK with breaking it off into larger chunks for now.

Yep you can do that. I think there are hooks to basically use in the router to say something like… if this has not been loaded yet, show a spinner and then get the chunk. So you can have as many ‘entry’ points as needed. Hey maybe we can even get a FlowRouter integration :wink:

Here’s a great video explaining it: https://www.youtube.com/watch?v=VkTCL6Nqm6Y

2 Likes

wow, and that video is already over a year old?! i got some catching up to do… i think this finally got me sold on going the webpack route (and it finally makes sense why the react material-ui inlines all css).

1 Like

Awesome stuff! Thanks for the hard work @SkinnyGeek1010 and @jedwards! I’m definitely going to try this out.

2 Likes

The hot-code reloading is awesome! And the ES6 modularities too!

Tho, anyone with success with FlowRouter + React?
Have been trying several hours and still didn’t get it work.

Will play around with this a little more during long weekend. :smiley: