├── .eslintrc
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── examples
├── 01 - Basic
│ ├── .eslintrc
│ ├── README.md
│ ├── components
│ │ └── MyComponent.js
│ ├── index.html
│ ├── index.js
│ ├── package.json
│ └── scripts
│ │ └── run
├── 02 - Side effects
│ ├── .eslintrc
│ ├── README.md
│ ├── components
│ │ ├── Dep.js
│ │ ├── MyComponent.js
│ │ ├── MyComponent2.js
│ │ └── theme.js
│ ├── index.html
│ ├── index.js
│ ├── package.json
│ └── scripts
│ │ └── run
└── 03 - Basic auth
│ ├── README.md
│ ├── components
│ ├── About.js
│ ├── App.js
│ ├── Dashboard.js
│ ├── Login.js
│ └── Logout.js
│ ├── index.html
│ ├── index.js
│ ├── package.json
│ ├── scripts
│ └── run
│ └── vendor
│ ├── auth.js
│ └── requireAuth.js
├── index.js
├── package.json
└── src
├── Proxies.js
├── StaticModules.js
├── actions
├── applyPatch.js
├── bytesToKb.js
├── processError.js
└── storeSources.js
├── injectWebSocket.js
├── overrideRequire.js
└── transform.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "env": {
4 | "browser": true,
5 | "node": true,
6 | "jasmine": true
7 | },
8 | "ecmaFeatures": {
9 | "arrowFunctions": true,
10 | "blockBindings": true,
11 | "classes": true,
12 | "defaultParams": true,
13 | "destructuring": true,
14 | "forOf": true,
15 | "generators": false,
16 | "modules": true,
17 | "objectLiteralComputedProperties": true,
18 | "objectLiteralDuplicateProperties": false,
19 | "objectLiteralShorthandMethods": true,
20 | "objectLiteralShorthandProperties": true,
21 | "spread": true,
22 | "superInFunctions": true,
23 | "templateStrings": true,
24 | "jsx": true
25 | },
26 | "rules": {
27 | /**
28 | * Strict mode
29 | */
30 | // babel inserts "use strict"; for us
31 | // http://eslint.org/docs/rules/strict
32 | "strict": [2, "never"],
33 |
34 | /**
35 | * ES6
36 | */
37 | "no-var": 0, // http://eslint.org/docs/rules/no-var
38 |
39 | /**
40 | * Variables
41 | */
42 | "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow
43 | "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names
44 | "no-unused-vars": [0, { // http://eslint.org/docs/rules/no-unused-vars
45 | "vars": "local",
46 | "args": "after-used"
47 | }],
48 | "no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define
49 |
50 | /**
51 | * Possible errors
52 | */
53 | "comma-dangle": [2, "always"], // http://eslint.org/docs/rules/comma-dangle
54 | "no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign
55 | "no-console": 0, // http://eslint.org/docs/rules/no-console
56 | "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger
57 | "no-alert": 1, // http://eslint.org/docs/rules/no-alert
58 | "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition
59 | "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys
60 | "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case
61 | "no-empty": 2, // http://eslint.org/docs/rules/no-empty
62 | "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign
63 | "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast
64 | "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi
65 | "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign
66 | "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations
67 | "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp
68 | "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace
69 | "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls
70 | "no-reserved-keys": 0, // http://eslint.org/docs/rules/no-reserved-keys
71 | "no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays
72 | "no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable
73 | "use-isnan": 2, // http://eslint.org/docs/rules/use-isnan
74 | "block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var
75 |
76 | /**
77 | * Best practices
78 | */
79 | "consistent-return": 2, // http://eslint.org/docs/rules/consistent-return
80 | "curly": [2, "multi-line"], // http://eslint.org/docs/rules/curly
81 | "default-case": 2, // http://eslint.org/docs/rules/default-case
82 | "dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation
83 | "allowKeywords": true
84 | }],
85 | "eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq
86 | "guard-for-in": 2, // http://eslint.org/docs/rules/guard-for-in
87 | "no-caller": 2, // http://eslint.org/docs/rules/no-caller
88 | "no-else-return": 2, // http://eslint.org/docs/rules/no-else-return
89 | "no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null
90 | "no-eval": 2, // http://eslint.org/docs/rules/no-eval
91 | "no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native
92 | "no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind
93 | "no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough
94 | "no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal
95 | "no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval
96 | "no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks
97 | "no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func
98 | "no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str
99 | "no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign
100 | "no-new": 2, // http://eslint.org/docs/rules/no-new
101 | "no-new-func": 2, // http://eslint.org/docs/rules/no-new-func
102 | "no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers
103 | "no-octal": 2, // http://eslint.org/docs/rules/no-octal
104 | "no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape
105 | "no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign
106 | "no-proto": 2, // http://eslint.org/docs/rules/no-proto
107 | "no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare
108 | "no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign
109 | "no-script-url": 2, // http://eslint.org/docs/rules/no-script-url
110 | "no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare
111 | "no-sequences": 2, // http://eslint.org/docs/rules/no-sequences
112 | "no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal
113 | "no-with": 2, // http://eslint.org/docs/rules/no-with
114 | "radix": 2, // http://eslint.org/docs/rules/radix
115 | "vars-on-top": 0, // http://eslint.org/docs/rules/vars-on-top
116 | "wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife
117 | "yoda": 2, // http://eslint.org/docs/rules/yoda
118 |
119 | /**
120 | * Style
121 | */
122 | "indent": [2, 2], // http://eslint.org/docs/rules/
123 | "brace-style": [2, // http://eslint.org/docs/rules/brace-style
124 | "1tbs", {
125 | "allowSingleLine": true
126 | }],
127 | "quotes": [
128 | 2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes
129 | ],
130 | "camelcase": [2, { // http://eslint.org/docs/rules/camelcase
131 | "properties": "never"
132 | }],
133 | "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing
134 | "before": false,
135 | "after": true
136 | }],
137 | "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style
138 | "eol-last": 2, // http://eslint.org/docs/rules/eol-last
139 | "func-names": 1, // http://eslint.org/docs/rules/func-names
140 | "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing
141 | "beforeColon": false,
142 | "afterColon": true
143 | }],
144 | "new-cap": [2, { // http://eslint.org/docs/rules/new-cap
145 | "newIsCap": true
146 | }],
147 | "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines
148 | "max": 2
149 | }],
150 | "no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary
151 | "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object
152 | "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func
153 | "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces
154 | "no-wrap-func": 2, // http://eslint.org/docs/rules/no-wrap-func
155 | "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle
156 | "one-var": [2, "never"], // http://eslint.org/docs/rules/one-var
157 | "padded-blocks": 0, // http://eslint.org/docs/rules/padded-blocks
158 | "semi": [2, "always"], // http://eslint.org/docs/rules/semi
159 | "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing
160 | "before": false,
161 | "after": true
162 | }],
163 | "space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords
164 | "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks
165 | "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren
166 | "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops
167 | "space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case
168 | "spaced-line-comment": 2 // http://eslint.org/docs/rules/spaced-line-comment
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | examples
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Alexey
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Browserify React Live
2 | This is a [browserify](https://github.com/substack/node-browserify) transform which works similarly to [react-hot-loader](https://github.com/gaearon/react-hot-loader).
3 | Once you run you app in the browser, it monitors your JavaScript code and only updates the changed component, preserving the state of the application.
4 |
5 |
6 |
7 | ## Installing
8 | ```bash
9 | npm install browserify-react-live --save-dev
10 | ```
11 |
12 | ## Quick example
13 | ```bash
14 | git clone https://github.com/Kureev/browserify-react-live.git
15 | cd browserify-react-live/examples/01\ -\ Basic
16 | npm i && npm start
17 | ```
18 |
19 | Run [http://localhost:8080](http://localhost:8080) and try updating the component.
20 |
21 | ## Running
22 |
23 | Add transform to `package.json`:
24 | ```json
25 | "browserify": {
26 | "transform": [
27 | "browserify-react-live"
28 | ]
29 | }
30 | ```
31 | or run watchify with transform from the CLI:
32 | ```bash
33 | watchify -t browserify-react-live components/file.js -o bundles/file.js
34 | ```
35 |
36 | Start `browserify-patch-server`:
37 | ```bash
38 | node_modules/.bin/browserify-patch-server components/*
39 | ```
40 |
41 |
42 | ## Configuration
43 | ### Port number
44 |
45 | - Server
46 | ```bash
47 | node_modules/.bin/browserify-patch-server components/* -p 8888 # Default is 8081
48 | ```
49 |
50 | - Transform
51 | ```bash
52 | watchify -t [ browserify-react-live -p 8888 ] components/file.js -o bundles/file.js # Default is 8080
53 | ```
54 |
55 | ## How it works
56 | `browserify-react-live` works with `browserify-patch-server`:
57 | - `browserify-patch-server`
58 | This part is responsible for watching changes for specified path and compute/broadcast patch. Every time watched files changes, it automatically calculate patch and send it via websocket to client.
59 | - `browserify-react-live` transform. Patch browserify's `require` function to inject Dan Abramov's `react-hot-api` and websocket client which will wait for server broadcast and apply received patch.
60 |
61 |
62 |
63 | ## Migration 1.x -> 2.x
64 | - Now you need to watch files instead of bundle. E.g. `components/*` instead of `dist/bundle.js`
65 |
66 | ## Compatibility
67 | - `node` > 0.10 or `io.js` > 2.0
68 |
69 | ## License
70 | MIT
71 |
--------------------------------------------------------------------------------
/examples/01 - Basic/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "env": {
4 | "browser": true,
5 | "node": true,
6 | "jasmine": true
7 | },
8 | "ecmaFeatures": {
9 | "arrowFunctions": true,
10 | "blockBindings": true,
11 | "classes": true,
12 | "defaultParams": true,
13 | "destructuring": true,
14 | "forOf": true,
15 | "generators": false,
16 | "modules": true,
17 | "objectLiteralComputedProperties": true,
18 | "objectLiteralDuplicateProperties": false,
19 | "objectLiteralShorthandMethods": true,
20 | "objectLiteralShorthandProperties": true,
21 | "spread": true,
22 | "superInFunctions": true,
23 | "templateStrings": true,
24 | "jsx": true
25 | },
26 | "rules": {
27 | /**
28 | * Strict mode
29 | */
30 | // babel inserts "use strict"; for us
31 | // http://eslint.org/docs/rules/strict
32 | "strict": [2, "never"],
33 |
34 | /**
35 | * ES6
36 | */
37 | "no-var": 0, // http://eslint.org/docs/rules/no-var
38 |
39 | /**
40 | * Variables
41 | */
42 | "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow
43 | "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names
44 | "no-unused-vars": [0, { // http://eslint.org/docs/rules/no-unused-vars
45 | "vars": "local",
46 | "args": "after-used"
47 | }],
48 | "no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define
49 |
50 | /**
51 | * Possible errors
52 | */
53 | "comma-dangle": [2, "always"], // http://eslint.org/docs/rules/comma-dangle
54 | "no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign
55 | "no-console": 0, // http://eslint.org/docs/rules/no-console
56 | "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger
57 | "no-alert": 1, // http://eslint.org/docs/rules/no-alert
58 | "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition
59 | "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys
60 | "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case
61 | "no-empty": 2, // http://eslint.org/docs/rules/no-empty
62 | "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign
63 | "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast
64 | "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi
65 | "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign
66 | "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations
67 | "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp
68 | "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace
69 | "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls
70 | "no-reserved-keys": 0, // http://eslint.org/docs/rules/no-reserved-keys
71 | "no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays
72 | "no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable
73 | "use-isnan": 2, // http://eslint.org/docs/rules/use-isnan
74 | "block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var
75 |
76 | /**
77 | * Best practices
78 | */
79 | "consistent-return": 2, // http://eslint.org/docs/rules/consistent-return
80 | "curly": [2, "multi-line"], // http://eslint.org/docs/rules/curly
81 | "default-case": 2, // http://eslint.org/docs/rules/default-case
82 | "dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation
83 | "allowKeywords": true
84 | }],
85 | "eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq
86 | "guard-for-in": 2, // http://eslint.org/docs/rules/guard-for-in
87 | "no-caller": 2, // http://eslint.org/docs/rules/no-caller
88 | "no-else-return": 2, // http://eslint.org/docs/rules/no-else-return
89 | "no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null
90 | "no-eval": 2, // http://eslint.org/docs/rules/no-eval
91 | "no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native
92 | "no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind
93 | "no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough
94 | "no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal
95 | "no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval
96 | "no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks
97 | "no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func
98 | "no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str
99 | "no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign
100 | "no-new": 2, // http://eslint.org/docs/rules/no-new
101 | "no-new-func": 2, // http://eslint.org/docs/rules/no-new-func
102 | "no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers
103 | "no-octal": 2, // http://eslint.org/docs/rules/no-octal
104 | "no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape
105 | "no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign
106 | "no-proto": 2, // http://eslint.org/docs/rules/no-proto
107 | "no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare
108 | "no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign
109 | "no-script-url": 2, // http://eslint.org/docs/rules/no-script-url
110 | "no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare
111 | "no-sequences": 2, // http://eslint.org/docs/rules/no-sequences
112 | "no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal
113 | "no-with": 2, // http://eslint.org/docs/rules/no-with
114 | "radix": 2, // http://eslint.org/docs/rules/radix
115 | "vars-on-top": 2, // http://eslint.org/docs/rules/vars-on-top
116 | "wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife
117 | "yoda": 2, // http://eslint.org/docs/rules/yoda
118 |
119 | /**
120 | * Style
121 | */
122 | "indent": [2, 2], // http://eslint.org/docs/rules/
123 | "brace-style": [2, // http://eslint.org/docs/rules/brace-style
124 | "1tbs", {
125 | "allowSingleLine": true
126 | }],
127 | "quotes": [
128 | 2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes
129 | ],
130 | "camelcase": [2, { // http://eslint.org/docs/rules/camelcase
131 | "properties": "never"
132 | }],
133 | "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing
134 | "before": false,
135 | "after": true
136 | }],
137 | "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style
138 | "eol-last": 2, // http://eslint.org/docs/rules/eol-last
139 | "func-names": 1, // http://eslint.org/docs/rules/func-names
140 | "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing
141 | "beforeColon": false,
142 | "afterColon": true
143 | }],
144 | "new-cap": [2, { // http://eslint.org/docs/rules/new-cap
145 | "newIsCap": true
146 | }],
147 | "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines
148 | "max": 2
149 | }],
150 | "no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary
151 | "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object
152 | "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func
153 | "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces
154 | "no-wrap-func": 2, // http://eslint.org/docs/rules/no-wrap-func
155 | "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle
156 | "one-var": [2, "never"], // http://eslint.org/docs/rules/one-var
157 | "padded-blocks": 0, // http://eslint.org/docs/rules/padded-blocks
158 | "semi": [2, "always"], // http://eslint.org/docs/rules/semi
159 | "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing
160 | "before": false,
161 | "after": true
162 | }],
163 | "space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords
164 | "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks
165 | "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren
166 | "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops
167 | "space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case
168 | "spaced-line-comment": 2 // http://eslint.org/docs/rules/spaced-line-comment
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/examples/01 - Basic/README.md:
--------------------------------------------------------------------------------
1 | ## Example 01 - Basic
2 |
3 | #### About
4 | Demonstrates the most basic flow with `browserify-react-live`
5 |
6 | #### Getting started
7 | ```
8 | npm install
9 | npm start
10 | ```
11 |
12 | By default your server is ready at [http://localhost:8080](http://localhost:8080).
13 |
14 | You can now change anything, in, say `components` folder and your changes will propagate!
15 |
16 | See [browserify-react-live](https://github.com/Kureev/browserify-react-live) for more details.
17 |
--------------------------------------------------------------------------------
/examples/01 - Basic/components/MyComponent.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const styles = {
4 | button: {
5 | padding: 10,
6 | display: 'block',
7 | },
8 | };
9 |
10 | module.exports = class MyComponent extends React.Component {
11 | state = {
12 | counter: 0,
13 | }
14 |
15 | onClick() {
16 | this.setState({ counter: this.state.counter + 1, });
17 | }
18 |
19 | render() {
20 | return (
21 |
22 | Hello, world (said {this.state.counter} times)
23 |
26 |
27 | );
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/examples/01 - Basic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Test for hot module replacement
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/01 - Basic/index.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var MyComponent = require('./components/MyComponent');
3 |
4 | React.render((
5 |
6 |
7 |
8 | ), document.getElementById('playground'));
9 |
--------------------------------------------------------------------------------
/examples/01 - Basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./scripts/run",
8 | "postinstall": "mkdir -p dist && ./node_modules/.bin/browserify index.js -o dist/bundle.js",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "author": "Alexey Kureev (https://github.com/Kureev)",
12 | "license": "MIT",
13 | "browserify": {
14 | "transform": [
15 | [
16 | "babelify",
17 | {
18 | "stage": 0
19 | }
20 | ],
21 | "browserify-react-live"
22 | ]
23 | },
24 | "devDependencies": {
25 | "babelify": "^6.1.3",
26 | "browserify": "^11.0.0",
27 | "browserify-patch-server": "^0.4",
28 | "browserify-react-live": "^2",
29 | "http-server": "^0.8.0",
30 | "watchify": "^3.3.0"
31 | },
32 | "dependencies": {
33 | "react": "^0.13.3"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/examples/01 - Basic/scripts/run:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | node_modules/.bin/watchify index.js -o dist/bundle.js &
3 | node_modules/.bin/bfps components/* &
4 | node_modules/.bin/http-server . &
5 | wait
6 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "env": {
4 | "browser": true,
5 | "node": true,
6 | "jasmine": true
7 | },
8 | "ecmaFeatures": {
9 | "arrowFunctions": true,
10 | "blockBindings": true,
11 | "classes": true,
12 | "defaultParams": true,
13 | "destructuring": true,
14 | "forOf": true,
15 | "generators": false,
16 | "modules": true,
17 | "objectLiteralComputedProperties": true,
18 | "objectLiteralDuplicateProperties": false,
19 | "objectLiteralShorthandMethods": true,
20 | "objectLiteralShorthandProperties": true,
21 | "spread": true,
22 | "superInFunctions": true,
23 | "templateStrings": true,
24 | "jsx": true
25 | },
26 | "rules": {
27 | /**
28 | * Strict mode
29 | */
30 | // babel inserts "use strict"; for us
31 | // http://eslint.org/docs/rules/strict
32 | "strict": [2, "never"],
33 |
34 | /**
35 | * ES6
36 | */
37 | "no-var": 0, // http://eslint.org/docs/rules/no-var
38 |
39 | /**
40 | * Variables
41 | */
42 | "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow
43 | "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names
44 | "no-unused-vars": [0, { // http://eslint.org/docs/rules/no-unused-vars
45 | "vars": "local",
46 | "args": "after-used"
47 | }],
48 | "no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define
49 |
50 | /**
51 | * Possible errors
52 | */
53 | "comma-dangle": [2, "always"], // http://eslint.org/docs/rules/comma-dangle
54 | "no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign
55 | "no-console": 0, // http://eslint.org/docs/rules/no-console
56 | "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger
57 | "no-alert": 1, // http://eslint.org/docs/rules/no-alert
58 | "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition
59 | "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys
60 | "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case
61 | "no-empty": 2, // http://eslint.org/docs/rules/no-empty
62 | "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign
63 | "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast
64 | "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi
65 | "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign
66 | "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations
67 | "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp
68 | "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace
69 | "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls
70 | "no-reserved-keys": 0, // http://eslint.org/docs/rules/no-reserved-keys
71 | "no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays
72 | "no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable
73 | "use-isnan": 2, // http://eslint.org/docs/rules/use-isnan
74 | "block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var
75 |
76 | /**
77 | * Best practices
78 | */
79 | "consistent-return": 2, // http://eslint.org/docs/rules/consistent-return
80 | "curly": [2, "multi-line"], // http://eslint.org/docs/rules/curly
81 | "default-case": 2, // http://eslint.org/docs/rules/default-case
82 | "dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation
83 | "allowKeywords": true
84 | }],
85 | "eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq
86 | "guard-for-in": 2, // http://eslint.org/docs/rules/guard-for-in
87 | "no-caller": 2, // http://eslint.org/docs/rules/no-caller
88 | "no-else-return": 2, // http://eslint.org/docs/rules/no-else-return
89 | "no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null
90 | "no-eval": 2, // http://eslint.org/docs/rules/no-eval
91 | "no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native
92 | "no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind
93 | "no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough
94 | "no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal
95 | "no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval
96 | "no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks
97 | "no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func
98 | "no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str
99 | "no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign
100 | "no-new": 2, // http://eslint.org/docs/rules/no-new
101 | "no-new-func": 2, // http://eslint.org/docs/rules/no-new-func
102 | "no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers
103 | "no-octal": 2, // http://eslint.org/docs/rules/no-octal
104 | "no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape
105 | "no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign
106 | "no-proto": 2, // http://eslint.org/docs/rules/no-proto
107 | "no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare
108 | "no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign
109 | "no-script-url": 2, // http://eslint.org/docs/rules/no-script-url
110 | "no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare
111 | "no-sequences": 2, // http://eslint.org/docs/rules/no-sequences
112 | "no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal
113 | "no-with": 2, // http://eslint.org/docs/rules/no-with
114 | "radix": 2, // http://eslint.org/docs/rules/radix
115 | "vars-on-top": 2, // http://eslint.org/docs/rules/vars-on-top
116 | "wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife
117 | "yoda": 2, // http://eslint.org/docs/rules/yoda
118 |
119 | /**
120 | * Style
121 | */
122 | "indent": [2, 2], // http://eslint.org/docs/rules/
123 | "brace-style": [2, // http://eslint.org/docs/rules/brace-style
124 | "1tbs", {
125 | "allowSingleLine": true
126 | }],
127 | "quotes": [
128 | 2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes
129 | ],
130 | "camelcase": [2, { // http://eslint.org/docs/rules/camelcase
131 | "properties": "never"
132 | }],
133 | "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing
134 | "before": false,
135 | "after": true
136 | }],
137 | "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style
138 | "eol-last": 2, // http://eslint.org/docs/rules/eol-last
139 | "func-names": 1, // http://eslint.org/docs/rules/func-names
140 | "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing
141 | "beforeColon": false,
142 | "afterColon": true
143 | }],
144 | "new-cap": [2, { // http://eslint.org/docs/rules/new-cap
145 | "newIsCap": true
146 | }],
147 | "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines
148 | "max": 2
149 | }],
150 | "no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary
151 | "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object
152 | "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func
153 | "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces
154 | "no-wrap-func": 2, // http://eslint.org/docs/rules/no-wrap-func
155 | "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle
156 | "one-var": [2, "never"], // http://eslint.org/docs/rules/one-var
157 | "padded-blocks": 0, // http://eslint.org/docs/rules/padded-blocks
158 | "semi": [2, "always"], // http://eslint.org/docs/rules/semi
159 | "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing
160 | "before": false,
161 | "after": true
162 | }],
163 | "space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords
164 | "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks
165 | "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren
166 | "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops
167 | "space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case
168 | "spaced-line-comment": 2 // http://eslint.org/docs/rules/spaced-line-comment
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/README.md:
--------------------------------------------------------------------------------
1 | ## Example 02 - Side effects
2 |
3 | #### About
4 | Demonstrates partial bundle update with `browserify-react-live`. Especially handy when some parts of your bundle has side-effects you don't want to occur.
5 |
6 | #### Getting started
7 | ```
8 | npm install
9 | npm start
10 | ```
11 |
12 | By default your server is ready at [http://localhost:8080](http://localhost:8080).
13 |
14 | You can now change anything, in, say `components` folder and your changes will propagate!
15 |
16 | See [browserify-react-live](https://github.com/Kureev/browserify-react-live) for more details.
17 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/components/Dep.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | export default class Test extends Component {
4 | render() {
5 | return (
6 | Hi, I'm MyComponent2 dependency
7 | );
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/components/MyComponent.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const theme = require('./theme');
3 |
4 | alert('Hi, I\'m a side effect of MyComponent');
5 |
6 | module.exports = class MyComponent extends React.Component {
7 | state = {
8 | counter: 0,
9 | }
10 |
11 | onClick() {
12 | this.setState({ counter: this.state.counter + 1, });
13 | }
14 |
15 | render() {
16 | return (
17 |
18 | Hello, world (said {this.state.counter} times)
19 |
22 |
23 | );
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/components/MyComponent2.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const TestDependency = require('./Dep');
3 | const theme = require('./theme');
4 |
5 | module.exports = class MyComponent2 extends React.Component {
6 | state = {
7 | counter: 100,
8 | }
9 |
10 | onClick() {
11 | this.setState({ counter: this.state.counter - 1, });
12 | }
13 |
14 | render() {
15 | return (
16 |
17 | Counter is {this.state.counter}
18 |
21 |
22 |
23 | );
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/components/theme.js:
--------------------------------------------------------------------------------
1 | export default {
2 | button: {
3 | padding: 10,
4 | display: 'block',
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Test for hot module replacement
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/index.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var MyComponent = require('./components/MyComponent');
3 | var MyComponent2 = require('./components/MyComponent2');
4 |
5 | React.render((
6 |
7 |
8 |
9 |
10 | ), document.getElementById('playground'));
11 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./scripts/run",
8 | "postinstall": "mkdir -p dist && ./node_modules/.bin/browserify index.js -o dist/bundle.js",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "author": "Alexey Kureev (https://github.com/Kureev)",
12 | "license": "MIT",
13 | "browserify": {
14 | "transform": [
15 | [
16 | "babelify",
17 | {
18 | "stage": 0
19 | }
20 | ],
21 | "browserify-react-live"
22 | ]
23 | },
24 | "devDependencies": {
25 | "babelify": "^6.1.3",
26 | "browserify": "^11.0.0",
27 | "browserify-patch-server": "^0.4",
28 | "browserify-react-live": "^2",
29 | "http-server": "^0.8.0",
30 | "watchify": "^3.3.0"
31 | },
32 | "dependencies": {
33 | "react": "^0.13.3"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/examples/02 - Side effects/scripts/run:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | node_modules/.bin/watchify index.js -o dist/bundle.js &
3 | node_modules/.bin/bfps components/* &
4 | node_modules/.bin/http-server . &
5 | wait
6 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/README.md:
--------------------------------------------------------------------------------
1 | ## Example 03 - Basic auth
2 |
3 | #### About
4 | Demonstrates usage `browserify-react-live` with `react-router` and basic auth scenario.
5 |
6 | #### Getting started
7 | ```
8 | npm install
9 | npm start
10 | ```
11 |
12 | By default your server is ready at [http://localhost:8080](http://localhost:8080).
13 |
14 | You can now change anything, in, say `components` folder and your changes will propagate!
15 |
16 | See [browserify-react-live](https://github.com/Kureev/browserify-react-live) for more details.
17 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/components/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class About extends React.Component {
4 | render() {
5 | return About
;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import auth from '../vendor/auth';
3 | import Router from 'react-router';
4 |
5 | var { RouteHandler, Link } = Router;
6 |
7 | export default class App extends React.Component {
8 | state = {
9 | loggedIn: auth.loggedIn(),
10 | }
11 |
12 | setStateOnAuth(loggedIn) {
13 | this.setState({
14 | loggedIn: loggedIn,
15 | });
16 | }
17 |
18 | componentWillMount() {
19 | auth.onChange = this.setStateOnAuth.bind(this);
20 | auth.login();
21 | }
22 |
23 | render() {
24 | return (
25 |
26 |
27 | -
28 | {this.state.loggedIn ? (
29 | Log out
30 | ) : (
31 | Sign in
32 | )}
33 |
34 | - About
35 | - Dashboard (authenticated)
36 |
37 |
38 |
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/components/Dashboard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import auth from '../vendor/auth';
3 |
4 | export default class Dashboard extends React.Component {
5 | render() {
6 | var token = auth.getToken();
7 | return (
8 |
9 |
Dashboard
10 |
You made it!
11 |
{token}
12 |
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/components/Login.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import auth from '../vendor/auth';
3 |
4 | export default class Login extends React.Component {
5 | constructor() {
6 | super();
7 | this.handleSubmit = this.handleSubmit.bind(this);
8 | this.state = {
9 | error: false,
10 | };
11 | }
12 |
13 | handleSubmit(event) {
14 | event.preventDefault();
15 | var { router } = this.context;
16 | var nextPath = router.getCurrentQuery().nextPath;
17 | var email = this.refs.email.getDOMNode().value;
18 | var pass = this.refs.pass.getDOMNode().value;
19 | auth.login(email, pass, (loggedIn) => {
20 | if (!loggedIn) {
21 | return this.setState({ error: true, });
22 | }
23 |
24 | if (nextPath) {
25 | router.replaceWith(nextPath);
26 | } else {
27 | router.replaceWith('/about');
28 | }
29 | });
30 | }
31 |
32 | render() {
33 | return (
34 |
42 | );
43 | }
44 |
45 | static contextTypes = {
46 | router: React.PropTypes.func,
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/components/Logout.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import auth from '../vendor/auth';
3 |
4 | export default class Logout extends React.Component {
5 | componentDidMount() {
6 | auth.logout();
7 | }
8 |
9 | render() {
10 | return You are now logged out
;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Test for hot module replacement
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/index.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Router = require('react-router');
3 | var auth = require('./vendor/auth');
4 | var Login = require('./components/Login');
5 | var Dashboard = require('./components/Dashboard');
6 | var Logout = require('./components/Logout');
7 | var About = require('./components/About');
8 | var App = require('./components/App');
9 | var requireAuth = require('./vendor/requireAuth');
10 | var { Route } = Router;
11 |
12 | var Dashboard = requireAuth(Dashboard);
13 |
14 | var routes = (
15 |
16 |
17 |
18 |
19 |
20 |
21 | );
22 |
23 | Router.run(routes, function(Handler) {
24 | React.render(, document.getElementById('playground'));
25 | });
26 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./scripts/run",
8 | "postinstall": "mkdir -p dist && ./node_modules/.bin/browserify index.js -o dist/bundle.js",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "author": "Alexey Kureev (https://github.com/Kureev)",
12 | "license": "MIT",
13 | "browserify": {
14 | "transform": [
15 | [
16 | "babelify",
17 | {
18 | "stage": 0
19 | }
20 | ],
21 | "browserify-react-live"
22 | ]
23 | },
24 | "devDependencies": {
25 | "babelify": "^6.1.3",
26 | "browserify": "^11.0.0",
27 | "browserify-patch-server": "^0.4",
28 | "browserify-react-live": "^2",
29 | "http-server": "^0.8.0",
30 | "watchify": "^3.3.0"
31 | },
32 | "dependencies": {
33 | "react": "^0.13.3",
34 | "react-router": "^0.13.3"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/scripts/run:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | node_modules/.bin/watchify index.js -o dist/bundle.js &
3 | node_modules/.bin/bfps components/* &
4 | node_modules/.bin/http-server . &
5 | wait
6 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/vendor/auth.js:
--------------------------------------------------------------------------------
1 | function pretendRequest(email, pass, cb) {
2 | setTimeout(() => {
3 | if (email === 'joe@example.com' && pass === 'password1') {
4 | cb({
5 | authenticated: true,
6 | token: Math.random().toString(36).substring(7)
7 | });
8 | } else {
9 | cb({authenticated: false});
10 | }
11 | }, 0);
12 | }
13 |
14 | export default {
15 | login (email, pass, cb) {
16 | cb = arguments[arguments.length - 1];
17 | if (localStorage.token) {
18 | if (cb) cb(true);
19 | this.onChange(true);
20 | return;
21 | }
22 | pretendRequest(email, pass, (res) => {
23 | if (res.authenticated) {
24 | localStorage.token = res.token;
25 | if (cb) cb(true);
26 | this.onChange(true);
27 | } else {
28 | if (cb) cb(false);
29 | this.onChange(false);
30 | }
31 | });
32 | },
33 |
34 | getToken: function () {
35 | return localStorage.token;
36 | },
37 |
38 | logout: function (cb) {
39 | delete localStorage.token;
40 | if (cb) cb();
41 | this.onChange(false);
42 | },
43 |
44 | loggedIn: function () {
45 | return !!localStorage.token;
46 | },
47 |
48 | onChange: function () {}
49 | };
50 |
--------------------------------------------------------------------------------
/examples/03 - Basic auth/vendor/requireAuth.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import auth from './auth';
3 |
4 | export default (Component) => {
5 | return class Authenticated extends React.Component {
6 | static willTransitionTo(transition) {
7 | if (!auth.loggedIn()) {
8 | transition.redirect('/login', {}, {
9 | 'nextPath': transition.path,
10 | });
11 | }
12 | }
13 | render() {
14 | return ;
15 | }
16 | };
17 | };
18 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./src/transform');
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "browserify-react-live",
3 | "version": "3.1.2",
4 | "description": "React live module reload for browserify",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "Alexey Kureev (https://github.com/Kureev)",
10 | "license": "MIT",
11 | "dependencies": {
12 | "diff": "^1.4.0",
13 | "logdown": "^1.2.4",
14 | "minimatch": "^2.0.10",
15 | "moment": "^2.10.3",
16 | "react-proxy": "^0.6",
17 | "strip-ansi": "^3.0.0",
18 | "through2": "^2.0.0",
19 | "ws": "^0.7.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Proxies.js:
--------------------------------------------------------------------------------
1 | var ReactProxy = require('react-proxy');
2 |
3 | function isWindows() {
4 | return navigator.platform.indexOf('Win') > -1;
5 | }
6 |
7 | function isObject(toTest) {
8 | return Object.prototype.toString.apply(toTest) === '[object Object]';
9 | }
10 |
11 | function isFunction(toTest) {
12 | return Object.prototype.toString.apply(toTest) === '[object Function]';
13 | }
14 |
15 | function isReactComponent(component) {
16 | return isFunction(component) &&
17 | isFunction(component.prototype.render);
18 | }
19 |
20 | function Proxies() {
21 | this.proxies = {};
22 | }
23 |
24 | Proxies.prototype = {
25 | get: function get(name) {
26 | // Preprocess name to shrink extension if supplied
27 | var proxyName = name.replace(/\.(js|jsx)$/, '');
28 | var proxy = this.proxies[proxyName];
29 |
30 | // If we don't have an exact match,
31 | // try to find by part of the name
32 | if (!proxy) {
33 | proxyName = Object.keys(this.proxies).filter(function iterateProxies(p) {
34 | if (isWindows()) {
35 | return proxyName.slice(-p.length) === p;
36 | }
37 |
38 | return p.slice(-proxyName.length) === proxyName;
39 | })[0];
40 |
41 | proxy = this.proxies[proxyName];
42 | }
43 |
44 | return proxy;
45 | },
46 |
47 | add: function add(name, component) {
48 | if (!name || !component) {
49 | return false;
50 | }
51 |
52 | var proxy;
53 |
54 | // If we already have a proxy with
55 | // this name, just return it
56 | if (proxy = this.get(name)) {
57 | return proxy;
58 | }
59 |
60 | // We can proxy only React Classes
61 | if (isReactComponent(component)) {
62 | proxy = ReactProxy.createProxy(component);
63 | this.proxies[name] = proxy;
64 |
65 | return proxy;
66 | }
67 |
68 | return false;
69 | },
70 |
71 | update: function update(name, newComponent) {
72 | var proxy = this.get(name);
73 | if (proxy) {
74 | return proxy.update(newComponent);
75 | }
76 |
77 | return false;
78 | },
79 | };
80 |
81 | module.exports = Proxies;
82 |
--------------------------------------------------------------------------------
/src/StaticModules.js:
--------------------------------------------------------------------------------
1 | function StaticModules() {
2 | this.modules = {};
3 | }
4 |
5 | function isWindows() {
6 | return navigator.platform.indexOf('Win') > -1;
7 | }
8 |
9 | StaticModules.prototype = {
10 | get: function get(name) {
11 | var moduleName = name
12 | .replace(/\.(js|jsx)$/, '')
13 | .replace(/^\//, '');
14 |
15 | var module = this.modules[moduleName];
16 |
17 | // If we don't have an exact match,
18 | // try to find by part of the name
19 | if (!module) {
20 | moduleName = Object.keys(this.modules).filter(function iterateModules(p) {
21 | if (isWindows()) {
22 | return moduleName.slice(-p.length) === p;
23 | }
24 |
25 | return p.slice(-moduleName.length) === moduleName;
26 | })[0];
27 |
28 | module = this.modules[moduleName];
29 | }
30 |
31 | return module;
32 | },
33 |
34 | add: function add(name, content) {
35 | if (!name || !content) {
36 | return false;
37 | }
38 |
39 | var moduleName = name
40 | .replace(/\.(js|jsx)$/, '')
41 | .replace(/^\//, '');
42 |
43 | this.modules[moduleName] = content;
44 | },
45 |
46 | update: function update(name, content) {
47 | var module = this.get(name);
48 |
49 | if (module) {
50 | this.add(name, content);
51 | } else {
52 | throw Error('Can\'t update ' + name + ' before it has been set');
53 | }
54 | }
55 | };
56 |
57 | module.exports = StaticModules;
58 |
--------------------------------------------------------------------------------
/src/actions/applyPatch.js:
--------------------------------------------------------------------------------
1 | var moment = require('moment');
2 | var React = require('react');
3 | var ReactProxy = require('react-proxy');
4 | var bytesToKb = require('./bytesToKb');
5 | var diff = require('diff');
6 |
7 | var forceUpdate = ReactProxy.getForceUpdate(React);
8 |
9 | /**
10 | * Parse patch file and log changes in a fancy way
11 | * @param {String} patch
12 | * @return {Void}
13 | */
14 | function logChanges(patch) {
15 | patch.split('\n').forEach(function iteratePatch(str) {
16 | if (str.match(/^\+\s/)) {
17 | console.log('%c' + str.replace(/^\+\s+/, '+ '), 'color: green');
18 | } else if (str.match(/^\-\s/)) {
19 | console.log('%c' + str.replace(/^-\s+/, '- '), 'color: red');
20 | }
21 | });
22 | }
23 |
24 | /**
25 | * Check if react hot replacement can
26 | * be applied to the module
27 | * @param {Object} module
28 | * @return {Boolean}
29 | */
30 | function canBePatched(module) {
31 | return module.exports &&
32 | (typeof module.exports === 'function') &&
33 | (module.exports.name || module.exports.displayName);
34 | }
35 |
36 | module.exports = function applyPatch(scope, source, data) {
37 | var timestamp = '['+ moment().format('HH:mm:ss') + ']';
38 |
39 | console.groupCollapsed(timestamp, 'Patch for',
40 | data.file, '(' + bytesToKb(data.patch.length) + 'kb)');
41 |
42 | logChanges(data.patch);
43 |
44 | var patched = diff.applyPatch(source, data.patch);
45 |
46 | // Build full file path for require
47 | // var filename = scope.__root + '/' + data.file;
48 | var filename = data.file;
49 |
50 | // Building require for specific filename
51 | // In our custom require we'll use filename to scope relative paths
52 | var __require = require('../overrideRequire')(scope, require, filename);
53 |
54 | // Create anon function for our patched source
55 | var f = Function(['require', 'module', 'exports', ], patched);
56 |
57 | // Mock module to get function result
58 | var _module = {};
59 |
60 | // Run module like as browserify does
61 | f(__require, _module, {});
62 |
63 | if (canBePatched(_module)) {
64 | var mountedInstances = scope.proxies.update(filename, _module.exports);
65 | if (!mountedInstances) {
66 | throw Error('Can\'t find ' + filename + ' in mounted instances');
67 | }
68 |
69 | mountedInstances.forEach(forceUpdate);
70 | } else {
71 | scope.modules.update(filename, _module.exports);
72 | }
73 |
74 | scope.files.forEach(function iterateBundles(file) {
75 | if (file.file === data.file) {
76 | file.content = patched;
77 | }
78 | });
79 |
80 | console.groupEnd();
81 | };
82 |
--------------------------------------------------------------------------------
/src/actions/bytesToKb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Convert bytes to kb + round it to xx.xx mask
3 | * @param {Number} bytes
4 | * @return {Number}
5 | */
6 | module.exports = function bytesToKb(bytes) {
7 | return Math.round((bytes / 1024) * 100) / 100;
8 | };
9 |
--------------------------------------------------------------------------------
/src/actions/processError.js:
--------------------------------------------------------------------------------
1 | var moment = require('moment');
2 | var Logdown = require('logdown');
3 |
4 | var error = new Logdown({ prefix: '[BPS:ERROR]', });
5 | var stripAnsi = require('strip-ansi');
6 |
7 | module.exports = function processError(data) {
8 | var timestamp = '['+ moment().format('HH:mm:ss') + ']';
9 | return error.error(timestamp, ' Error in file ' +
10 | data.file + ':\n' + stripAnsi(data.error));
11 | };
12 |
--------------------------------------------------------------------------------
/src/actions/storeSources.js:
--------------------------------------------------------------------------------
1 | var moment = require('moment');
2 | var Logdown = require('logdown');
3 | var bytesToKb = require('./bytesToKb');
4 |
5 | var system = new Logdown({ prefix: '[BPS:SYSTEM]', });
6 |
7 | module.exports = function storeSources(scope, sources) {
8 | var timestamp = '['+ moment().format('HH:mm:ss') + ']';
9 | scope.files = scope.files || sources;
10 |
11 | console.groupCollapsed(timestamp, 'Initialized react-live-patch');
12 |
13 | scope.files.forEach(function iterateSources(source) {
14 | system.log(timestamp + ' File *' + source.file + '*(' +
15 | bytesToKb(source.content.length) + 'Kb) has been added to react-live-patch');
16 | });
17 |
18 | console.groupEnd();
19 | };
20 |
--------------------------------------------------------------------------------
/src/injectWebSocket.js:
--------------------------------------------------------------------------------
1 | var processError = require('./actions/processError');
2 | var storeSources = require('./actions/storeSources');
3 | var applyPatch = require('./actions/applyPatch');
4 |
5 | module.exports = function injectWebSocket(scope, req, port) {
6 | scope.ws = new WebSocket('ws://localhost:' + (port || 8081));
7 | scope.ws.onmessage = function onMessage(res) {
8 | var data = JSON.parse(res.data);
9 |
10 | /**
11 | * Handle error reports from patch-server
12 | * @param {String} data.error
13 | */
14 | if (data.error) {
15 | processError(data);
16 | }
17 |
18 | /**
19 | * Setup initial files
20 | * @param {String} data.sources
21 | */
22 | if (data.sources) {
23 | storeSources(scope, data.sources);
24 | }
25 |
26 | /**
27 | * Apply patch to initial file
28 | * @param {Diff} data.patch
29 | */
30 | if (data.patch) {
31 | var source = scope.files
32 | .filter(function filterBundle(file) {
33 | return file.file === data.file;
34 | })
35 | .map(function getContent(file) {
36 | return file.content;
37 | })
38 | .pop();
39 |
40 | applyPatch(scope, source, data);
41 | }
42 | };
43 |
44 | return scope.ws;
45 | };
46 |
--------------------------------------------------------------------------------
/src/overrideRequire.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | function isNodeModule(name) {
4 | return name[0] !== '.';
5 | }
6 |
7 | function makeAddStaticModule(scope) {
8 | return function addStaticModule(name, content) {
9 | var module = scope.modules.get(name);
10 |
11 | if (!module) {
12 | module = content
13 | }
14 |
15 | scope.modules.add(name, module);
16 |
17 | return scope.modules.get(name);
18 | }
19 | }
20 |
21 | module.exports = function overrideRequire(scope, req, filename) {
22 | var addStaticModule = makeAddStaticModule(scope);
23 |
24 | return function overrideRequire(name) {
25 | if (isNodeModule(name)) {
26 | return addStaticModule(name, req(name));
27 | }
28 |
29 | var fullName = path.resolve(path.dirname(filename), name);
30 |
31 | if (fullName.indexOf(scope.baseDir) === 0) {
32 | fullName = fullName.slice(scope.baseDir.length);
33 | }
34 |
35 | // Try to find stored proxy by name
36 | var proxy = scope.proxies.get(fullName);
37 |
38 | // If succeeded, return proxied component
39 | if (proxy) {
40 | return proxy.get();
41 | }
42 |
43 | // Otherwise try to include a module
44 | if (module = scope.modules.get(fullName || name)) {
45 | return module;
46 | }
47 |
48 | var module = req(name);
49 |
50 | // And then proxy it
51 | proxy = scope.proxies.add(fullName, module);
52 |
53 | if (proxy) {
54 | return proxy.get();
55 | }
56 |
57 | // if it's not proxible, add it to static
58 | addStaticModule(fullName, module);
59 |
60 | return module;
61 | };
62 | };
63 |
--------------------------------------------------------------------------------
/src/transform.js:
--------------------------------------------------------------------------------
1 | const through = require('through2');
2 | const pjson = require('../package.json');
3 | const path = require('path');
4 |
5 | /**
6 | * Resolve path to library file
7 | * @param {String} file
8 | * @return {String}
9 | */
10 | function pathTo(file) {
11 | return pjson.name + '/src/' + file;
12 | }
13 |
14 | /**
15 | * Initialize react live patch
16 | * @description Inject React & WS, create namespace
17 | * @param {Object} options
18 | * @return {String}
19 | */
20 | function initialize(options) {
21 | var port = options.port;
22 | var baseDir = options.baseDir;
23 |
24 | return '\n' +
25 | 'var $$scope = window.__RLP = (window.__RLP || {});\n' +
26 | 'if (!$$scope.initialized) {\n' +
27 | 'var Proxies = require("' + pathTo('Proxies') + '");\n' +
28 | 'var StaticModules = require("' + pathTo('StaticModules') + '");\n' +
29 | 'require("' + pathTo('injectWebSocket') + '")($$scope, require, ' + port + ');\n' +
30 | '$$scope.baseDir = "' + baseDir + '";\n' +
31 | '$$scope.modules = new StaticModules();\n' +
32 | '$$scope.proxies = new Proxies();\n' +
33 | '$$scope.initialized = true;\n' +
34 | '}\n';
35 | }
36 |
37 | /**
38 | * Check if file is JSON (duck test)
39 | * @param {String} file
40 | * @return {Boolean}
41 | */
42 | function isJSON(file) {
43 | return file.slice(-4) === 'json';
44 | }
45 |
46 | /**
47 | * Generate overriden require function
48 | * @param {String} filename
49 | * @return {String} Overriden require injection
50 | */
51 | function overrideRequire(filename) {
52 | return 'require = require("' + pathTo('overrideRequire') + '")' +
53 | '($$scope, require, "' + filename + '");\n';
54 | }
55 |
56 | module.exports = function applyReactHotAPI(file, options) {
57 | var content = [];
58 | var port = options.port;
59 |
60 | return through(
61 | function transform(part, enc, next) {
62 | content.push(part); next();
63 | },
64 |
65 | function finish(done) {
66 | var prelude = '';
67 | content = content.join('');
68 |
69 | if (!isJSON(file)) {
70 | prelude = initialize({
71 | port: port,
72 | baseDir: path.resolve('./'),
73 | }) + overrideRequire(file);
74 | }
75 |
76 | this.push(prelude + content); done();
77 | }
78 | );
79 | };
80 |
--------------------------------------------------------------------------------