Skip to content
This repository was archived by the owner on Jun 3, 2019. It is now read-only.

Commit 405af6f

Browse files
diondirzaSteven Truesdell
authored andcommitted
Webpack 3 and other perks (#473)
* Update deps and fix security for font source * Add scope hoisting plugin * Update nvmrc to latest LTS version * remove unecessary config * optimize webpack config * fix config eslintrc following new structure * Move scope hoisting feature to prod build * upgrade lint staged
1 parent e081d75 commit 405af6f

File tree

8 files changed

+306
-285
lines changed

8 files changed

+306
-285
lines changed

.eslintrc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
"node": true,
88
"jest": true
99
},
10-
"ecmaFeatures": {
11-
"defaultParams": true
10+
"parserOptions": {
11+
"ecmaVersion": 6,
12+
"sourceType": "module",
13+
"ecmaFeatures": {
14+
"defaultParams": true
15+
}
1216
},
1317
"rules": {
1418
// A jsx extension is not required for files containing jsx

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v6.11.0
1+
v6.11.1

config/values.js

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ const values = {
7373
htmlPage: {
7474
titleTemplate: 'React, Universally - %s',
7575
defaultTitle: 'React, Universally',
76-
description: 'A starter kit giving you the minimum requirements for a production ready universal react application.',
76+
description:
77+
'A starter kit giving you the minimum requirements for a production ready universal react application.',
7778
},
7879

7980
// Content Security Policy (CSP)
@@ -112,24 +113,6 @@ const values = {
112113
// These extensions are tried when resolving src files for our bundles..
113114
bundleSrcTypes: ['js', 'jsx', 'json'],
114115

115-
// Additional asset types to be supported for our bundles.
116-
// i.e. you can import the following file types within your source and the
117-
// webpack bundling process will bundle them with your source and create
118-
// URLs for them that can be resolved at runtime.
119-
bundleAssetTypes: [
120-
'jpg',
121-
'jpeg',
122-
'png',
123-
'gif',
124-
'ico',
125-
'eot',
126-
'svg',
127-
'ttf',
128-
'woff',
129-
'woff2',
130-
'otf',
131-
],
132-
133116
// What should we name the json output file that webpack generates
134117
// containing details of all output files for a bundle?
135118
bundleAssetsFileName: 'assets.json',

internal/webpack/configFactory.js

Lines changed: 117 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,17 @@ export default function webpackConfigFactory(buildOptions) {
4545
const ifProdClient = ifElse(isProd && isClient);
4646

4747
console.log(
48-
`==> Creating ${isProd ? 'an optimised' : 'a development'} bundle configuration for the "${target}"`,
48+
`==> Creating ${isProd
49+
? 'an optimised'
50+
: 'a development'} bundle configuration for the "${target}"`,
4951
);
5052

51-
const bundleConfig = isServer || isClient
52-
? // This is either our "server" or "client" bundle.
53-
config(['bundles', target])
54-
: // Otherwise it must be an additional node bundle.
55-
config(['additionalNodeBundles', target]);
53+
const bundleConfig =
54+
isServer || isClient
55+
? // This is either our "server" or "client" bundle.
56+
config(['bundles', target])
57+
: // Otherwise it must be an additional node bundle.
58+
config(['additionalNodeBundles', target]);
5659

5760
if (!bundleConfig) {
5861
throw new Error('No bundle configuration exists for target:', target);
@@ -75,7 +78,9 @@ export default function webpackConfigFactory(buildOptions) {
7578
// Required to support hot reloading of our client.
7679
ifDevClient(
7780
() =>
78-
`webpack-hot-middleware/client?reload=true&path=http://${config('host')}:${config('clientDevServerPort')}/__webpack_hmr`,
81+
`webpack-hot-middleware/client?reload=true&path=http://${config('host')}:${config(
82+
'clientDevServerPort',
83+
)}/__webpack_hmr`,
7984
),
8085
// The source entry file for the bundle.
8186
path.resolve(appRootDir.get(), bundleConfig.srcEntryFile),
@@ -109,7 +114,9 @@ export default function webpackConfigFactory(buildOptions) {
109114
publicPath: ifDev(
110115
// As we run a seperate development server for our client and server
111116
// bundles we need to use an absolute http path for the public path.
112-
`http://${config('host')}:${config('clientDevServerPort')}${config('bundles.client.webPath')}`,
117+
`http://${config('host')}:${config('clientDevServerPort')}${config(
118+
'bundles.client.webPath',
119+
)}`,
113120
// Otherwise we expect our bundled client to be served from this path.
114121
bundleConfig.webPath,
115122
),
@@ -212,6 +219,11 @@ export default function webpackConfigFactory(buildOptions) {
212219
}),
213220
),
214221

222+
// Implement webpack 3 scope hoisting that will remove function wrappers
223+
// around your modules you may see some small size improvements. However,
224+
// the significant improvement will be how fast the JavaScript loads in the browser.
225+
ifProdClient(new webpack.optimize.ModuleConcatenationPlugin()),
226+
215227
// We use this so that our generated [chunkhash]'s are only different if
216228
// the content for our respective chunks have changed. This optimises
217229
// our long term browser caching strategy for our client bundle, avoiding
@@ -420,95 +432,109 @@ export default function webpackConfigFactory(buildOptions) {
420432
// -----------------------------------------------------------------------
421433
]),
422434
module: {
423-
rules: removeNil([
424-
// JAVASCRIPT
435+
// Use strict export presence so that a missing export becomes a compile error.
436+
strictExportPresence: true,
437+
rules: [
425438
{
426-
test: /\.jsx?$/,
427-
// We will defer all our js processing to the happypack plugin
428-
// named "happypack-javascript".
429-
// See the respective plugin within the plugins section for full
430-
// details on what loader is being implemented.
431-
loader: 'happypack/loader?id=happypack-javascript',
432-
include: removeNil([
433-
...bundleConfig.srcPaths.map(srcPath => path.resolve(appRootDir.get(), srcPath)),
434-
ifProdClient(path.resolve(appRootDir.get(), 'src/html')),
435-
]),
436-
},
437-
438-
// CSS
439-
// This is bound to our server/client bundles as we only expect to be
440-
// serving the client bundle as a Single Page Application through the
441-
// server.
442-
ifElse(isClient || isServer)(
443-
mergeDeep(
439+
// "oneOf" will traverse all imports with following loaders until one will
440+
// match the requirements. When no loader matches it will fallback to the
441+
// "file" loader at the end of the loader list.
442+
oneOf: removeNil([
443+
// JAVASCRIPT
444444
{
445-
test: /\.css$/,
445+
test: /\.jsx?$/,
446+
// We will defer all our js processing to the happypack plugin
447+
// named "happypack-javascript".
448+
// See the respective plugin within the plugins section for full
449+
// details on what loader is being implemented.
450+
loader: 'happypack/loader?id=happypack-javascript',
451+
include: removeNil([
452+
...bundleConfig.srcPaths.map(srcPath => path.resolve(appRootDir.get(), srcPath)),
453+
ifProdClient(path.resolve(appRootDir.get(), 'src/html')),
454+
]),
446455
},
447-
// For development clients we will defer all our css processing to the
448-
// happypack plugin named "happypack-devclient-css".
449-
// See the respective plugin within the plugins section for full
450-
// details on what loader is being implemented.
451-
ifDevClient({
452-
loaders: ['happypack/loader?id=happypack-devclient-css'],
456+
457+
// CSS
458+
// This is bound to our server/client bundles as we only expect to be
459+
// serving the client bundle as a Single Page Application through the
460+
// server.
461+
ifElse(isClient || isServer)(
462+
mergeDeep(
463+
{
464+
test: /\.css$/,
465+
},
466+
// For development clients we will defer all our css processing to the
467+
// happypack plugin named "happypack-devclient-css".
468+
// See the respective plugin within the plugins section for full
469+
// details on what loader is being implemented.
470+
ifDevClient({
471+
loaders: ['happypack/loader?id=happypack-devclient-css'],
472+
}),
473+
// For a production client build we use the ExtractTextPlugin which
474+
// will extract our CSS into CSS files. We don't use happypack here
475+
// as there are some edge cases where it fails when used within
476+
// an ExtractTextPlugin instance.
477+
// Note: The ExtractTextPlugin needs to be registered within the
478+
// plugins section too.
479+
ifProdClient(() => ({
480+
loader: ExtractTextPlugin.extract({
481+
fallback: 'style-loader',
482+
use: ['css-loader'],
483+
}),
484+
})),
485+
// When targetting the server we use the "/locals" version of the
486+
// css loader, as we don't need any css files for the server.
487+
ifNode({
488+
loaders: ['css-loader/locals'],
489+
}),
490+
),
491+
),
492+
493+
// MODERNIZR
494+
// This allows you to do feature detection.
495+
// @see https://modernizr.com/docs
496+
// @see https://github.com/peerigon/modernizr-loader
497+
ifClient({
498+
test: /\.modernizrrc.js$/,
499+
loader: 'modernizr-loader',
453500
}),
454-
// For a production client build we use the ExtractTextPlugin which
455-
// will extract our CSS into CSS files. We don't use happypack here
456-
// as there are some edge cases where it fails when used within
457-
// an ExtractTextPlugin instance.
458-
// Note: The ExtractTextPlugin needs to be registered within the
459-
// plugins section too.
460-
ifProdClient(() => ({
461-
loader: ExtractTextPlugin.extract({
462-
fallback: 'style-loader',
463-
use: ['css-loader'],
464-
}),
465-
})),
466-
// When targetting the server we use the "/locals" version of the
467-
// css loader, as we don't need any css files for the server.
468-
ifNode({
469-
loaders: ['css-loader/locals'],
501+
ifClient({
502+
test: /\.modernizrrc(\.json)?$/,
503+
loader: 'modernizr-loader!json-loader',
470504
}),
471-
),
472-
),
473505

474-
// ASSETS (Images/Fonts/etc)
475-
// This is bound to our server/client bundles as we only expect to be
476-
// serving the client bundle as a Single Page Application through the
477-
// server.
478-
ifElse(isClient || isServer)(() => ({
479-
test: new RegExp(`\\.(${config('bundleAssetTypes').join('|')})$`, 'i'),
480-
loader: 'file-loader',
481-
query: {
482-
// What is the web path that the client bundle will be served from?
483-
// The same value has to be used for both the client and the
484-
// server bundles in order to ensure that SSR paths match the
485-
// paths used on the client.
486-
publicPath: isDev
487-
? // When running in dev mode the client bundle runs on a
488-
// seperate port so we need to put an absolute path here.
489-
`http://${config('host')}:${config('clientDevServerPort')}${config('bundles.client.webPath')}`
490-
: // Otherwise we just use the configured web path for the client.
491-
config('bundles.client.webPath'),
492-
// We only emit files when building a web bundle, for the server
493-
// bundle we only care about the file loader being able to create
494-
// the correct asset URLs.
495-
emitFile: isClient,
496-
},
497-
})),
498-
499-
// MODERNIZR
500-
// This allows you to do feature detection.
501-
// @see https://modernizr.com/docs
502-
// @see https://github.com/peerigon/modernizr-loader
503-
ifClient({
504-
test: /\.modernizrrc.js$/,
505-
loader: 'modernizr-loader',
506-
}),
507-
ifClient({
508-
test: /\.modernizrrc(\.json)?$/,
509-
loader: 'modernizr-loader!json-loader',
510-
}),
511-
]),
506+
// ASSETS (Images/Fonts/etc)
507+
// This is bound to our server/client bundles as we only expect to be
508+
// serving the client bundle as a Single Page Application through the
509+
// server.
510+
ifElse(isClient || isServer)(() => ({
511+
loader: 'file-loader',
512+
exclude: [/\.js$/, /\.html$/, /\.json$/],
513+
query: {
514+
// What is the web path that the client bundle will be served from?
515+
// The same value has to be used for both the client and the
516+
// server bundles in order to ensure that SSR paths match the
517+
// paths used on the client.
518+
publicPath: isDev
519+
? // When running in dev mode the client bundle runs on a
520+
// seperate port so we need to put an absolute path here.
521+
`http://${config('host')}:${config('clientDevServerPort')}${config(
522+
'bundles.client.webPath',
523+
)}`
524+
: // Otherwise we just use the configured web path for the client.
525+
config('bundles.client.webPath'),
526+
// We only emit files when building a web bundle, for the server
527+
// bundle we only care about the file loader being able to create
528+
// the correct asset URLs.
529+
emitFile: isClient,
530+
},
531+
})),
532+
533+
// Do not add any loader after file loader (fallback loader)
534+
// Make sure to add the new loader(s) before the "file" loader.
535+
]),
536+
},
537+
],
512538
},
513539
};
514540

package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,23 +60,23 @@
6060
"dependencies": {
6161
"app-root-dir": "1.0.2",
6262
"colors": "1.1.2",
63-
"compression": "1.6.2",
63+
"compression": "1.7.0",
6464
"cross-env": "5.0.1",
6565
"dotenv": "4.0.0",
6666
"express": "4.15.3",
6767
"helmet": "3.6.1",
6868
"hpp": "0.2.2",
6969
"modernizr": "3.5.0",
70-
"normalize.css": "6.0.0",
71-
"offline-plugin": "4.8.1",
70+
"normalize.css": "7.0.0",
71+
"offline-plugin": "4.8.3",
7272
"prop-types": "15.5.10",
7373
"react": "15.6.1",
7474
"react-async-bootstrapper": "1.1.1",
7575
"react-async-component": "1.0.0-beta.3",
7676
"react-dom": "15.6.1",
7777
"react-helmet": "5.1.3",
78-
"react-router-dom": "4.1.1",
79-
"serialize-javascript": "1.3.0",
78+
"react-router-dom": "4.1.2",
79+
"serialize-javascript": "1.4.0",
8080
"uuid": "3.1.0"
8181
},
8282
"devDependencies": {
@@ -101,21 +101,21 @@
101101
"enzyme-to-json": "1.5.1",
102102
"eslint": "3.19.0",
103103
"eslint-config-airbnb": "15.0.2",
104-
"eslint-plugin-import": "2.6.1",
104+
"eslint-plugin-import": "2.7.0",
105105
"eslint-plugin-jsx-a11y": "5.1.1",
106106
"eslint-plugin-react": "7.1.0",
107-
"extract-text-webpack-plugin": "2.1.2",
107+
"extract-text-webpack-plugin": "3.0.0",
108108
"file-loader": "0.11.2",
109109
"glob": "7.1.2",
110110
"happypack": "3.0.3",
111111
"html-webpack-plugin": "2.29.0",
112112
"husky": "0.14.3",
113113
"jest": "20.0.4",
114-
"lint-staged": "4.0.1",
114+
"lint-staged": "4.0.2",
115115
"md5": "2.2.1",
116116
"modernizr-loader": "1.0.1",
117117
"node-notifier": "5.1.2",
118-
"prettier": "1.5.2",
118+
"prettier": "1.5.3",
119119
"prettier-eslint": "6.4.2",
120120
"prettier-eslint-cli": "4.1.1",
121121
"react-addons-test-utils": "15.6.0",
@@ -125,11 +125,11 @@
125125
"rimraf": "2.6.1",
126126
"semver": "5.3.0",
127127
"source-map-support": "0.4.15",
128-
"style-loader": "0.16.1",
129-
"webpack": "2.6.1",
130-
"webpack-bundle-analyzer": "2.8.2",
128+
"style-loader": "0.18.2",
129+
"webpack": "3.3.0",
130+
"webpack-bundle-analyzer": "2.8.3",
131131
"webpack-dev-middleware": "1.11.0",
132-
"webpack-hot-middleware": "2.18.1",
132+
"webpack-hot-middleware": "2.18.2",
133133
"webpack-md5-hash": "0.0.5",
134134
"webpack-node-externals": "1.6.0"
135135
}

server/middleware/security.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const cspConfig = {
1717
// need the following:
1818
// 'data:',
1919
],
20-
fontSrc: ["'self'"],
20+
fontSrc: ["'self'", 'data:'],
2121
objectSrc: ["'self'"],
2222
mediaSrc: ["'self'"],
2323
manifestSrc: ["'self'"],

0 commit comments

Comments
 (0)