Skip to content

Commit

Permalink
Add support for webpack's CommonsChunkPlugin and remove next bundle (#…
Browse files Browse the repository at this point in the history
…301)

* Add example app which demonstrate the problem.

* Add the first working version.

* Fix lint issues.

* Add README.md

* Use /_next/main.js as the main file URI

* Add the support for loading the core next bundle.

* Optimize the output by removing Next modules from pages.

* Use the same package.json as master use.

* Change the example repo's README for simpler instructions.

* Change example projects package.json to support next build and start.

* Change main.js into commons.js.

* Add support for hot core reload and errors.

* Introduce require based on eval-script.

* Add error reporting support with hot reloading.

* Update README.md
  • Loading branch information
arunoda authored and nkzawa committed Nov 28, 2016
1 parent c7ba914 commit fcd59ad
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 23 deletions.
4 changes: 2 additions & 2 deletions client/next-dev.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'react-hot-loader/patch'
import * as next from './next'

module.exports = next
import { requireModule } from '../lib/eval-script'

window.next = next
module.exports = requireModule
35 changes: 22 additions & 13 deletions client/next.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,33 @@ import HeadManager from './head-manager'
import { rehydrate } from '../lib/css'
import Router from '../lib/router'
import App from '../lib/app'
import evalScript from '../lib/eval-script'
import evalScript, { requireModule } from '../lib/eval-script'

const {
__NEXT_DATA__: { component, errorComponent, props, ids, err }
} = window

const Component = evalScript(component).default
const ErrorComponent = evalScript(errorComponent).default
document.addEventListener('DOMContentLoaded', () => {
const Component = evalScript(component).default
const ErrorComponent = evalScript(errorComponent).default

export const router = new Router(window.location.href, {
Component,
ErrorComponent,
ctx: { err }
})
const router = new Router(window.location.href, {
Component,
ErrorComponent,
ctx: { err }
})

// This it to support error handling in the dev time with hot code reload.
if (window.next) {
window.next.router = router
}

const headManager = new HeadManager()
const container = document.getElementById('__next')
const appProps = { Component, props, router, headManager }
const headManager = new HeadManager()
const container = document.getElementById('__next')
const appProps = { Component, props, router, headManager }

rehydrate(ids)
render(createElement(App, appProps), container)
})

rehydrate(ids)
render(createElement(App, appProps), container)
module.exports = requireModule
13 changes: 13 additions & 0 deletions examples/shared-modules/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Example app using shared modules

This example features:

* An app with two pages which has a common Counter component
* That Counter component maintain the counter inside its module.

## How to run it

```sh
npm install
npm run dev
```
19 changes: 19 additions & 0 deletions examples/shared-modules/components/Counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'

let count = 0

export default class Counter extends React.Component {
add () {
count += 1
this.forceUpdate()
}

render () {
return (
<div>
<p>Count is: {count}</p>
<button onClick={() => this.add()}>Add</button>
</div>
)
}
}
20 changes: 20 additions & 0 deletions examples/shared-modules/components/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react'
import Link from 'next/link'

const styles = {
a: {
marginRight: 10
}
}

export default () => (
<div>
<Link href='/'>
<a style={styles.a} >Home</a>
</Link>

<Link href='/about'>
<a style={styles.a} >About</a>
</Link>
</div>
)
19 changes: 19 additions & 0 deletions examples/shared-modules/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "shared-modules",
"version": "1.0.0",
"description": "This example features:",
"main": "index.js",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "*"
},
"author": "",
"license": "ISC",
"next": {
"cdn": false
}
}
11 changes: 11 additions & 0 deletions examples/shared-modules/pages/about.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react'
import Header from '../components/Header'
import Counter from '../components/Counter'

export default () => (
<div>
<Header />
<p>This is the about page.</p>
<Counter />
</div>
)
11 changes: 11 additions & 0 deletions examples/shared-modules/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react'
import Header from '../components/Header'
import Counter from '../components/Counter'

export default () => (
<div>
<Header />
<p>HOME PAGE is here!</p>
<Counter />
</div>
)
4 changes: 2 additions & 2 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ gulp.task('build-dev-client', ['compile-lib', 'compile-client'], () => {
.src('dist/client/next-dev.js')
.pipe(webpack({
quiet: true,
output: { filename: 'next-dev.bundle.js' },
output: { filename: 'next-dev.bundle.js', libraryTarget: 'var', library: 'require' },
module: {
loaders: [
{
Expand All @@ -125,7 +125,7 @@ gulp.task('build-client', ['compile-lib', 'compile-client'], () => {
.src('dist/client/next.js')
.pipe(webpack({
quiet: true,
output: { filename: 'next.bundle.js' },
output: { filename: 'next.bundle.js', libraryTarget: 'var', library: 'require' },
plugins: [
new webpack.webpack.DefinePlugin({
'process.env': {
Expand Down
6 changes: 4 additions & 2 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ export default ({ head, css, html, data, dev, staticMarkup, cdn }) => {
</head>
<body>
<div id='__next' dangerouslySetInnerHTML={{ __html: html }} />
{staticMarkup ? null : <script dangerouslySetInnerHTML={{ __html: '__NEXT_DATA__ = ' + htmlescape(data) }} />}
{staticMarkup ? null : <script dangerouslySetInnerHTML={{
__html: `__NEXT_DATA__ =${htmlescape(data)}; module={};`
}} />}
{staticMarkup ? null : createClientScript({ dev, cdn })}
<script type='text/javascript' src='/_next/commons.js' />
</body>
</html>
}
Expand All @@ -30,7 +33,6 @@ function createClientScript ({ dev, cdn }) {
load('https://cdn.zeit.co/next.js/${pkg.version}/next.min.js', function (err) {
if (err) load('/_next/next.bundle.js')
})
function load (src, fn) {
fn = fn || function () {}
var script = document.createElement('script')
Expand Down
15 changes: 11 additions & 4 deletions lib/eval-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ const modules = new Map([
['next/head', Head]
])

function require (moduleName) {
const name = moduleName
const m = modules.get(name)

if (m) return m

throw new Error(`Module "${moduleName}" is not exists in the bundle`)
}

export const requireModule = require

/**
* IMPORTANT: This module is compiled *without* `use strict`
* so that when we `eval` a dependency below, we don't enforce
Expand All @@ -28,10 +39,6 @@ const modules = new Map([

export default function evalScript (script) {
const module = { exports: {} }
const require = function (path) { // eslint-disable-line no-unused-vars
return modules.get(path)
}
// don't use Function() here since it changes source locations
eval(script) // eslint-disable-line no-eval
return module.exports
}
4 changes: 4 additions & 0 deletions server/build/webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export default async function createCompiler (dir, { hotReload = false, dev = fa
log: false,
// required not to cache removed files
useHashIndex: false
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'commons',
filename: 'commons.js'
})
]

Expand Down
5 changes: 5 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export default class Server {
}

defineRoutes () {
this.router.get('/_next/commons.js', async (req, res, params) => {
const p = join(this.dir, '.next/commons.js')
await this.serveStatic(req, res, p)
})

this.router.get('/_next/:path+', async (req, res, params) => {
const p = join(__dirname, '..', 'client', ...(params.path || []))
await this.serveStatic(req, res, p)
Expand Down

0 comments on commit fcd59ad

Please sign in to comment.