Webpack external attribute meaning - reactjs

I'm reading a react project. In this project, they defined an external like this:
webpackConfig.externals = {}
webpackConfig.externals['react/lib/ExecutionEnvironment'] = true
webpackConfig.externals['react/lib/ReactContext'] = true
webpackConfig.externals['react/addons'] = true
I have read Webpack document but I still don't understand above lines. What is the meaning when define those configurations ?
Thanks

The externals configuration option provides a way of excluding dependencies from the output bundles. Instead, the created bundle relies on that dependency to be present in the consumer's environment. This feature is typically most useful to library developers, however there are a variety of applications for it.
It is used to build a library with webpack that has dependencies to other libraries which should not be included in the compiled version. The externals option defines dependencies that should be resolved in the target environment.
Check these links for more explanation:
https://webpack.js.org/configuration/externals/
https://github.com/webpack/webpack/tree/master/examples/externals
http://tomasalabes.me/blog/_site/web-development/2016/04/30/Webpack-Series-Part-1.html

Related

How Gradle decides from which dependency to take class if it present in more than one

I'm using Gradle and have 2 dependencies in my project:
implementation group: 'org.seleniumhq.selenium', name: 'selenium-api', version: '3.1.4'
implementation group: 'io.appium', name: 'java-client', version: '5.0.2'
Both dependencies have a class WebDriver under the same package:
org.openqa.selenium.WebDriver
Despite the order of these 2 dependencies in the build.gradle file when I use WebDriver the reference goes to the second dependency - java-client.
How does Gradle decide which dependency to use?
If I comment out java-client the reference goes to the other one (selenium-api - the one I expect to be used).
Playing around with versions of the java-client showed even more confusing results:
while using a version less than 4.1.0 WebDriver class dependency is resolved correctly - from the selenium-api;
while using version 4.1.0 and higher it is resolved to the java-client.
I can't figure out what is the rule here.
Or how can I specify a resolution strategy in this case?
The question is not about the build tool and it's dependency resolution. From Gradle perspective those dependencies have nothing in common and are resolved independently.
Each dependency becomes an entry in the class path of the runtime, so which of the classes used is just a question of the class path order which is a bad idea in general.
Two different library artifacts differing in more than the version should not offer equal classes - except you really want to replace it and must never be used together like SLF4J wrappers. Instead they should change the package structure (see Apache Commons Lang e.g. moving package org.apache.commons.lang to import org.apache.commons.lang3 to avoid conflicts when included by transitive dependencies or prefixing repackaged classes).
In this case Appium did a bad job including Selenium classes instead of declaring a transitive dependency. You should not use both dependencies in one project module or will get unpredictable results especially if the implementations of the selenium classes differ. As far as I know this problem has been addressed in later versions of Appium, try to upgrade to version 7 instead of 5.

how to confirm if tree shaking is working with Webpack 2?

