-
Notifications
You must be signed in to change notification settings - Fork 2
/
009_tests..010_react
329 lines (328 loc) · 10.7 KB
/
009_tests..010_react
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
diff --git a/.babelrc b/.babelrc
index 002b4aa..4ffef06 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,3 +1,3 @@
{
- "presets": ["env"]
+ "presets": ["env", "react"]
}
diff --git a/.eslintrc b/.eslintrc
index ab176b2..b58a6f5 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,11 +1,15 @@
{
+ "parser": "babel-eslint",
"env": {
"browser": true,
"commonjs": true,
"es6": true,
- "node": true,
+ "node": true
},
- "extends": "eslint:recommended",
+ "extends": [
+ "eslint:recommended",
+ "plugin:react/recommended"
+ ],
"parserOptions": {
"sourceType": "module"
},
@@ -17,5 +21,6 @@
"semi": ["error", "always"],
"no-unused-vars": ["error"],
"no-console": 0
- }
+ },
+ "plugins": ["react"]
}
\ No newline at end of file
diff --git a/index.html b/index.html
index 75ca0ea..5eab624 100644
--- a/index.html
+++ b/index.html
@@ -3,8 +3,6 @@
<head>
<meta charset="UTF-8">
<title>JavaScript Example</title>
- <!-- generated the css we want to use -->
- <script src="dist/common.js"></script>
<!-- link the generated css -->
<link href="dist/common.css" rel="stylesheet" title="Default Style"/>
</head>
@@ -12,6 +10,7 @@
<h1>Hello from HTML!</h1>
<div>Console.log here:</div>
<div id="log"></div>
+ <div id="react"></div>
<script>
// https://stackoverflow.com/questions/20256760/javascript-console-log-to-html
(function () {
@@ -25,6 +24,9 @@
}
})();
</script>
+ <!-- generated the css we want to use AND mount React -->
+ <script src="dist/vendor.js"></script>
+ <script src="dist/common.js"></script>
<script src="dist/index.js"></script>
</body>
-</html>
\ No newline at end of file
+</html>
diff --git a/package.json b/package.json
index 041617d..8d6eef2 100644
--- a/package.json
+++ b/package.json
@@ -29,15 +29,21 @@
},
"homepage": "https://github.com/scherler/Modern-JavaScript-Explained-For-Dinosaurs#readme",
"dependencies": {
- "moment": "2.19.1"
+ "moment": "2.19.1",
+ "react": "16.0.0",
+ "react-dom": "16.0.0"
},
"devDependencies": {
- "babel-core": "6.26.0",
+ "@babel/core": "^7.0.0-beta.4",
+ "babel-eslint": "8.0.1",
"babel-loader": "7.1.2",
"babel-preset-env": "1.6.1",
+ "babel-preset-react": "6.24.1",
"css-loader": "0.28.7",
"eslint": "4.10.0",
"eslint-loader": "1.9.0",
+ "eslint-plugin-react": "7.4.0",
+ "expose-loader": "0.7.3",
"extract-text-webpack-plugin": "3.0.2",
"jest": "21.2.1",
"jest-junit": "3.1.0",
diff --git a/part2.md b/part2.md
index 142c322..1cb203a 100644
--- a/part2.md
+++ b/part2.md
@@ -327,4 +327,150 @@ We simply declare a new npm script as follows.
```json
"test:watch": "jest --watch",
-```
\ No newline at end of file
+```
+
+## Integrate react ([react](https://facebook.github.io/react/))
+
+**Branch: [react](https://github.com/scherler/Modern-JavaScript-Explained-For-Dinosaurs/tree/010_react)**
+
+**[Diff](./diffs/009_tests..010_react)** `git diff 009_tests..010_react`
+
+### What is React?
+
+There exist different definition of what react is. React is often described as “the V in the MVC structure”.
+This also happens to be the least tangible explanation one could give a newcomer, as (V)iews are typically
+logic-less files that are driven by a controller. Further, frameworks like Angular, Backbone, Ember, and more
+already have sufficient view layers — which then begs the question, why do we need to replace the V in MVC with React?
+
+The answer is that React doesn’t necessarily want to replace our views — it wants to augment them by allowing you to create
+highly reusable UI components (tab bars, comment boxes, pop up modals, lists, sortable tables, etc).
+
+In other words, the big idea behind React is this: what if you could create your own HTML element that has customized
+functionality? For example, one could make a <CommentBox> element that would display a textarea, run validations on the
+text typed into the textarea, submits the form when the enter key is pressed, etc — all just by including one line of code:
+<CommentBox></CommentBox>. (For those of you coming from the Angular world, you can think of React Components as a close analogy to Directives).
+
+When I first got in touch with react I thought it would be like **XML**, since I have a strong background in XSL, XML et.al..
+...but I soon had to learn that they have **nothing in common**.
+
+### First render with react
+
+Let us now create a first integration which we will further enhance later on. Our first stab is to inject all dependencies
+in our components, the steps to do so are the following:
+
+- tell `babel` about the special syntax that react brings to the plate. In our `.babelrc` we need to add a new preset
+```json
+{
+ "presets": ["env", "react"]
+}
+```
+- tell `eslint` about the special syntax that react brings to the plate. In our `.eslintrc` we need to add a new parser,
+extend the rules for react and add the react pluggin
+```json
+{
+ "parser": "babel-eslint",
+ "env": {
+ "browser": true,
+ "commonjs": true,
+ "es6": true,
+ "node": true
+ },
+ "extends": [
+ "eslint:recommended",
+ "plugin:react/recommended"
+ ],
+ "parserOptions": {
+ "sourceType": "module"
+ },
+ "rules": {
+ "comma-dangle": ["error", "always-multiline"],
+ "indent": ["error", 2],
+ "linebreak-style": ["error", "unix"],
+ "quotes": ["error", "single"],
+ "semi": ["error", "always"],
+ "no-unused-vars": ["error"],
+ "no-console": 0
+ },
+ "plugins": ["react"]
+}
+```
+- install the following npm packages
+```npm
+npm i -S -E react react-dom
+npm i -D -E babel-eslint babel-preset-react eslint-plugin-react
+
+```
+- extend our `common.js`
+```javascript
+import '../less/index.less'; // tell webpack to request the transpiling of less to css
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+const root = document.getElementById('react');
+ReactDOM.render(<div>Hello React!</div>, root);
+```
+- as you can see we are trying to render React in element with the id `react`. That needs to be added to our index.html
+```html
+<div id="react"></div>
+```
+
+### Enhance bundle size and loading times
+
+Our current bundle size has grown quite a bit, even if we have really not much javascript developed.
+So common.js is around 115kB and index.js has grown to 252kB. That does not sound much at the moment but
+as more dependencies we are using the bigger the bundles for each page are growing.
+
+The solution is to tell webpack that we will use some common libaries like react and moment as external files
+so webpack will not bundle them into our different files. That has as well the benefit that this `vendor` bundle can be
+cached by the browser which makes loading each next page **much** faster in comparision on what we had before.
+
+First install the following npm package
+```npm
+npm i -D -E expose-loader
+
+```
+
+For that we need to change our `entry` section webpack.config.js to the following, which is using the `expose-loader` which adds
+modules to the global object:
+
+```json
+entry: {
+ "vendor": [
+ "expose-loader?React!react",
+ "expose-loader?ReactDOM!react-dom",
+ "expose-loader?moment!moment",
+ ],
+ index: './src/js/index.js',
+ common: './src/js/common.js',
+},
+```
+
+and add a new section `externals` to the same file which tell webpack
+that we do not want to bundle those libraries:
+
+```json
+externals: {
+ // Use external version of React
+ "react": "React",
+ "react-dom": "ReactDOM",
+ "moment": "moment"
+},
+```
+
+From here we can either use a `CDN` of those external libs or we can include the vendor bundle
+in our index.html:
+
+```html
+<script src="dist/vendor.js"></script>
+```
+
+That has the effect that our page bundles (index and common) had been
+reduced to around 800 bytes and the vendor bundle containing all our deps
+with 370 kB.
+
+By separating common modules from bundles, the resulting chunked
+file can be loaded once initially, and stored in cache for later use.
+This results in pagespeed optimizations as the browser can quickly serve the shared
+code from cache, rather than being forced to load a larger bundle whenever a new page is visited.
+
+Now that we have a nice performing integration of react let us create our first react app.
\ No newline at end of file
diff --git a/src/js/common.js b/src/js/common.js
index c72d0ac..10ad68e 100644
--- a/src/js/common.js
+++ b/src/js/common.js
@@ -1 +1,6 @@
-import '../less/index.less'; // tell webpack to request the transpiling of less to css
\ No newline at end of file
+import '../less/index.less'; // tell webpack to request the transpiling of less to css
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+const root = document.getElementById('react');
+ReactDOM.render(<div>Hello React!</div>, root);
diff --git a/src/js/index.js b/src/js/index.js
index 289517c..d924c11 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -1,6 +1,7 @@
// index.js
import moment from 'moment';
+
export const sum = (a, b) => a + b;
-console.log('Hello from JavaScript and weback server!');
+console.log('Hello from JavaScript and webpack server!');
console.log(`startOf("day").fromNow(): ${moment().startOf('day').fromNow()}`);
console.log(`1 + 1 is ${sum(1, 1)}`);
diff --git a/webpack.config.js b/webpack.config.js
index 3588378..86aaad2 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,4 +1,5 @@
// webpack.config.js
+const webpack = require('webpack');
const ExtractTextPlugin = require("extract-text-webpack-plugin"); // allows to extract the generated css out of the bundle
const extractLess = new ExtractTextPlugin("dist/[name].css");
module.exports = {
@@ -10,6 +11,11 @@ module.exports = {
}
},
entry: {
+ "vendor": [
+ "expose-loader?React!react",
+ "expose-loader?ReactDOM!react-dom",
+ "expose-loader?moment!moment",
+ ],
index: './src/js/index.js',
common: './src/js/common.js',
},
@@ -50,6 +56,19 @@ module.exports = {
},
],
},
+ externals: {
+ // Use external version of React
+ "react": "React",
+ "react-dom": "ReactDOM",
+ "moment": "moment"
+ },
// Use the plugin to specify the resulting filename (and add needed behavior to the compiler)
- plugins: [ extractLess ],
+ plugins: [
+ extractLess,
+ new webpack.optimize.CommonsChunkPlugin({
+ name: "vendor",
+ minChunks: Infinity,
+ async: true
+ })
+ ]
};
\ No newline at end of file