Snowpack V2 Announced

This project is very cool, def worth checking out.

Snowpack is a better build tool for modern web apps. Snowpack leverages ESM imports in your application to remove all unnecessary bundling work from your dev workflow. The end result is a build tool that starts up instantly and wastes no time rebuilding on every change. See changes reflected in the browser instantly.

10 Likes

Very cool indeed! I’ve been keen to try it out for a while.
I’ve used native esm for toy projects, but you lose a lot by not having any build step, and every time I install webpack, I immediately regret it and switch back to Meteor. It’s nice to have a middle ground solution

2 Likes

Meteor 2.0 build system? :laughing:

7 Likes

At least for dev. From what I understand this isn’t for production builds at all.

1 Like

That’s interesting…

I’ve moved from meteor to a monorepo with a client (create-react-app typically) and a vanilla node/graphql backend. Then I use accountsJS. I link up the github to netlify (client) and heroku (backend). It’s been pretty good to me so far.

I also have a CRA hack for hot reload

1 Like

Do you have and public code with this approach? I’d love to check it out.

Vite is also another example of ES module import based dev servers.

It seems that both Vite & Snowpack are dev servers that leverages modern browsers and ES modules HRM during development and use other build systems (Parcel and Rollup) in production.

I actually sometimes run webpack parallel to Meteor during dev, this is taking it a step further. So essentially during dev you’ll have a seperate view layer dev server running and then use Meteor’s build system in production (and hopefully the dev and production servers are consistent).

1 Like

This and much more is possible with https://hqjs.org since 2018. Check it out it is much more mature project that already solved a lot of issues that bot snowpack and vite should only explore.

3 Likes

