Brand wise building with Webpack - javascript

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.

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!

Different babel or webpack configuration based on entry point

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.

Allowing deep imports from npm packages without a build directory (like lib/dist) in the path

The standard approach when packaging code for npm is to place transpiled or bundled code in a separate lib, dist or build directory and to set the package.main property (and module/browser) to point to the built files, which makes the existence of the build directory transparent when doing bare imports (without a path). However, if deep imports are needed (importing specific modules not referenced in package.json properties), it means that the build directory needs to be included in the path like so: require('package/lib/some-module'), which looks bad.
Are there any examples of an approach that would at the same time:
Support deep imports without the build directory in the path
Support npm-link and tools like Lerna
Still place the built files in a separate directory for tidiness
Every approach I've tried or seen fails to fit one of the criteria; for example, copying package.json into the build directory (lib/dist) allows publishing or linking the package from the build directory, but tools like Lerna don't support this approach since they expect the package.json to be in the root of the package instead of the build directory, so only points 1 and 3 are met.
Placing sources in the root of the package and the transpiled or built files next to the sources allows deep imports and is also supported by Lerna, but it doesn't meed the 3rd criteria (tidiness).
Having import maps would solve this issue, but I'm not sure if any tool supports import maps yet.
The question is: is there some approach that I've missed that could meet all three listed points?

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