Comments (20)
@gaearon
I implemented this in my own (large) project and in create-react-app.
On my own project it took our rebuild times from ~4000ms to ~1000ms.
However in the CRA which basically just has React in the DLL the difference is alot smaller.
Stats
Commit | First build | second build | Rebuild 1 | Rebuild 2 | Rebuild 3 | File 2 | File 2 RB |
---|---|---|---|---|---|---|---|
PreDLL | 4335ms | 4413ms | 666ms | 322ms | 598ms | 563ms | 353ms |
PostDLL | 2611ms | 2752ms | 220ms | 183ms | 144ms | 193ms | 313ms |
Added complexity
Creating DLL package list
The list of node modules to for the DLL can either be automatically generated from the package.json (ala react-boilerplate) or manually added to an array.
Automatically going through the package.json makes it easier but I found some packages (react-toolbox) can break the dll build (due to importing of sass files).
Manually the user knows what is going in the DLL but has to remember to add files to the array when they add new node_modules (but they know what packages make up the dll). Any missed files just go into the regular bundle.
Weird webpack stuff
DLL's aren't used by many project. When you eject and see it, it might be confusing (although my implementation is much simpler than react-boilerplate). It also needs to be run on any update to the node_modules (I believe it can be ran as postinstall
)
Reliability
React-boilerplate is the only large project I know of using DLLs. It should be getting a lot of user testing now, but as of this moment its largely untested in real world apps.
Worth adding?
I don't have much of an answer if it's worth adding. The 'feeling' between the two rather minimal as is. However if CRA is used for something containin 10+ node_modules, the difference might be much larger.
Large CRA example
Example with larger CRA (imports: redux, react-redux, lodash, react-bootstrap, immutable, redux-saga, reselect, babel-polyfill, react-router. No other changes)
Commit | First build | second build | Rebuild 1 | Rebuild 2 | Rebuild 3 | File 2 | File 2 RB |
---|---|---|---|---|---|---|---|
PreDLL | 6801ms | 7536ms | 1489ms | 1192ms | 816ms | 1248ms | 1226ms |
PostDLL | 2965ms | 2202ms | 633ms | 145ms | 222ms | 230ms | 241ms |
from create-react-app.
I am so excited about this!
After seeing @ro-savage's Stats, I had to try it for myself.
I was so impressed by it. I realized that I really-really want it to be there the next time I build something with CRA.
So, I decided to make a PR.
I wanted to Add the DllPlugin to CRA without introducing new files,
I liked the cleanness of the source code and didn't wanted to mess it with all the DllPlugin's Boilerplate.
The main challenges was that:
- The DLL has to have its own config
- The DLL must be built ahead of time. Otherwise, the DllReferencePlugin won't be able to find the DLL's manifest.
- The DLL bundle needs to be injected to index.html before the main one, but only in development mode.
- The DLL needs to be rebuilt every time a node module is added or removed. but also stored in a cache, to prevent unnecessary build.
- The user should be able to easily choose what modules are included in the DLL, ideally from his package.json
Those constraints led to many iterations over this PR,
until one night I realized that the most declarative and minimalist form to add DLL Support to CRA is by creating a new webpack plugin that encapsulates all that logic.
You just add it to webpack.config.dev.js as usual, tell it which modules you want to move to the DLL and that's it.
Now, when you run webpack for the first time, It creates a separate compiler that builds the DLLs, stores them in a cache directory, and load them into the memory so webpack's dev server can consume them later.
Then, it connects with the HTMLPlugin to injects the DLL bundles before the main one.
The next time you run webpack, it will read the DLLs from the cache, to skip unnecessary build, unless node_modules changed or if the plugin's settings are different from the last build.
The more I worked on the Plugin, the more I realized that there's nothing specific to CRA about it, and that this plugin can serve many other webpacks configurations, so I extracted the code into a separate repository and called it AutoDllPlugin.
This PR is now included only 2 changes:
It adds a plugin to webpack.config.dev.js
and another dependency to react-script's package.json
The way to use it is by adding the dll entries in the packge.json, like so:
{
"name": "closed-cra-dll-test",
"version": "1.0.0",
"private": true,
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1"
},
"devDependencies": {
"react-scripts": "1.0.7"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"dll": {
"entry": {
"vendor": [
"react",
"react-dom"
]
}
}
}
Only ./polyfills are included by default.
I left 'react' and 'react-dom' intentionally, in case someone we'll want to use CRA to work on one of them.
That's it.
It was a really incredible journey for me to make this plugin.
I hope you'll like it.
from create-react-app.
@gaearon Sorry this sat here for nearly a week. I guess now I know you were talking to me? ;)
from create-react-app.
IMO it'd be nice to have, even though the gains on the minimal examples are small. It's such a pain to set up if you're unfamiliar with it, so having something working out of the box is really nice.
from create-react-app.
@mxstbr Would be great if you could take a look at it. I saw react-boilerplate
uses it but I can’t figure out how to add it. 😢
from create-react-app.
(No pressure though! I’m sure somebody will help us after open sourcing if you don’t have time. Thanks a lot for your help so far.)
from create-react-app.
Would not recommend, adds a lot of complexity. The sole benefit is that in dev mode, your builds are slightly faster if you have a lot of dependencies. (in our case it knocked off a few seconds of build time)
In production, we simply use the CommonsChunkPlugin
, which basically does the same thing automatically, it's just a bit slower since it has to figure it out, whereas with the DLL plugin we tell webpack what our vendor deps are.
from create-react-app.
Oh, okay, not a big deal then.
from create-react-app.
@mxstbr @gaearon I thought the big benefit of DLL was rebuild times. Having a faster hot-reload/rebuild when you make a change is very useful.
I did some quick and rough testing on react-boilerplate taking the commits before and after DLL was added.
Both tested in same order doing and in two different folders, right after one another.
Start -> Start -> Change Footer -> Change Footer -> Change Footer -> Change Button -> Change A
Commit | First build | second build | Rebuild 1 | Rebuild 2 | Rebuild 3 | File 2 | File 3 |
---|---|---|---|---|---|---|---|
PreDLL | 8584ms | 7740ms | 1672ms | 745ms | 551ms | 802ms | 742ms |
PostDLL | 5566ms | 6488ms | 266ms | 156ms | 230ms | 328ms | 362ms |
I feel those rebuild times are pretty significant. Its a difference between feeling instant and 'waiting' for the reload. Larger project should have even more benefit.
As this project is, in part about a great dev experience, it would make sense to me that that fast rebuilds is worth adding if it can be done in a not-so-complicated manner (would be a great example for others to follow as well)
from create-react-app.
If you can submit a PR significantly improving rebuild times in any way I will be happy to get it in.
from create-react-app.
Shameless plug, you can look how tarec uses DLLS:
- There is a command (
tarec dll
) that will put all thedependencies
in the package.json of the application in the dll. See the webpack config. Dlls will be generated in a.tarec
folder, where we can find them - When the application starts, we look for dlls and include them in the page. @SimenB's
add-asset-html-webpack-plugin
does a nice job for that
So it's not perfect yet:
- We assume that all
dependencies
will be included in the application. I think this is a fair assumption though - Users are responsible for regenerating the dlls when their dependencies change. This step can be automated. We could generate a hash of the dependencies and regenerate the Dlls automatically for example
- This is not activated for production builds as I feel performance improvements will mostly be beneficial for hot reload and startup times
But I concur with @ro-savage, in my experience it yields very impressive improvements even on medium size apps with a dozen dependencies.
It also improves the debugging experiences on lower-end machines in chrome because the source maps of the actual application become smaller.
from create-react-app.
I implemented it pretty quickly in a work project with similar performance gains as @ro-savage:
View the diff...
diff --git a/package.json b/package.json
index f8fab95..75541b4 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"prebuild": "rimraf build",
"build": "per-env",
"build:development": "webpack --watch --config webpack.config.server.js",
+ "build:dll": "webpack --config webpack.config.dll.js",
"build:staging": "webpack",
"build:production": "webpack",
"deploy": "per-env",
@@ -31,6 +32,7 @@
"start:development": "npm run build:development",
"start:production": "start-cluster build/server.js",
"start:staging": "start-cluster build/server.js",
+ "postinstall": "npm run build:dll",
"pretest": "rimraf build && npm run lint",
"test": "per-env",
"test:development": "mocha --bail --watch src/**/*.test.js",
diff --git a/src/middleware/view.js b/src/middleware/view.js
index 8021bfb..e624bfa 100644
--- a/src/middleware/view.js
+++ b/src/middleware/view.js
@@ -46,6 +46,7 @@ export default router()
</script>
<script src="https://cdn.ravenjs.com/2.1.0/raven.min.js"></script>
+ <script src="/vendor.dll.js"></script>
<script src="/${entry}.js"></script>
<script>
Raven.config('https://[email protected]/67531').install()
diff --git a/webpack.config.client.js b/webpack.config.client.js
index c2a8fca..1c8fc08 100644
--- a/webpack.config.client.js
+++ b/webpack.config.client.js
@@ -47,6 +47,10 @@ module.exports = require("./webpack.config.defaults")
},
},
})
+ .plugin("webpack.DllReferencePlugin", {
+ context: process.cwd(),
+ manifest: require("./build/vendor.dll.json"),
+ })
.plugin("webpack.DefinePlugin", {
__CLIENT__: true,
__SERVER__: false,
diff --git a/webpack.config.dll.js b/webpack.config.dll.js
new file mode 100644
index 0000000..daf747c
--- /dev/null
+++ b/webpack.config.dll.js
@@ -0,0 +1,39 @@
+module.exports = require("@terse/webpack").api()
+ .entry({
+ vendor: [
+ "codemirror",
+ "codemirror/mode/css/css.js",
+ "codemirror/mode/htmlmixed/htmlmixed.js",
+ "codemirror/mode/javascript/javascript.js",
+ "codemirror/mode/markdown/markdown.js",
+ "history",
+ "react",
+ "react-codemirror",
+ "react-dom",
+ "react-redux",
+ "react-router",
+ "react-select",
+ ],
+ })
+ .output({
+ filename: "[name].dll.js",
+ library: "[name]_[hash]",
+ path: "build",
+ })
+ .plugin("webpack.DllPlugin", {
+ name: "[name]_[hash]",
+ path: "build/[name].dll.json",
+ })
+ .plugin("webpack-md5-hash")
+ .plugin("webpack.NamedModulesPlugin")
+ .when(["staging", "production"], function minify(api) {
+ return api
+ .plugin("webpack.optimize.DedupePlugin")
+ .plugin("webpack.optimize.UglifyJsPlugin", {
+ mangle: true,
+ sourcemap: false,
+ })
+ ;
+ })
+ .getConfig()
+;
It was a cinch to implement and, since the project uses bundleDependencies
, it could be possible to build it when publishing the package & have it available without requiring the user to build it.
Or, you can do what I did and have it happen on postinstall
, which works well so far.
from create-react-app.
Would you like to submit a proof of concept PR?
from create-react-app.
Haha. If you’d like 😄
from create-react-app.
Closing for lack of interest. If somebody wants to do this, please go ahead and submit a PR!
from create-react-app.
Can you do the same thing with CommonChunks plugin please?
from create-react-app.
Hi @JustFly1984,
I've never used the CommonChunks Plugin before, I'll take a look at it.
from create-react-app.
Thank you)
from create-react-app.
@asfktz nice job
from create-react-app.
nice job
from create-react-app.
Related Issues (20)
- Install windows HOT 1
- err
- create-react-app my-app
- Why react app keep calling ws/info and ws/iframe.html ? HOT 2
- Split off eslint-config-react-app from the rest of this project HOT 1
- Erron installiation create-react-app HOT 1
- Issue while creating an react app HOT 3
- Snyk Package Analysis - Incomplete List of Disallowed Inputs Vulnerability HOT 1
- Snyk Package Analysis - Sandbox Bypass Copy link to issue Vulnerability HOT 1
- Snyk Package Analysis - Regular Expression Denial of Service (ReDoS) Vulnerability HOT 1
- Snyk Package Analysis - Regular Expression Denial of Service (ReDoS) Vulnerability HOT 1
- Snyk Package Analysis - Improper Input Validation Vulnerability HOT 1
- Snyk Package Analysis - Prototype Pollution Vulnerability HOT 1
- Snyk Package Analysis - Missing Release of Resource after Effective Lifetime Vulnerability HOT 1
- Docs: code splitting links to old/incorrect React page
- Create issue Facebook app HOT 1
- Uncaught ReferenceError: process is not defined at emitReadable (_stream_readable.js:529:1) at onEofChunk (_stream_readable.js:506:1) at readableAddChunk (_stream_readable.js:255:1) at Readable.push (_stream_readable.js:241:1) at index.js:423:1 emitReadable @ _stream_readable.js:529 onEofChunk @ _stream_readable.js:506 readableAddChunk @ _stream_readable.js:255 Readable.push @ _stream_readable.js:241 (anonymous) @ index.js:423 Show 5 more frames Show less
- Run `npm install` in `D:\git\r\`. HOT 1
- Hi gaearon
- Hebosho911
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from create-react-app.