Do these dev servers support aliases, such as?

 resolve: {
    alias: {
      'meteor/meteor': stubsDir('./meteor.js'),
      'meteor/accounts-base': stubsDir('./account_base.js'),
      'meteor/random': stubsDir('./random.js'),
      'meteor/dburles:factory': stubsDir('./dburles_factory.js'),
      'meteor/edgee:slingshot': stubsDir('./edgee_slingshot.js'),
.....

If so, can you please point me to the documentation/example? And did anyone manage to run one of those dev servers on an existing Meteor project during development? Something like

Ironically, it seems that webpack is starting to fall out of fashion already since those dev severs are promoting Parcel and Rollup or their own production bundlers and Deno has built it bundler as well, the joy of JS!

It makes sense to have a specialized high-speed bundler during development since many steps can be eliminated to optimize the refresh. If we manage to run those dev servers on a Meteor project during development, perhaps we won’t need a built-in HMR API after all and piggyback on one of those servers by running it in parallel with the Meteor process (for backend) and user the Meteor bundler for production, assuming the output during dev/production are identical, although I think we’ll have an issue with SSR, needs more thought.

@hqjs @zodern @filipenevola and others any thoughts on this? I see a potential opportunity here specifically for large React projects.

2 Likes

It looks like snowpack has an alias option and also vite so it should be relatively easy to run those in parallel with Meteor during development for large projects that needs HMR, for quick workarond you can stub all the meteor client calls and get the client running.

1 Like

Oh dang. I really want to give both a try now.

It does, you can add .babelrc with the plugin hqjs@babel-plugin-transform-name-imports

{
  "plugins": [[ "hqjs@babel-plugin-transform-name-imports", {
      "resolve": { "vue": "vue/dist/vue.esm.js" },
      "versions": { "react": "react@16.0.1" },
    }]]
}

Or any other aliases you want.

1 Like

There should be no problem to run hq in parallel with meteor. I will prepare examples eventually and add them to some repo so it woukd be obvious. The whole philosophy of hq is to work out of the box with no configuration, so I might add required substitution right to the core.

4 Likes

I’ve tried with snowpack and the alias doesn’t seem to work or maybe I’m doing something wrong…

I tried this config


 "installOptions": {
    "alias": {"meteor/mongo": "./test"}
  },

and it keeps resolving to /web_modules/meteor/mongo.js :man_shrugging:

Anyway, I think it’ll be great to have an example hqjs, perhaps you can use the Meteor react skeleton and try to get that running.


meteor create --react new-react-app
cd new-react-app
meteor

If it works well, I’m sure the Meteor community will adopt it, thanks!

1 Like

So apparently snowpack alias only works for package names (renaming one package to another installed package)…

I guess I’ve to use babel for the aliasing to a path with snowpack as well, perhaps someone who has more experience with this can give it a try.

Ok, so I got Snowpack to work with Meteor React app…
Screen Recording 2020-06-07 at 2.11.40 PM

Here is the config I’ve used:

  "snowpack": {
    "aliases": {
      "meteor/mongo": "meteor_stubs"
    },
    "extends": "@snowpack/app-scripts-react",
    "scripts": {
      "mount:imports": "mount imports --to /imports",
      "mount:meteor_stubs": "mount meteor_stubs --to /meteor_stubs",
      "build:js,jsx": "@snowpack/plugin-babel"
    },
    "installOptions": {
      "alias": {
        "meteor/meteor": "meteor_stubs",
        "meteor/accounts-base": "./meteor_stubs/account_base.js",
        "meteor/random": "./meteor_stubs/random.js",
        "meteor/dburles:factory": "./meteor_stubs/dburles_factory.js",
        "meteor/edgee:slingshot": "./meteor_stubs/edgee_slingshot.js",
        "meteor/reactive-var": "./meteor_stubs/reactive_var.js",
        "meteor/react-meteor-data": "./meteor_stubs/react_meteor_data.js",
        "meteor/mongo": "meteor_stubs",
        "meteor/http": "./meteor_stubs/meteor_http.js",
        "meteor/check": "./meteor_stubs/meteor_check.js",
        "meteor/tracker": "./meteor_stubs/tracker.js",
        "meteor/ultimatejs:tracker-react": "./meteor_stubs/tracker_react.js",
        "meteor/mdg:validated-method": "./meteor_stubs/validated_method.js",
        "meteor/universe:i18n": "./meteor_stubs/universe_i18n.js",
        "meteor/alanning:roles": "./meteor_stubs/alanning_roles.js",
        "meteor/chuangbo:cookie": "./meteor_stubs/chuangbo_cookie.js"
      }
    },
    "plugins": [
      "@snowpack/plugin-babel"
    ]
  },

I created a local NPM package to stub the meteor client, I’ll try to publish it when I’ve time.

But basically, this approach works minus the SSR, so I think we can forget about webpack for good, and keep Meteor build for production and backend during dev since it has unique features such as differential bundling and I think tree shaking is coming soon as well, thus making it superior to webpack in production and when coupled with things like snowpack in development. Anyway I was never a fan of webpack to start with, but it had the right approach with the assets dependency graph and it gets credit for that.

Let me know if you’ve any thoughts or comments.

4 Likes

Wow, so fast! That looks amazing. I can’t wait to see your work published so I can dive in more. I agree about forgetting about Webpack. I’ve always liked Rollup and Parcel more anyways. :wink:

Really interested to see your Meteor stubs pacakge.

2 Likes

I took a closer look at the Snowpack code and here is a high-level flow of what I think is happening:

  1. Snowpack traverse the files scanning for ESM imports and build dependency map
  2. When a file change within the map, it broadcast the changes the client recursively via web sockets
  3. The browser will then dynamically import the file with a timestamp attached to it to bust the cache (see here), the server will ship the requested file after applying any defined transformation

And that will get us the basic HMR and again this process is being standardized here, which should be fast enough already since we only need to transpile JSX and it’ll send the code without minification etc. leveraging the recent dynamic import browsers capabilities.

Going further, by maintaining the state:

React components will lose the state after HMR, to maintain the state, we need to add react fast refresh as per the following instructions, basically, the dynamically shipped modules need to register extra function, which you can see Snowpack doing it at here their react fast refresh plugin.

Thoughts On Meteor Integration:

We could run Snowpack in parallel today, which is fine, but we’ll have to stub the Meteor functions. We could also inject the meteor scripts and package to the snowpack public HTML file but this is kind of a hack.

I think the best way forward is to modify the Meteor dev server to support ESM bundling during development. This would require adding the following code to the server which is being standarized as we speak. And for react-fast refresh, we’ll probably need to intercept the JSX files compilation to add the extra registration calls required via some sort of plugin/package.

I unfortunately never had the chance to play with the meteor dev server and build system closely, but I really think this would be an interesting project, and folks like @zodern, @benjamn @filipenevola have the necessary know-how to get it working relatively fast.

I think this is a great opportunity to improve the development experience for many Meteor users and I’ll be disappointed if we fail to act on it, and I’m willing (and I think others as well) to fund this initiative if needed.

4 Likes

I think before we decide what to do, we should discuss:

  1. How fast rebuilds are now
  2. How fast we want them to be
  3. What trade offs we are willing to make to achieve that

Something else we should keep in mind is that the time from saving a change to a file to the new code running can be much larger than the rebuild time shown with METEOR_PROFILE. For example, Meteor checks files for changes every 5 seconds, which decreases to 500ms for the specific files that were modified since Meteor was started. Also, until the first full rebuild, there is an extra 0.5 - 2 second delay before starting client rebuilds due to checking if files used for the server were modified. Fixing these could have a larger impact than improving rebuild performance.

Regarding HMR: I have a basic implementation almost ready to share. Currently it only supports the modern client bundle to simplify testing, but I plan to extend it to all client architectures, meteor packages, and the server. If we used ecmascript modules for HMR, it would only support the app code in the modern client bundle, and maybe the server and meteor packages if how those are bundled was substantially changed.

2 Likes

I experimented more with Snowpack by attempting to a port a large CRA project to it. And I managed to get it running after removing some packages and imports yet it was still reloading the entire app by hitting this code path.

It seems that Snowpack works only with ESM modules which are around 7% of the package on NPM and if it encounters anything else in your dependency graph it will reload the browser.

I think Snowpack, Pika, and Deno are marching toward a new ecosystem without NPM or a centralized repository, all the code will be imported via a URL and cached either in the browser or the locally (in the case of Deno), basically the package source code will be like a web page that can be imported from anywhere using Javascript (without NPM, webpack, etc.), which is exciting and will bring a lot of simplicity and joy back to web development, however, this is a future that is still in the making.

Interestingly, Meteor is not using Webpack and at some point in the near future it could easily adopt ESM only modules thus simplifying the build process significantly, furthermore, Atmosphere can be used to host Meteor specific ESM packages. I honestly don’t think it is worth converting any project to Webpack given this trend, it’ll sure be legacy in a few years since the browsers are getting really good at importing packages, caching, refreshing and managing their dependencies. I personally would stick to Meteor, RollupJS, Snowpack/Pika and Deno, even Parcel future is questionable since there will be no need to bundle anything :man_shrugging:, that’s my read on the situation but let me know if you think otherwise.

I agree with zodern, his approach to HMR is more pragmatic and reliable for the NPM ecosystem that we’ve today. My personal conclusion is that Snowpack/Pike should only be used when you have greenfield projects and you are willing to stick to ESM modules and they are a really good fit for Deno land.

With that said, I invite others to experiment with Snowpack, Pika, Deno, and ESM modules to get a sense of where things are heading and would be happy to hear your opinions on it.

4 Likes