-
Notifications
You must be signed in to change notification settings - Fork 563
Publish ES5 modules to NPM #137
Comments
Thanks for the suggestion. I actually spent a lot of time thinking about this issue before publishing, and ultimately I chose to publish the source modules rather than the built modules. Here was my initial thinking (I'm happy to reconsider if it becomes a burden for a lot of people):
I'd consider publishing both the source and built files, but I'd want to make sure there was a real demand for it before doing the work to support it. Thoughts? |
Thanks for your thoughts, it's great to see some solid thinking behind this. However, since it does seem this does deviate from the norm for NPM published packages it would be nice if the loading via npm section mentioned you will need to be sure you transpile down to ES5 since it will ultimately be used in the browser. |
Thanks @scurker !, I just spent 5-6 hours troubleshooting babel, webpack, grunt, the upgrade to webpack 2, downgrading to webpack 1, bouncing around commits, changes. It was because babel was not processing node_modules, as you said. @philipwalton I think this is misleading:
The end fix is very simple, but understanding the problem these days is a quagmire of interconnected tools, not so clear error messages, and mountains of outdated config recommendations... Edit: also worth noting that I did try removing the exclude on node_modules completely early on, but ran into another module that had some babel settings and a not so clear error message. |
@matthewlein FYI you also need I wish there was a better community standard around this, because I think Philip has perfectly valid reasons to not transpile code but there's not an official way to make those intentions clear. |
Huh, haven't hit any errors yet without it. I will keep that in mind if I see anything. |
Derp. There it is, |
This is the reason I'm still sticking with v1. Compiling a module is non-standard practice so a lot of the tools I use are not really good at this. For me, it was easier to just not update autotrack. I also think publishing ES2015 is great, but the ecosystem is not ready yet, mainly because there is still no agreement on how to do this. May I propose to publish an ES5 version on the v1 branch? This would give users an opton. |
I also just spent a couple hours on this. I 👍 the recommendations about improving the docs as well, and had the exact intuition about "ES2015 compatibility". Perhaps we could just link to this issue? To be honest, adapting our webpack exclusions isn't tricky as long as I know that's what needs to be adapted. |
Hi, just to add my two cents (sorry I'm late): Create-React-App's build process doesn't transform the libs in From Dan (React team & author of CRA):
|
My two cents: After a couple of hours, was able to figure out the root issue and fix my build. Finding this thread helped, but it took a while to understand why this was the issue and further complicated since I am using Typescript. Here is the error I was getting:
IMO, this is not the default format that npm modules are published. This is a hard / bigger question but until community figures the way to move forward from ES5 it would be nice if this repo followed the current defacto standard. I opt'ed to add babel to just to get this module to work, here are the steps if anyone else is interested.
webpack v2 module: {
rules: [
{
test: /\.tsx?$/,
use: { loader: 'ts-loader' },
},
{
test: /\.js?$/,
use: { loader: 'babel-loader' },
exclude: /node_modules\/(?!(autotrack|dom-utils))/,
},
]
}, |
I've spent a bit of time looking into what it would take to publish the plugin source files as ES5 so they could be more easily consumed via webpack with most users' The problem is, since autotrack depends on my dom-utils package, transpiling all the autotrack source files via babel into a That means my options are to either (1) publish only babel-transpiled ES5 versions of all the plugins (which I don't want to do since closure compiler-transpiled versions are ~40% smaller), or (2) I can continue to publish ES2015 versions and ensure this issue is as clear as possible in the documentation. At this point I'd much rather do option (2), since it's ultimately the most flexible and future-proof, and it still works with all existing tools (just not with all existing configurations of those tools). On other hand, if I do option (1), I'd be preventing anyone who wants to use a transpiler other than babel from doing so, and I'd be forcing all consumers of autotrack to download far more code than they need. I also want to point out that I already am providing an ES5 version of autotrack that users can include in their builds, it's just not referenced in I people want, I'd be willing to update the |
I also want to reiterate that, even if you're using webpack to build your app, you don't have to bundle autotrack with the rest of your code. It's actually much better to create a custom build and load it separately via And if you really want to use webpack to bundle autotrack, then you should definitely be using code splitting and you can still transpile autotrack via |
Another way to solve this problem without needing a special case in the webpack config:
|
@michaelBenin doing that will include all plugins, which kinda defeats the purpose of us using a bundler since that file is already bundled/minified/optimized. You also don't want to include it in your site's main JavaScript file as it'll slow down the load unnecessarily (I say unnecessarily because analytics code never needs to be loaded up front). Just to reiterate to everyone on this thread, I get the appeal of loading autotrack via webpack, but unless you're using webpack's code splitting features, you're actually making your site slower by including autotrack in your main bundle. It's much better to load the full version of autotrack via |
Add me to the list of folks who have lost more than one hour to this decision. I appreciate that for some use cases, being able to save, what is it, about 10kb?, might seem important. But for lots of users, the engineering hours spent trying to optimize that 10kb of savings may not be worth it. Our bundle is about 700kb currently. I'm not going to defend that, but it's also perfectly acceptable for our use case. My priority right now is getting a product out to market that is fast (enough) and gets to our users quickly so we can collect usage data, gather feedback, start generating revenue, etc. For use cases like ours, we are more than happy to take a 10kb hit on an important library if it lets us get moving fast. I was blown away by how powerful your library is, kudos to you. And I tossed the changes into a PR, moved on to the next feature in a few hours (bigly savings there again, congratulations - terrific job). But then to come back later and see that our builds were failing because of this sort of non-standard practice was definitely a bummer. Could you ship prebuilt versions for babel and closure? Again, I have read all of your concerns, and those are all great, but for many use cases, there really isn't anything wrong with developers wanting to keep their dev process streamlined and efficient - that's also a feature. "Compliance is a feature" how's that for a quote? |
My understanding with regards to Webpack v2 and Rollup is that |
@scurker the problem with using the main/module property of I provide an ES5 version of the library with the full plugin list, and I expose the source code for users who want to include just specific plugins. As far as I know, @bennidhamma if you don't care about the extra size to your bundle and you want to bundle with webpack instead of using Though, as I've said a few times in this thread, I strongly recommend against doing this. It's far better to just use
I already ship an ES5 version. Arguably, the version that gets loaded when you do |
Ahh, my bad. I misunderstood the documentation. Thanks @philipwalton :) |
I want to jump in here and say this bit me as well—over 10 lost hours over the last two days, and wasted the time of the Heroku support team, the Heroku ruby buildpack dev team, and the Rails webpacker team. At the end of it all, I still have no idea how to actually utilize analyticsjs-boilerplate with autotrack in production (it's working perfectly in development). Unfortunately, it's already cost me thousands of dollars, so I'll be tearing it out and going back to the default tracking snippet with some smart tweaks and additional calls, loaded however the hell Google wants to load it, because what's important is that I can ship the feature and move on with my work. Please reconsider whatever has resulted in this experience. |
@coreyward (and whoever else) my understanding of what @philipwalton is saying is that he doesn't want to sacrifice performance for ease of use and possible incorrectness (I don't claim to understand all the details mentioned in this issue). I think that is fine. Perhaps what we need is more understandable documentation on how to do things the Right Way. For me, this commit fixed autotrack. Basically, with this command I generated autotrack.custom.js. I put that in my repository's assets, and then load it asynchronously. Hope that helps. |
@zackhsi Unfortunately, the solution you're using doesn't work for me since I'm using another library by @philipwalton that, somewhat confusingly, doesn't follow his advice, and imports from autotrack. It's also not available compiled to ES5. If I were using autotrack by itself, I could copy-paste pre-built JS files into my app, modify them as needed, and load it all asynchronously with script tags. That's what I've done in the past, without bothering with yarn/npm, webpack, babel, or a dozen other dependencies. |
@coreyward sorry you lost time to this. If you can point to anything thats missing from or misleading in the documentation, I'm happy to fix it or clarify. The truth is webpack is complex, and lots of people run into issues using it. That's why I ship both (1) a pre-built, pre-minified, ES5 version of the library in the repo that people can load as-is via All of the issues people have raised in this thread pertain specifically to how to load autotrack with webpack and babel-loader. You can completely avoid that complexity by not loading autotrack via webpack and babel-loader. As for the |
@zackhsi I think this comment is very much on point:
Feel free to reach out to me any time to offer feedback on this library or any best practices we (Google) promote. If anything is confusing or needs clarification, we want to know. |
@philipwalton thanks a ton for this context; it certainly spared me many of the pitfalls that others have encountered. FWIW, it still took me a few hours of failing to get Can I recommend some sort of very noticeable disclaimer immediately inside of the The following approach is not recommended unless you have a really good reason to use it (e.g. code splitting). The recommended approach is via |
I disagree strongly with this. If you live in the react/babel/webpack world, then perhaps it seems like that, but the web development ecosystem is quite a bit larger than that ecosystem, and I'd rather offer flexibility that benefits everyone (and most importantly, minimizes the potential hurt to end users).
You only have to add And to be clear, this isn't an autotrack issue, it's a Webpack and And if you don't want to worry about that, then you can just remove the line Also, this is an area where
I'm actually embracing build systems the most by publishing ES2015 source files, as they're far more compatible with a wide range of build systems. By publishing the source files as transpiled ES5 I'm not embracing build systems at all, I'm forcing my build onto others.
This isn't quite true. |
Since confusion keeps coming up around this, I think it makes the most sense to update the Here's what this will do: What will change:For users who import the entire autotrack export, e.g.: import 'autotrack'; They will get the ES5 version in the main repo, so they won't see any errors when loading via webpack and transpiling via This is effectively the same as what you can already do by importing What will not change:Users who only import select plugins, e.g.: import 'autotrack/lib/plugins/event-tracker';
import 'autotrack/lib/plugins/outbound-link-tracker';
import 'autotrack/lib/plugins/url-change-tracker'; They will still need to transiple the source from ES2015. As I've explained above, I cannot publish all individual plugins as ES5 because they have dependencies on modules that are published as ES2015, and Does this seem reasonable to everyone? |
I'm late to the party but that seems reasonable. I appreciate the availability of ES6 source files and have no problem working with this package as I whitelist paths for transpiling ( |
It's also worth pointing out that making This is probably not a major concern for most autotrack users, but it's another argument on the side of it making the most sense to publish source files rather than bundled and compiled files. Publishing the source files will always give tools the most flexibility and power to make optimizations. |
That's probable a good compromise that helps reduce some confusion. Is there any chance the documentation can get updated as well for importing individual plugins? |
I am using https://github.com/vuejs-templates/webpack as boilerplate and I found the proposed exclude solutions didn't seem to help. Finally decided to forget about it and just do |
@justin-hackin here's a working webpack example from my analyticsjs-boilerplate project. Perhaps compare it to that and see what's different. |
In autotrack v2, the published package is in the form of ES6 modules, and this is causing an issue with Webpack minification. See googleanalytics/autotrack#137 I tried the proposed solution of excluding it from Babel, but it didn't work on the first try, and I don't want to spend any more time on it. We only use one autotrack plugin anyway.
In autotrack v2, the published package is in the form of ES6 modules, and this is causing an issue with Webpack minification. See googleanalytics/autotrack#137 I tried the proposed solution of excluding it from Babel, but it didn't work on the first try, and I don't want to spend any more time on it. We only use one autotrack plugin anyway.
Like @justin-hackin I also was trying to apply I ended up copying the entire |
I got another solution which is somewhat in between loading external scripts and a full webpack compile: Step 1: copy analytics.js and autotrack.js to your webpack static folder.
you can change the names of the files as you wish if you don't like the defaults Step 3: back in your own javascript code, initiate the global ga variable:
works for me. |
FYI, we're starting the work to compile deps with Let us know if you have feedback about how this should work. |
I came across this same problem today - deployed our website with webpack simple Seems Also @philipwalton I notice you said:
But that's not true, according to the package.json you need these as well (they are not in dev devepencnies which I find odd):
Surely those are dependencies when your compiling a custom version using your own I'm not sure what the solution is here but I think at minimum |
I think @philipwalton your main concern is with this, right?
Couldn't that import as uncompiled and then is it possible to have the compiled version as well, but just under a different directory?
I'm a bit of a babel noob so not sure if that is possible, but wouldn't that allow for all possibilities? That way people can consume and bundle whatever version they like. For me the worst case scenario is to use a custom |
I think your lack of cross-browser test coverage is to blame :) Joking aside, I haven't made the changes I mentioned above in autotrack because I'm starting to see more and more websites deploying ES2015+ versions of their code (I actually have an article explaining how to do this with an ES5 fallback). And given that
They aren't in dev dependencies because they're needed for the custom compiler binary.
It's possible, but it'd only work if it and all of it's dependencies used the exact same |
Interesting article, it definitely makes a lot of sense as the majority of browsers support ES2015 natively. I think just improvements the docs would help
Kind of annoying though that you need to install those dependencies even if you won't be using your custom build CLI tool to build a custom version, or want to bundle with webpack.
Well the webpack I totally understand you wanting to push towards a better way of bundling, it does add complexity to using the library though. For example, you require What about other package developers who use special plugins / options as well? I can imagine your bundler config getting pretty big supporting different ways of transpiling. Typescript? I guess that's a separate issue though. |
babel-loader shouldn't be, and we're working with them and others to remove this line from their code samples and tutorials.
The reason they advocate it is because it's faster. But as it's becoming more and more common for authors to publish ES2015+ code, it's not good for these sites to be including that line in their basic usage guidelines. It's also not true that all packages can produce a dist/transpiled version. If you have any third-party dependencies then bundling them into a dist version will lead to code duplication. Bundlers already have a mechanism for dependency de-duping, but if module authors are bundling their dependencies that work is wasted. Again, note that all of this works perfectly, out of the box, with the default configuration of webpack and babel. It's only problematic if you exclude
That's not true, |
I haven't had time to play around with it myself, but with the release of webpack 4, build tools are moving towards faster builds where ignoring |
Create React App can handle standard modern JS in dependencies starting with 2.0. |
See googleanalytics/autotrack#137 for details, why autotrack also needs dom-utils.
...to avoid SyntaxError in legacy browsers googleanalytics/autotrack#137
It seems a common pattern for modules in npm these days is to publish their code as ES5, while keeping ES6 modules in the original source. The idea being is that it doesn't require any consumers to have any knowledge of how external modules are written, it just works out of the box.
Assuming most modules in npm are already compiled, most webpack configs you see tend to ignore
node_modules
for faster compilation time:This can cause issues with bundlers if your code isn't ES5 because if you have this configuration, it chokes on ES6 specific code. You can work around this for
autotrack
by excluding these specific packages:exclude: /node_modules\/(?!(autotrack|dom-utils))/
However, that can get pretty long if you have a lot of external packages that aren't precompiled. It's also not as straightforward for someone who is starting out and may not be familiar with the inner workings of webpack.
In either case, either this should be documented for bundle users or have published ES5 modules in npm so that it's not an issue. I'd be happy to create a pull request to help.
The text was updated successfully, but these errors were encountered: