Created
September 16, 2016 11:27
-
-
Save trotzig/2a95f39f83b2330f85d8b9fdaec67e2e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 7b5f5c739eefb8c5bca2981b007ab09b8df9b63a | |
Author: Henric Trotzig + Kevin Kehl <henric.trotzig+kevin.kehl@brigade.com> | |
Date: Mon Jul 11 21:46:09 2016 +0200 | |
Load partner tools asynchronously | |
This is the first commit in a serious of commits aiming to split up our | |
application bundle into smaller pieces. By using the `lazy` support of | |
the bundle-loader webpack plugin [1], we can make require statements | |
resolve a function that can be used to asynchronously load a module | |
instead of resolving the module itself. We can then use that | |
lazy-loading function in our <App> router to dynamically load routes for | |
a specific part of our app. | |
The technique is inspired by | |
http://henleyedition.com/implicit-code-splitting-with-react-router-and-webpack/ | |
which in turn is based on the Dynamic Routing technique: | |
https://github.com/reactjs/react-router/blob/master/docs/guides/DynamicRouting.md | |
When you now load a partner tools page (e.g. /partners/1), you'll see | |
two HTTP requests. Something like this: | |
- application.js | |
- assets11.11.js | |
Reducing the size of our application.js bundle should help make our | |
application faster, because there will be less to download and less code | |
to initialize. | |
[1]: https://github.com/webpack/bundle-loader | |
Change-Id: Ie694f3dae6d1f369b0d0e58b76a5632e630710ed | |
Reviewed-on: https://code.brigade.zone/15035 | |
Reviewed-by: Kevin Kehl <kevin.kehl@brigade.com> | |
Reviewed-by: Tom Dooner <tom.dooner@brigade.com> | |
Tested-by: Leeroy Jenkins <jenkins@brigade.com> | |
diff --git a/app/assets/components/App/index.jsx b/app/assets/components/App/index.jsx | |
index b4319f5..a20c16d 100644 | |
--- a/app/assets/components/App/index.jsx | |
+++ b/app/assets/components/App/index.jsx | |
@@ -1,4 +1,3 @@ | |
-const IndexRoute = require('react-router/lib/IndexRoute'); | |
const React = require('react'); | |
const Redirect = require('react-router/lib/Redirect'); | |
const Route = require('react-router/lib/Route'); | |
@@ -6,8 +5,6 @@ const Router = require('react-router/lib/Router'); | |
const AccountFormPage = require('components/pages/AccountFormPage'); | |
const AlertsPage = require('components/pages/AlertsPage'); | |
-const CampaignScreenerPositionsPage = | |
- require('components/partners/CampaignScreenerPositionsPage'); | |
const CausesSignUpImmediatelyPage = | |
require('components/pages/CausesSignUpImmediatelyPage'); | |
const CommPrefsPage = require('components/pages/CommPrefsPage'); | |
@@ -43,13 +40,8 @@ const OnboardingFlowTopicPage = | |
require('components/pages/OnboardingFlowTopicPage'); | |
const OnboardingFlowVoterIdentityPage = | |
require('components/pages/OnboardingFlowVoterIdentityPage'); | |
-const PartnerCampaignPage = require('components/partners/PartnerCampaignPage'); | |
-const PartnerCampaignUpdateTable = | |
- require('components/partners/PartnerCampaignUpdateTable'); | |
-const PartnerHomePage = require('components/partners/PartnerHomePage'); | |
-const PartnerPetitionTable = | |
- require('components/partners/PartnerPetitionTable'); | |
-const PartnerToolsLayout = require('components/partners/Layout'); | |
+const PartnerToolsRoutes = | |
+ require('bundle?lazy!components/routes/PartnerToolsRoutes'); | |
const PartnersPage = require('components/pages/PartnersPage'); | |
const PoliticianPage = require('components/pages/PoliticianPage'); | |
const PopularPage = require('components/pages/PopularPage'); | |
@@ -150,6 +142,20 @@ function redirectToHomeIfLoggedIn(nextState, replaceState) { | |
replaceState({}, Urls.loggedInHome()); | |
} | |
+/** | |
+ * Utility function to lazy-load a module imported with the `bundle?lazy!` | |
+ * loader. Can be used in e.g. `getChildRoutes`, `getComponent` to make the | |
+ * module asynchronously load through a separate HTTP GET. | |
+ * | |
+ * @param {Function} lazyModule imported with the `bundle?lazy!` prefix. | |
+ * @return {Function} | |
+ */ | |
+function lazyLoad(lazyModule) { | |
+ return (_, done) => { | |
+ lazyModule(module => done(null, module)); | |
+ }; | |
+} | |
+ | |
let rendered = false; | |
const App = React.createClass({ | |
@@ -310,18 +316,10 @@ const App = React.createClass({ | |
path='/partners' | |
component={PartnersPage} | |
/> | |
- <Route path='/partners/:organizationId' component={PartnerToolsLayout}> | |
- <IndexRoute component={PartnerHomePage} /> | |
- <Redirect | |
- from='campaigns/:campaignId' | |
- to='campaigns/:campaignId/updates' | |
- /> | |
- <Route path='campaigns/:campaignId' component={PartnerCampaignPage}> | |
- <Route path='updates' component={PartnerCampaignUpdateTable} /> | |
- <Route path='petitions' component={PartnerPetitionTable} /> | |
- <Route path='screeners' component={CampaignScreenerPositionsPage} /> | |
- </Route> | |
- </Route> | |
+ <Route | |
+ path='/partners' | |
+ getChildRoutes={lazyLoad(PartnerToolsRoutes)} | |
+ /> | |
<Redirect | |
from='/petitions/:petitionId' | |
to='/' | |
diff --git a/app/assets/components/routes/PartnerToolsRoutes.jsx b/app/assets/components/routes/PartnerToolsRoutes.jsx | |
new file mode 100644 | |
index 0000000..1ccc45b | |
--- /dev/null | |
+++ b/app/assets/components/routes/PartnerToolsRoutes.jsx | |
@@ -0,0 +1,29 @@ | |
+const IndexRoute = require('react-router/lib/IndexRoute'); | |
+const React = require('react'); | |
+const Redirect = require('react-router/lib/Redirect'); | |
+const Route = require('react-router/lib/Route'); | |
+ | |
+const CampaignScreenerPositionsPage = | |
+ require('components/partners/CampaignScreenerPositionsPage'); | |
+const PartnerCampaignPage = require('components/partners/PartnerCampaignPage'); | |
+const PartnerCampaignUpdateTable = | |
+ require('components/partners/PartnerCampaignUpdateTable'); | |
+const PartnerHomePage = require('components/partners/PartnerHomePage'); | |
+const PartnerPetitionTable = | |
+ require('components/partners/PartnerPetitionTable'); | |
+const PartnerToolsLayout = require('components/partners/Layout'); | |
+ | |
+module.exports = [ | |
+ <Route path=':organizationId' component={PartnerToolsLayout}> | |
+ <IndexRoute component={PartnerHomePage} /> | |
+ <Redirect | |
+ from='campaigns/:campaignId' | |
+ to='campaigns/:campaignId/updates' | |
+ /> | |
+ <Route path='campaigns/:campaignId' component={PartnerCampaignPage}> | |
+ <Route path='updates' component={PartnerCampaignUpdateTable} /> | |
+ <Route path='petitions' component={PartnerPetitionTable} /> | |
+ <Route path='screeners' component={CampaignScreenerPositionsPage} /> | |
+ </Route> | |
+ </Route> | |
+]; | |
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json | |
index ba724b7..63585af 100644 | |
--- a/npm-shrinkwrap.json | |
+++ b/npm-shrinkwrap.json | |
@@ -1476,6 +1476,11 @@ | |
"from": "builtin-modules@https://npm.brigade.zone/builtin-modules/-/builtin-modules-1.1.1.tgz", | |
"resolved": "https://npm.brigade.zone/builtin-modules/-/builtin-modules-1.1.1.tgz" | |
}, | |
+ "bundle-loader": { | |
+ "version": "0.5.4", | |
+ "from": "bundle-loader@https://npm.brigade.zone/bundle-loader/-/bundle-loader-0.5.4.tgz", | |
+ "resolved": "https://npm.brigade.zone/bundle-loader/-/bundle-loader-0.5.4.tgz" | |
+ }, | |
"bytes": { | |
"version": "2.1.0", | |
"from": "bytes@https://npm.brigade.zone/bytes/-/bytes-2.1.0.tgz", | |
diff --git a/package.json b/package.json | |
index 170d4b2..1df3e81 100644 | |
--- a/package.json | |
+++ b/package.json | |
@@ -14,6 +14,7 @@ | |
"babel-preset-stage-2": "^6.3.13", | |
"babel-runtime": "^6.3.19", | |
"branch-sdk": "^1.8.4", | |
+ "bundle-loader": "^0.5.4", | |
"classnames": "^2.2.3", | |
"compression-webpack-plugin": "^0.2.0", | |
"css-loader": "^0.23.0", |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 8bd165c8b165268791e9c2620c8c7127376b4fbd | |
Author: Henric Trotzig <henric.trotzig@brigade.com> | |
Date: Thu Jul 14 12:15:01 2016 +0200 | |
Load <DistricPage> asynchronously | |
Adding lazy-loading to our <App> component will help us keep the size | |
down of the main application.js bundle. Making <DistrictPage> load | |
asynchronously shaves off a significant chunk of code. | |
Change-Id: Ic0561bfc01b9901d0e5683fd8393acb7bb66ef19 | |
Reviewed-on: https://code.brigade.zone/15163 | |
Tested-by: Leeroy Jenkins <jenkins@brigade.com> | |
Reviewed-by: Kevin Kehl <kevin.kehl@brigade.com> | |
diff --git a/app/assets/components/App/index.jsx b/app/assets/components/App/index.jsx | |
index 6822941..f240b62 100644 | |
--- a/app/assets/components/App/index.jsx | |
+++ b/app/assets/components/App/index.jsx | |
@@ -8,7 +8,7 @@ const AlertsPage = require('components/pages/AlertsPage'); | |
const CausesSignUpImmediatelyPage = | |
require('components/pages/CausesSignUpImmediatelyPage'); | |
const ConventionSignupPage = require('components/pages/ConventionSignupPage'); | |
-const DistrictPage = require('components/pages/DistrictPage'); | |
+const DistrictPage = require('bundle?lazy!components/pages/DistrictPage'); | |
const GetVerifiedPage = require('components/pages/GetVerifiedPage'); | |
const History = require('lib/history'); | |
const HomePage = require('bundle?lazy!components/pages/HomePage'); | |
@@ -162,7 +162,7 @@ const App = React.createClass({ | |
/> | |
<Route | |
path='/districts/:districtId' | |
- component={DistrictPage.Controller} | |
+ getComponent={lazyLoad(DistrictPage)} | |
/> | |
<Redirect | |
from='/elections/:location' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 0d88af463990f3af90df9e5cc4f6192fecfae64b | |
Author: Henric Trotzig <henric.trotzig@brigade.com> | |
Date: Wed Jul 13 22:26:15 2016 +0200 | |
Prepare webpack config for code splitting | |
I'm about to use a technique to split up our application bundle into | |
multiple pieces, loaded asynchronously based on what page you are | |
looking at. For that to work, webpack needs to be able to dynamically | |
fetch a script from the same origin as the original file. This will work | |
in dev, because we're setting the publicPath [1] to the location of the | |
webpack dev server. But for environments like production and test where | |
we use precompiled assets, we obviously can't fetch from the webpack dev | |
server. | |
I considered two approaches for this change: | |
A) introduce a new webpack.config.development.js config file | |
B) use an environment variable to special-case when the webpack | |
dev-server is used. | |
A would make our already complicated webpack configuration setup even | |
more complicated. B had a smaller footprint, so that's what I decided to | |
go with. | |
[1]: https://github.com/webpack/docs/wiki/configuration#outputpublicpath | |
Change-Id: I19b8b7e8d5c4ccec97a41474440493b299cc153e | |
Reviewed-on: https://code.brigade.zone/15117 | |
Reviewed-by: Tom Dooner <tom.dooner@brigade.com> | |
Tested-by: Leeroy Jenkins <jenkins@brigade.com> | |
diff --git a/script/start-webpack b/script/start-webpack | |
index 3cbb346..b34f3dc 100755 | |
--- a/script/start-webpack | |
+++ b/script/start-webpack | |
@@ -1,7 +1,9 @@ | |
#!/bin/bash | |
+export WEBPACK_DEV_SERVER_ACTIVE=1 | |
+ | |
if [[ -n "$HOT_MODULES" ]]; then | |
- exec "$(npm bin)"/webpack-dev-server $@ --progress --colors --hot --host 0.0.0.0 | |
+ exec "$(npm bin)"/webpack-dev-server "$@" --progress --colors --hot --host 0.0.0.0 | |
else | |
- exec "$(npm bin)"/webpack-dev-server $@ --progress --colors --host 0.0.0.0 | |
+ exec "$(npm bin)"/webpack-dev-server "$@" --progress --colors --host 0.0.0.0 | |
fi | |
diff --git a/webpack.config.common.js b/webpack.config.common.js | |
index 22b1f5d..f52ca48 100644 | |
--- a/webpack.config.common.js | |
+++ b/webpack.config.common.js | |
@@ -18,8 +18,17 @@ function appVersion() { | |
} | |
function appOrigin() { | |
- const appHost = process.env.APP_HOST || 'localhost'; | |
- return 'http://' + appHost + ':8080'; | |
+ if (process.env.WEBPACK_DEV_SERVER_ACTIVE) { | |
+ // In development, we need to specify a full URL so that the webpack dev | |
+ // server works correctly. | |
+ const appHost = process.env.APP_HOST || 'localhost'; | |
+ return 'http://' + appHost + ':8080'; | |
+ } | |
+ | |
+ // In other environments (e.g. production, test), we have precompiled assets | |
+ // that we can resolve from the same host as where the generated bundle is | |
+ // located. | |
+ return ''; | |
} | |
// Ensure the target directory exists. | |
@@ -76,7 +85,7 @@ module.exports = { | |
output: { | |
path: outputPath, | |
filename: '[name].js', | |
- publicPath: appOrigin() + '/assets' | |
+ publicPath: appOrigin() + '/assets/' | |
}, | |
resolve: { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment