Webpack compiler inside Meteor (ES6 modules, hot reload and code splitting!)

Awesome stuff! Thanks a lot! I agree with both jedwards and dinos about convention over configuration and flexibility. As in sane defaults, but it needs to overridable.

@benoitt, wow! It looks incredible. Iā€™m currently busy, but will definitely dig into new kickstart this evening.

If you want hot-module replacement, youā€™ll have to pipe it through babel though. Same with any language. Hereā€™s what I have for coffeescript

      {
        test: /\.coffee$/,
        loader: 'babel!coffee',
      },
2 Likes

import is ES6 syntax that compiled to require.

1 Like

@benoitt I think a solid strategy would be to have a relatively opinionated and reasonably configurable set of defaults like you have right now, but also provide a hook like webpack.client.override.js which gets the entire webpack config object and can manipulate it or pass an entirely fresh config back if they want. This way, its infinitely configurable in terms of webpack.

It should be possible.
There is another skeleton page for meteor with webpack available https://github.com/jedwards1211/meteor-webpack-react

I successfully added typescript support though ts-loader: https://github.com/jbbr/meteor-webpack-react/tree/ts-loader.

Itā€™s likely that this is also possible with benoittā€™s kickstart

I have an issue on Mac OS X:

  1. git clone https://github.com/thereactivestack/kickstart-simple kickstart
  2. cd kickstart
  3. Add "radium": "0.14.1" to packages.json
  4. meteor
  5. Then I have infinite ā€œbuilding npm-container packageā€ message and CPU 95% load

How do I know whether meteor or webpack (or both) is handling a file - I can see that both *.js and *.jsx files can be used with import/export without an ā€œ.import.ā€ extension prefix. But css files need this prefix to prevent meteors css handling.

Is there a way to be sure whats happening?
What if I wanna use less: Is it okay to add a less loader to the webpack config and import less files without prefix and use a meteor plugin which has the meteor ā€œlessā€ dependency?

I also agree we should keep a default configuration and make sure anyone can override it by his own way of doing things.

It is also the purpose of the kickstart projects. You just clone a good setup and start from there instead of from scratch. Unfortunally, we will always need a little bit of boiletplate code for Webpack.

This is coming. But first I want to nail the unit / integration tests :smile:

You can use import and require anywhere. The reason there is some require on the server is because I want to include those files, but there is no variable to import there. Just to include Meteor subscriptions and methods.

You can look at the kickstart-hugeapp example (especially client/AdminApp/index.js). There is probably many ways to do the same thing with different loaders.

This is how webpack.conf.js files are working. Iā€™m trying to override as few things as possible unless it is absolutely required to make it work inside Meteor.

I will look into that. Can you send a bug issue on https://github.com/thereactivestack/meteor-webpack/issues? Thanks for noticing.

The .js and .jsx files are all handled by Webpack. However, .css files are handled by Meteor and there is nothing I can do about it. So Iā€™ve used .import.css.

If you would like to use less, you can add the less loader (just like the sass loader) and use .less files. Just make sure to not add the less package on Meteor :smile:

3 Likes

@benoitt this is awesome!!! Ah I wanted to try it out, but couldnā€™t really get the dev client to communicate with the webpack dev server because of this issue.

This will be fixed very quickly. Youā€™re not the first having this problem :smile:

1 Like

@benoitt:

I prefer an app structured like this:

src/
  module1/
    server/
      entry.js
      ....
    client/
      entry.js
      .....
    fileInBoth.js

  module2/
    server/
    client/

server/
  entry.js (requires all src/<module>/server/entry.js )

client/
  entry.js (requires all src/<module>/client/entry.js)

Itā€™s a bit like a package based app structure but without meteor packages :slight_smile: adventage over meteor packages: No need to write package.js files and still have clean dependencies through import/export.

I can do this with your stack but obviously the src directory is also watched by the meteor server watcher. This results in server reloads when I change a file, which is only referenced in a client entry file.

BTW: The meteor server watcher causes server reloads even when changing dead code in the server directory - which doesnā€™t break anything but is slow and feels bad.

Is it possible to change this behavior somehow? I presume this isnā€™t possible because the meteor watcher canā€™t be configuredā€¦

EDIT: As I want SSR anyway, I might just live with server reloads on client changesā€¦ I was just wondering if this is possible somehow.

1 Like

I think your structure is more clear and modular. Iā€™ll try to fix this soon.

