Skip to content

Commit eb1cfe8

Browse files
committed
feat: improve SSR support
BREAKING CHANGE: - SSR has been rewritten from scratch, if you use it, please follow the new guide. - Prefetch component and prefetch functions have been removed, please use `webpackPrefetch` instead.
1 parent 766bd66 commit eb1cfe8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+5450
-462
lines changed

README.md

Lines changed: 6 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -230,46 +230,19 @@ export const OtherComponent = loadable(() =>
230230
231231
### Prefetching
232232
233-
To enhance user experience, you can prefetch components, it loads component in background. This way you will avoid loading at first component display.
233+
Loadable Components is fully compatible with [webpack hints `webpackPrefetch` and `webpackPreload`](https://webpack.js.org/guides/code-splitting/#prefetching-preloading-modules).
234234
235-
Each `loadable` component exposes a `Prefetch` component. It renders nothing but prefetch the component.
235+
Most of the time, you want to "prefetch" a component, it means it will be loaded when the browser is idle. You can do it by adding `/* webpackPrefetch: true */` inside your import statement.
236236
237237
```js
238238
import loadable from '@loadable/component'
239239

240-
const OtherComponent = loadable(() => import('./OtherComponent'))
241-
242-
function MyComponent() {
243-
return (
244-
<div>
245-
{/* Nothing will be rendered, but the component will be loaded in background */}
246-
<OtherComponent.Prefetch />
247-
</div>
248-
)
249-
}
250-
```
251-
252-
A method `prefetch` is also exposed, you can call it to trigger `prefetch` on user action.
253-
254-
```js
255-
import loadable from '@loadable/component'
256-
257-
const OtherComponent = loadable(() => import('./OtherComponent'))
258-
259-
function MyComponent() {
260-
return (
261-
<div>
262-
<button onMouseOver={() => OtherComponent.prefetch()}>
263-
Prefetch on hover
264-
</button>
265-
</div>
266-
)
267-
}
240+
const OtherComponent = loadable(() =>
241+
import(/* webpackPrefetch: true */ './OtherComponent'),
242+
)
268243
```
269244
270-
> `prefetch` and `Prefetch` are also available for components created with `lazy`, `loadable.lib` and `lazy.lib`.
271-
272-
> Only component based prefetching (`<Prefetch>`) is compatible with Server Side Rendering.
245+
> You can extract prefetched resources server-side to add `<link rel="prefetch">` in your head.
273246
274247
## API
275248
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"env": {
3+
"browser": true
4+
},
5+
"rules": {
6+
"import/no-unresolved": "off",
7+
"import/no-extraneous-dependencies": "off"
8+
}
9+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
public/dist
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const loadableBabelPlugin = require('../../packages/babel-plugin')
2+
3+
function isWebTarget(caller) {
4+
return Boolean(caller && caller.target === 'web')
5+
}
6+
7+
function isWebpack(caller) {
8+
return Boolean(caller && caller.name === 'babel-loader')
9+
}
10+
11+
module.exports = api => {
12+
const web = api.caller(isWebTarget)
13+
const webpack = api.caller(isWebpack)
14+
15+
return {
16+
presets: [
17+
'@babel/preset-react',
18+
[
19+
'@babel/preset-env',
20+
{
21+
useBuiltIns: web ? 'entry' : undefined,
22+
targets: !web ? { node: 'current' } : undefined,
23+
modules: webpack ? false : 'commonjs',
24+
},
25+
],
26+
],
27+
plugins: ['@babel/plugin-syntax-dynamic-import', loadableBabelPlugin],
28+
}
29+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"ignore": ["client", "public"],
3+
"execMap": {
4+
"js": "babel-node"
5+
}
6+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "client-side",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"license": "MIT",
6+
"scripts": {
7+
"dev": "nodemon src/server/main.js",
8+
"build": "NODE_ENV=production yarn build:webpack && yarn build:lib",
9+
"build:webpack": "webpack",
10+
"build:lib": "babel -d lib src",
11+
"start": "NODE_ENV=production node lib/server/main.js"
12+
},
13+
"devDependencies": {
14+
"@babel/cli": "^7.1.2",
15+
"@babel/node": "^7.0.0",
16+
"babel-loader": "^8.0.4",
17+
"css-loader": "^1.0.1",
18+
"mini-css-extract-plugin": "^0.4.4",
19+
"nodemon": "^1.18.5",
20+
"webpack": "^4.24.0",
21+
"webpack-cli": "^3.1.2",
22+
"webpack-dev-middleware": "^3.4.0",
23+
"webpack-node-externals": "^1.7.2"
24+
},
25+
"dependencies": {
26+
"express": "^4.16.4",
27+
"express-async-handler": "^1.1.4",
28+
"moment": "^2.22.2",
29+
"react": "^16.6.0",
30+
"react-dom": "^16.6.0"
31+
}
32+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react'
2+
// eslint-disable-next-line import/no-extraneous-dependencies
3+
import loadable from '@loadable/component'
4+
import './main.css'
5+
6+
const A = loadable(() => import('./letters/A'))
7+
const B = loadable(() => import('./letters/B'))
8+
const C = loadable(() => import(/* webpackPreload: true */ './letters/C'))
9+
const D = loadable(() => import(/* webpackPrefetch: true */ './letters/D'))
10+
11+
// We keep some references to prevent uglify remove
12+
A.C = C
13+
A.D = D
14+
15+
const Moment = loadable.lib(() => import('moment'))
16+
17+
const App = () => (
18+
<div>
19+
<A />
20+
<B />
21+
<Moment>{moment => moment().format('HH:mm')}</Moment>
22+
</div>
23+
)
24+
25+
export default App
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/* A CSS */
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// We simulate that "moment" is called in "A" and "B"
2+
import moment from 'moment'
3+
import './A.css'
4+
5+
const A = () => 'A'
6+
7+
// We keep a reference to prevent uglify remove
8+
A.moment = moment
9+
10+
export default A
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// We simulate that "moment" is called in "A" and "B"
2+
import moment from 'moment'
3+
4+
const B = () => 'B'
5+
6+
// We keep a reference to prevent uglify remove
7+
B.moment = moment
8+
9+
export default B

0 commit comments

Comments
 (0)