Different babel or webpack configuration based on entry point - javascript

In my application, I am applying babel using webpack (which I use to generate my bundles from my source files). I create one bundle that runs on the server (entry point server_rendering.js) in an ExecJS environment and another that runs on the client (entry point application.js). Due to some peculiar interactions with certain JS libraries, I need to run different babel transformations dependent on the entry point file. How might I do this?
To clarify, there seem to be a number of similar questions concerned with babel responding differently based on environment variables which is not what I want to do here. I want to be able to compile both files as part of the same webpack process.
In my situation, I could also be satisfied with augmenting my webpack configuration based on the entry point.

You would need multiple Webpack configs, for example by returning an array of configs from webpack.config.js. Webpack can't do what you ask with one config because entrypoints are just that, entry points into one application. A given file will only be compiled a single time within an application, so there isn't any way to compile the same file multiple ways.
How you integrate that with Babel is up to you, but you could for instance pass envName: "client" to babel-loader in your client-side Webpack config, and envName: "server" to Babel your server Webpack config. Then your Babel config can select the set of plugins based on that value.

Related

How could I write a Webpack plugin that updates `resolve.modules` and `resolve.alias` in `--watch` mode at runtime?

I work in a large monorepo that has very many files that are processed by Webpack. One of our main patterns is that we use fully-qualified filenames for every module name and import. For example, if I have a file with path "/path/to/module/MyCoolModule.js", the import would simply look like import MyCoolModule from 'MyCoolModule' without needing any explicit path to the module. This is enabled by recursively scanning the project's directories for all relevant .js files/folders at Webpack init and then passing in the scanned files into resolve.modules and resolve.alias.
We like this pattern, and it works well for general usage when webpack is run in watch mode; however, it breaks down when new folders and files are added to the project while Webpack is already running. Because the files and folders are only scanned at Webpack init, Webpack is unable to resolve imports for new files/folders added since it started, so compilation will fail. This requires us to restart Webpack, which takes 1-2 minutes on our project. Across many engineers when switching between git branches or updating changes from master, this can add up to a significant slowdown in raw time and in breaking flow.
I'd like to write a plugin that will dynamically update the resolve.modules and resolve.alias such that we do not have to restart Webpack when new folders and files are added to the project. However, I am at a loss for how to do this. It seems like I have three main questions:
What hook(s) can I tap into to be notified when Webpack detects new files or folders?
Where would I put this plugin to access the above hooks? Would it exist in the top-level plugins config? resolve.plugins? etc.. As I'm understanding it, where the plugin is placed/configured will affect what hooks are available to it
How would I make Webpack aware of these dynamic updates? I am guessing there's a reference to the resolve obj somewhere that holds resolve.modules and resolve.aliases that Webpack actively references, but I'm not sure where that would live or where to access it (this could be completely wrong too)
(note: we are technically using Webpack 4, but answers for Webpack 5 are welcomed because I know we're behind there, and I'd guess a Webpack 5 solution would still point me in the right direction)
Thanks!

Brand wise building with Webpack

