1
0
Fork 0
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:
Arunoda Susiripala 2016-11-28 05:45:56 +05:30 committed by Naoyuki Kanezawa
parent c7ba914f52
commit fcd59adea1
13 changed files with 143 additions and 23 deletions

View file

@ -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

View file

@ -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

View 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
```

View 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>
)
}
}

View 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>
)

View 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
}
}

View 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>
)

View 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>
)

View file

@ -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': {

View file

@ -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')

View file

@ -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
}

View file

@ -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'
})
]

View file

@ -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)