I just finished updating my react app from webpack 1 to webpack 2. However, My bundle size increased by ~30Kb. I was hoping the bundle size would decrease , How can i confirm that tree shaking worked. And why the increase?
TL;DR: As of version 2.3, webpack doesn't have any tree shaking. It merely uses UglifyJS to remove unused code.
First we must define what is tree shaking.
Stackoverflow defines it as "dead code elimination algorithm for modern javascript".
Webpack clarifies that it relies on ES2015 module import/export for the static structure of its module system.
Rollup (which originally popularized the term) also has a similar explanation.
So we can deduce a specific definition: static exclusion of unused ES module exports.
Now, let's see which stages of transformation each module usually has:
babel-loader is fed an entry point which is a javascript file in some module format. Babel can either transform it to another module format of leave it as is (module: false)
webpack will statically parse the file and find imported modules (using some sort of regexp)
webpack will either transform the module format (if babel doesn't tranform it already) or add some wrappers (for commonjs modules)
imported module becomes an entry point and goes to babel-loader
after all modules are loaded and transformed, uglify will process the result bunle and remove unused code (unused: true)
Now, we can see that while uglify can remove unused exports it doesn't actually rely on ES module syntax. It's just a general purpose dead code elimination so it can't be defined as "Tree shaking".
So how can we confirm whether webpack has tree shaking?
First of all, all the code must be in ES module format.
As it was already mentioned in another answer we must disable Uglify.
We also must disable babel's module transformation as we can't know whether a module is used at that phase.
And now if webpack actually implements a tree shaking algorithm we can confirm it by looking at the bundle size of this entry point:
import { keyBy } from 'lodash-es'; // lodash is in ES module format
console.log(keyBy([{ key: 'value' }], 'key'));
If webpack does have tree shaking the result should be tens of kilobytes. If it doesn't it would be half a megabyte or more.
There's a few steps you can take:
turn off minification/uglify
insert comments into some of the functions you know are unused
check the output to see if those comments are there or not
Webpack can also show you the size of each import module/package. For example, at work we have a bundle that includes both lodash and underscore because one of the libraries we're using requires each of them; webpack clearly shows how many kilobytes each package adds:
You should be able to see from this where the increase in size is coming from.

Fallback for webpack external libraries

Is there a way to specify a fallback for webpack external, for example if I can't find angular then try to search for it in your node_modules?
You can reference parts 2 of the answer to this Webpack question.
You can use the provide plugin and set an alias for the global. As stated:
Most legacy modules rely on the presence of specific globals, like jQuery plugins do on $ or jQuery. In this scenario you can configure webpack, to prepend var $ = require("jquery") everytime it encounters the global $ identifier.
The angular global will be treated the same way. Therefore if you don't have angular in node modules but loaded via external script, Webpack will allow you to use it the same way as if it was living in your node modules.

What is the difference between "configuration: 'android-endpoints'" and "configuration: 'endpoints'" in build.gradle in Android Studio?

In my app module (which depends on my backend endpoints module), I have the following
dependencies {
compile project(path: ':backend', configuration: 'android-endpoints')
}
But the following also works.
dependencies {
compile project(path: ':backend', configuration: 'endpoints')
}
I see that the generated .jar file dependency has the "android" appended to its name in the former case. However, I suspect there is a more fundamental difference between the two. Does anyone know?
I found the following cryptic reference here:
https://github.com/GoogleCloudPlatform/gradle-appengine-plugin
search for "How do I use a compile dependency on my endpoints client libraries from another project?" in the FAQ section.
Thanks for your help and I hope this isn't a stupid question.
android-endpoints adds few a extra transitive dependencies to the artifact that are required to use endpoints with android, it also removes some that are already included with android.
included : "google-api-client-android"
excluded : "org.apache.httpcomponents:httpclient"
endpoints only adds "google-api-client" and doesn't exclude anything.

gruntjs / angularjs - optional development config?

Like most js web apps we have a config.js file that contains global config information about the app, base api urls and such. These values are often different in local development than in production.
I've looked at answers like: Development mode for AngularJS using GruntJS, and also things like grunt-replace for creating an on-the-fly config file.
My issue is that the "development" part varies from developer to developer, we all need a version of the API setup so the base api urls will be different. I'd like to allow each developer to override specific variables in the config in a way that doesn't require them to commit that info to the git repo (I agree that this isn't best practice, everything should be in the repo, but as this is only 1/2 variables for this project I can overlook it)
Any ideas on how to achieve this setup?
You can use grunt-preprocess. I would have production (and dev-server, etc) values in a file, say env.json. You could use grunt to look for an optional file, say overrides.json or developer.json, which would extend/overwrite the values from env.json.
var envFile = require('./env.json');
You can create command line options to grunt with grunt.option, e.g. var env = grunt.option('env') || undefined;, which could be used to turn off overriding.
You can get data from the optional file using fs.existsSync:
var fs = require('fs');
var developerFile;
if (fs.existsSync('./developer.json')) {
developerFile = require('./developer.json');
}
The simplest way to define the grunt-preprocess context would be to use the developer.json file if present, or the env.json file if not:
context: developerFile ? developerFile : envFile;
This requires the developer file to be complete. An alternative is to extend the envFile with options from developerFile if it's present.
In my project, we use different config files (which are basically files with JS object). So every developer has his app/configs/developer/config.js file, which is not comited in the source control, so every developer has his own setup. Project uses link to app/scripts/config.js by default and this file is just a soft link to developers config file. However, there are also app/configs/staging/config.js and app/configs/production/config.js files, which are replaced when using gruntjj to build project. Those configs are just copied to build solution instead of soft linked file.
I hope that makes sense..

Resources