I have a requirement to do webpack build based on the brand (use brand specific css to build). I want to pass the brand as an agrument while building. for example I have 2 brands brandA and brandB, I will have build commands as below.
npm build --brandA
npm build --brandB
Is there a solution for this kind of brand wise build in webpack? Please help.
Yes, webpack is really good at this sort of thing once you get familiar with it. There are a few different ways you could approach it, but they all relate to how you set up your webpack config.
Write separate webpack config files for each 'brand.' This is the closest match to your example, because webpack has a CLI flag for specifying a config file to use, e.g. webpack --config webpack.config.brand-a.js
But most of your webpack config will probably be the same for each brand(especially if it's only the CSS that's changing). So rather than have duplicate code, you split out the parts that are the same in each brand's config file, maybe put each chunk in a /webpack directory at the root of your project as separate little JS modules. So you have a module for the loader config, and one for the plugin config, etc., and your config files each require/import those. Now your config files have a lot less boilerplate in them and are mostly just the parts that differ from build to build.
Once you start splitting up your webpack config there's a lot of ways to organize it. Although the normal webpack config format is to export a single config object, it also allows you to export an array of config objects from your config file -- in this case webpack will do a separate build for each config object in the exported array. So another way to implement this would be a single webpack.config.js file, where you write a little code to iterate through the brands and, for each one, push a config object into an array -- then export the whole array. The upside here would be you could run all the builds with a single command, as webpack takes care of creating separate processes for each build.
A word of warning -- build time can get pretty hefty. (Although I haven't been deep into it since v1.x and things have probably gotten better.) If you build a lot you might find that it's worth looking into webpack optimization to speed up the process.

Webpack: Bundle several js framework into one bundle?

I'm trying to understand the purpose of webpack. I'm intending to use fixed-data-table from React and it has to be processed through webpack and transformed with Babel as it uses require function which otherwise can't be processed by the browser.
To output a bundle.js file, could I include, say, several frameworks in one bundle? I.e. Bootstrap, React, React-dom, and other frameworks? As far as I can tell in the documentation, you can only input one .js file and process it into a bundle.js - or am I wrong? Are there examples of importing several frameworks into one webpack configuration file, and outputting just one Bundle.js? I haven't been able to google myself to that point. Seems like most people process just one framework to one bundle, which doesn't seem intuitive to me.
Webpack, literally takes all your dependencies and mashes it into one big file known as the ultimate bundle.js
There is no limit (other than the space of your hard drive) to how many frameworks you can include in one bundle, Webpack just needs to be aware that this dependency is in use and needs to be required. Depending on your build configurations, Webpack should find these immediately after traversing your directory.
The easiest method is to register the framework via. require or import call in your Babel ES6 files. If this is not possible, I suggest reading the documentation on RequireJS that is an alternate method to register them.

webpack build to multiple files

I have web pack application and want to build output multiple files not a single javascript file. for example if I have such folder structure
components
1.js
2.js
actions
1.js.
2.js
my webpack build have to compile files in same folder structure. How i can achieve that?
I tried babel cli:
babel ./src --out-dir ./lib --source-maps --presets es2015,react --plugins babel-plugin-add-module-exports,babel-plugin-transform-decorators-legacy,babel-plugin-transform-class-properties --watch
It outputs files as I wanted but getting error
Cannot resolve module
Because it does not know anything about webpack resolve.
Any suggestions?
Getting webpack to output multiple files is possible but it does have limitations. First it's important to understand how this works. Webpack actually provides a runtime script that can load code "chunks" as they are needed, this is important for large applications so the user doesn't have to download the javascript for the entire app just to see the homepage. But webpack needs to keep track of these chunks and what they're named at build time to be able to load them correctly at run time. For that reason it has it's own file naming conventions to enable this functionality. See more here: https://webpack.js.org/guides/code-splitting/. So you can require.ensure all of your deps, but they won't be named and foldered they way you describe as webpack's runtime wouldn't be able to find them in that case.
The other thing that's important to consider is that webpack is a bundler, so it's meant to bundle files. Essentially your saying you don't want to bundle your files. So if that's the case, you should probably look into using require.js. Many people have moved from require to bundlers such as Wepback and Browserify as typically it's not efficient to download every little module seperately. But, every app is different so you may in fact have a good reason to not bundle.
If you do in fact want to do some bundling but want to optimize how it's done, then I can help with that as well, and webpack is certainly a great tool for that. But I'll need to understand your use case a little more to give the best advice.

Interchangeable configuration files in Webpack

I'm trying to bundle a react project that can run in multiple environments and needs different configurations to run on each one. I have it set up with browserify, but have recently been looking to move to webpack.
The idea goes like this: there's a js directory with a bunch of js files, of which main.js is the entry point. There is also a config folder with development.js, staging.js, production.js and so on. I am importing the configuration from all files using import config from './config'. So I want to be able to create a main.bundle.js file with all our code, and another config.js whose contents can be replaced with those of {environment}.js.
This allows us to choose the configuration for the app in deploy time, not at build time, just by copying over the contents of {environment.js}.
I have attempted to unsuccessfully use webpack's CommonsChunkPlugin, but it complains at bundle time that js/config.js is not there (obviously).
Why not make multiple builds, one with each config, and then deploy the one you want? There's different ways you could load the desired config for the build, but one very way would be to use the DefinePlugin to define constants for each environment, write a conditional against those constants to load the corresponding config, and let the Uglify plugin's dead code elimination pare down the conditional to the one valid case. I've used this approach in a number of places to handle per-environment conditionals without bloating the production code.

Categories