Itā€™s really hard to know what is deadcode and what isnā€™t. I was expecting Meteor to figure this out for me :(. Iā€™m sure we can improve this.

If you change a file inside a client folder (even inside src), Meteor should figure out you are not changing the server. Iā€™ll test why this is happening.

You donā€™t have to live in this sad world. Watch server/entry.js, SSR is only enabled in production. This means you can develop without the anoying code reload all the time. The hot-reload should work.

BTW your browser should never reload. Hot-reload should be injecting the new code. Unless you are in production, it is blocked by Webpack.

Ah nice, thanks. I just figured out how to prevent server reload:

Just use the structure client/module1/server/entry.js and require the server entry from server/entry.js. It feels a bit awkward to put server code into the client directory butā€¦ it works. Thatā€™s also what you in your example do to get client routes on the server for SSR.

1 Like

I love you. I really, really love you for this.

6 Likes

Iā€™ll argue with you this is not that awkward. This is client code you are running on the server for SSR :smile:

I love how everyone is willingly trying a new way to use Meteor. Thank you! :smile:

1 Like

Yeah thats true for components and routes which are only required from server for SSR.

But my preferred, modularized package structure introduces server-only code at the same level as client-only code. Having server-only code in the client/ directory feels awkward.

But I think this structure has its advantages. Itā€™s almost the same as the package based structure the Telescope Meteor app is using (Only without the package.js files but plain js entries instead)

Can you share me on github your structure? I think most people are looking for something like this.

2 Likes

Sure!

Iā€™m still playing with your kickstart. Iā€™ve been using the one by @jedwards until now - and Iā€™m not yet sure if I want to switch to yours as I like having full control over npm, webpack config, watchersā€¦ But having multiple choices is not a bad thing.
Anyway I really like what you have build and will do a sample with my preferred structure on github.

4 Likes

Anyone got this to work on Windows?

Iā€™m getting:

C:\MyFiles\Meteor\kickstart-simple>meteor
[[[[[ C:\MyFiles\Meteor\kickstart-simple ]]]]]

=> Started proxy.
=> Started MongoDB.
npm-container: updating npm dependencies -- react-mixin, babel-loader,
null-loader, url-loader, file-loader, style-loader, css-loader,
sass-loader, style-collector-loader, webpack-hot-middleware,
babel-plugin-react-transform, react-transform-hmr,
react-transform-catch-errors, redbox-react...
webpack built 657bbd699dc4db0dc1e4 in 5804ms /
Hash: 657bbd699dc4db0dc1e4
Version: webpack 1.12.2
Time: 5804ms
        Asset     Size  Chunks       Chunk Names
       web.js  39.4 kB    0, 1       main
common.web.js  23.1 kB       1       common
chunk    {0} web.js (main) 12.3 kB {1} [rendered]
    [0] multi main 40 bytes {0} [built] [1 error]
    [1] ./packages/npm-container/.npm/package/~/webpack-hot-middleware/client.js
?path=http://localhost:3500/__webpack_hmr 3.27 kB {0} [built]
    [2] (webpack)/buildin/module.js 251 bytes {0} [built]
    [3] ./packages/npm-container/.npm/package/~/webpack-hot-middleware/~/queryst
ring/index.js 127 bytes {0} [built]
    [4] ./packages/npm-container/.npm/package/~/webpack-hot-middleware/~/queryst
ring/decode.js 2.4 kB {0} [built]
    [5] ./packages/npm-container/.npm/package/~/webpack-hot-middleware/~/queryst
ring/encode.js 2.09 kB {0} [built]
    [6] ./packages/npm-container/.npm/package/~/webpack-hot-middleware/~/strip-a
nsi/index.js 161 bytes {0} [built]
    [7] ./packages/npm-container/.npm/package/~/webpack-hot-middleware/~/strip-a
nsi/~/ansi-regex/index.js 145 bytes {0} [built]
    [8] ./packages/npm-container/.npm/package/~/webpack-hot-middleware/client-ov
erlay.js 883 bytes {0} [built]
    [9] ./packages/npm-container/.npm/package/~/webpack-hot-middleware/process-u
pdate.js 2.93 kB {0} [built]
chunk    {1} common.web.js (common) 0 bytes [rendered]

ERROR in C:/MyFiles/Meteor/kickstart-simple/client/entry.js
Module build failed: ReferenceError: Unknown plugin "react-transform"
  at PluginManager.subnormaliseString (C:\MyFiles\Meteor\kickstart-simple\packag
es\npm-container\.npm\package\node_modules\babel-loader\node_modules\babel-core\
lib\transformation\file\plugin-manager.js:147:13)
  at PluginManager.add (C:\MyFiles\Meteor\kickstart-simple\packages\npm-containe
r\.npm\package\node_modules\babel-loader\node_modules\babel-core\lib\transformat
ion\file\plugin-manager.js:190:40)
  at File.buildTransformers (C:\MyFiles\Meteor\kickstart-simple\packages\npm-con
tainer\.npm\package\node_modules\babel-loader\node_modules\babel-core\lib\transf
ormation\file\index.js:237:21)
  at new File (C:\MyFiles\Meteor\kickstart-simple\packages\npm-container\.npm\pa
ckage\node_modules\babel-loader\node_modules\babel-core\lib\transformation\file\
index.js:139:10)
  at Pipeline.transform (C:\MyFiles\Meteor\kickstart-simple\packages\npm-contain
er\.npm\package\node_modules\babel-loader\node_modules\babel-core\lib\transforma
tion\pipeline.js:164:16)
  at transpile (C:\MyFiles\Meteor\kickstart-simple\packages\npm-container\.npm\p
ackage\node_modules\babel-loader\index.js:12:22)
  at Object.module.exports (C:\MyFiles\Meteor\kickstart-simple\packages\npm-cont
ainer\.npm\package\node_modules\babel-loader\index.js:69:12)
 @ multi main
=> Started your app.

=> App running at: http://localhost:3000/
   Type Control-C twice to stop.