mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Add support for webpack's CommonsChunkPlugin and remove next bundle (#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
This commit is contained in:
parent
c7ba914f52
commit
fcd59adea1
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
|
||||
rehydrate(ids)
|
||||
render(createElement(App, appProps), container)
|
||||
})
|
||||
|
||||
const headManager = new HeadManager()
|
||||
const container = document.getElementById('__next')
|
||||
const appProps = { Component, props, router, headManager }
|
||||
|
||||
rehydrate(ids)
|
||||
render(createElement(App, appProps), container)
|
||||
module.exports = requireModule
|
||||
|
|
13
examples/shared-modules/README.md
Normal file
13
examples/shared-modules/README.md
Normal file
|
@ -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
examples/shared-modules/components/Counter.js
Normal file
19
examples/shared-modules/components/Counter.js
Normal file
|
@ -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
examples/shared-modules/components/Header.js
Normal file
20
examples/shared-modules/components/Header.js
Normal file
|
@ -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
examples/shared-modules/package.json
Normal file
19
examples/shared-modules/package.json
Normal file
|
@ -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
examples/shared-modules/pages/about.js
Normal file
11
examples/shared-modules/pages/about.js
Normal file
|
@ -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
examples/shared-modules/pages/index.js
Normal file
11
examples/shared-modules/pages/index.js
Normal file
|
@ -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>
|
||||
)
|
|
@ -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: [
|
||||
{
|
||||
|
@ -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': {
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
})
|
||||
]
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue