mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
next-dev
This commit is contained in:
parent
e51c7eabf1
commit
88b01e0a72
|
@ -1,11 +1,8 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { resolve, dirname } from 'path'
|
||||
import { resolve } from 'path'
|
||||
import parseArgs from 'minimist'
|
||||
import fs from 'mz/fs'
|
||||
import mkdirp from 'mkdirp-then';
|
||||
import glob from 'glob-promise'
|
||||
import { transpile, bundle } from '../server/build'
|
||||
import build from '../server/build'
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2), {
|
||||
alias: {
|
||||
|
@ -16,29 +13,8 @@ const argv = parseArgs(process.argv.slice(2), {
|
|||
|
||||
const dir = resolve(argv._[0] || '.')
|
||||
|
||||
Promise.resolve()
|
||||
.then(async () => {
|
||||
const paths = await glob('**/*.js', { cwd: dir, ignore: 'node_modules/**' })
|
||||
await Promise.all(paths.map(async (p) => {
|
||||
const code = await transpile(resolve(dir, p))
|
||||
const outpath = resolve(dir, '.next', p)
|
||||
await writeFile(outpath, code)
|
||||
}))
|
||||
|
||||
const pagePaths = await glob('.next/pages/**/*.js', { cwd: dir })
|
||||
await Promise.all(pagePaths.map(async (p) => {
|
||||
const code = await bundle(resolve(dir, p))
|
||||
const outpath = resolve(dir, '.next', p)
|
||||
await writeFile(outpath, code)
|
||||
}))
|
||||
})
|
||||
build(dir)
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
exit(1)
|
||||
})
|
||||
|
||||
async function writeFile (path, data) {
|
||||
await mkdirp(dirname(path))
|
||||
await fs.writeFile(path, data, { encoding: 'utf8', flag: 'w+' })
|
||||
}
|
||||
|
||||
|
|
30
bin/next-dev
Executable file
30
bin/next-dev
Executable file
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { resolve } from 'path'
|
||||
import parseArgs from 'minimist'
|
||||
import Server from '../server'
|
||||
import build from '../server/build'
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2), {
|
||||
alias: {
|
||||
h: 'help',
|
||||
p: 'port'
|
||||
},
|
||||
boolean: ['h'],
|
||||
default: {
|
||||
p: 3000
|
||||
}
|
||||
})
|
||||
|
||||
const dir = resolve(argv._[0] || '.')
|
||||
|
||||
build(dir)
|
||||
.then(async () => {
|
||||
const srv = new Server({ dir, dev: true })
|
||||
await srv.start(argv.port)
|
||||
console.log('> Ready on http://localhost:%d', argv.port);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
exit(1)
|
||||
})
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { resolve } from 'path'
|
||||
import parseArgs from 'minimist'
|
||||
import Server from '../server'
|
||||
|
||||
|
@ -14,9 +15,9 @@ const argv = parseArgs(process.argv.slice(2), {
|
|||
}
|
||||
})
|
||||
|
||||
const dir = argv._[0] || '.'
|
||||
const dir = resolve(argv._[0] || '.')
|
||||
|
||||
const srv = new Server(dir)
|
||||
const srv = new Server({ dir })
|
||||
srv.start(argv.port)
|
||||
.then(() => {
|
||||
console.log('> Ready on http://localhost:%d', argv.port);
|
||||
|
|
1
client/next-dev.js
Normal file
1
client/next-dev.js
Normal file
|
@ -0,0 +1 @@
|
|||
import './next'
|
|
@ -54,8 +54,8 @@ export function DevTools (props, context) {
|
|||
DevTools.contextTypes = { _documentProps: PropTypes.any }
|
||||
|
||||
export function NextScript (props, context) {
|
||||
const { hotReload } = context._documentProps;
|
||||
const src = !hotReload ? '/_next/next.bundle.js' : '/_next/next-dev.bundle.js'
|
||||
const { dev } = context._documentProps;
|
||||
const src = !dev ? '/_next/next.bundle.js' : '/_next/next-dev.bundle.js'
|
||||
return <script type='text/javascript' src={src}/>
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
"cross-spawn": "4.0.2",
|
||||
"glob-promise": "1.0.6",
|
||||
"htmlescape": "1.1.1",
|
||||
"memory-fs": "0.3.0",
|
||||
"minimist": "1.2.0",
|
||||
"mkdirp-then": "1.2.0",
|
||||
"mz": "2.4.0",
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
import { resolve, dirname, basename } from 'path'
|
||||
import webpack from 'webpack'
|
||||
import { transformFile } from 'babel-core'
|
||||
import MemoryFS from 'memory-fs'
|
||||
import preset2015 from 'babel-preset-es2015'
|
||||
import presetReact from 'babel-preset-react'
|
||||
import transformAsyncToGenerator from 'babel-plugin-transform-async-to-generator'
|
||||
import transformClassProperties from 'babel-plugin-transform-class-properties'
|
||||
import transformObjectRestSpread from 'babel-plugin-transform-object-rest-spread'
|
||||
import transformRuntime from 'babel-plugin-transform-runtime'
|
||||
import moduleAlias from 'babel-plugin-module-alias'
|
||||
|
||||
const babelRuntimePath = require.resolve('babel-runtime/package')
|
||||
.replace(/[\\\/]package\.json$/, '');
|
||||
|
||||
export function transpile (path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
transformFile(path, {
|
||||
presets: [preset2015, presetReact],
|
||||
plugins: [
|
||||
transformAsyncToGenerator,
|
||||
transformClassProperties,
|
||||
transformObjectRestSpread,
|
||||
transformRuntime,
|
||||
[
|
||||
moduleAlias,
|
||||
[
|
||||
{ src: `npm:${babelRuntimePath}`, expose: 'babel-runtime' },
|
||||
{ src: `npm:${require.resolve('react')}`, expose: 'react' },
|
||||
{ src: `npm:${require.resolve('../lib/link')}`, expose: 'next/link' }
|
||||
]
|
||||
]
|
||||
],
|
||||
ast: false
|
||||
}, (err, result) => {
|
||||
if (err) return reject(err)
|
||||
resolve(result.code)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function bundle (path) {
|
||||
const fs = new MemoryFS()
|
||||
|
||||
const compiler = webpack({
|
||||
entry: path,
|
||||
output: {
|
||||
path: dirname(path),
|
||||
filename: basename(path),
|
||||
libraryTarget: 'commonjs2'
|
||||
},
|
||||
externals: [
|
||||
'react',
|
||||
'react-dom',
|
||||
{
|
||||
[require.resolve('react')]: 'react',
|
||||
[require.resolve('../lib/link')]: 'next/link'
|
||||
}
|
||||
],
|
||||
resolveLoader: {
|
||||
root: resolve(__dirname, '..', '..', 'node_modules')
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: { warnings: false },
|
||||
sourceMap: false
|
||||
})
|
||||
],
|
||||
module: {
|
||||
preLoaders: [
|
||||
{ test: /\.json$/, loader: 'json-loader' }
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
compiler.outputFileSystem = fs
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
compiler.run((err, stats) => {
|
||||
if (err) return reject(err)
|
||||
|
||||
const jsonStats = stats.toJson()
|
||||
if (jsonStats.errors.length > 0) {
|
||||
const error = new Error(jsonStats.errors[0])
|
||||
error.errors = jsonStats.errors
|
||||
error.warnings = jsonStats.warnings
|
||||
return reject(error)
|
||||
}
|
||||
|
||||
resolve(fs.readFileSync(path))
|
||||
})
|
||||
})
|
||||
}
|
51
server/build/bundle.js
Normal file
51
server/build/bundle.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { resolve, dirname, basename } from 'path'
|
||||
import webpack from 'webpack'
|
||||
|
||||
export default function bundle (src, dst) {
|
||||
const compiler = webpack({
|
||||
entry: src,
|
||||
output: {
|
||||
path: dirname(dst),
|
||||
filename: basename(dst),
|
||||
libraryTarget: 'commonjs2'
|
||||
},
|
||||
externals: [
|
||||
'react',
|
||||
'react-dom',
|
||||
{
|
||||
[require.resolve('react')]: 'react',
|
||||
[require.resolve('../lib/link')]: 'next/link'
|
||||
}
|
||||
],
|
||||
resolveLoader: {
|
||||
root: resolve(__dirname, '..', '..', 'node_modules')
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: { warnings: false },
|
||||
sourceMap: false
|
||||
})
|
||||
],
|
||||
module: {
|
||||
preLoaders: [
|
||||
{ test: /\.json$/, loader: 'json-loader' }
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
compiler.run((err, stats) => {
|
||||
if (err) return reject(err)
|
||||
|
||||
const jsonStats = stats.toJson()
|
||||
if (jsonStats.errors.length > 0) {
|
||||
const error = new Error(jsonStats.errors[0])
|
||||
error.errors = jsonStats.errors
|
||||
error.warnings = jsonStats.warnings
|
||||
return reject(error)
|
||||
}
|
||||
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
18
server/build/index.js
Normal file
18
server/build/index.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { resolve } from 'path'
|
||||
import glob from 'glob-promise'
|
||||
import transpile from './transpile'
|
||||
import bundle from './bundle'
|
||||
|
||||
export default async function build (dir) {
|
||||
const dstDir = resolve(dir, '.next')
|
||||
|
||||
const paths = await glob('**/*.js', { cwd: dir, ignore: 'node_modules/**' })
|
||||
await Promise.all(paths.map(async (p) => {
|
||||
await transpile(resolve(dir, p), resolve(dstDir, p))
|
||||
}))
|
||||
|
||||
const pagePaths = await glob('pages/**/*.js', { cwd: dstDir })
|
||||
await Promise.all(pagePaths.map(async (p) => {
|
||||
await bundle(resolve(dstDir, p), resolve(dstDir, '_bundles', p))
|
||||
}))
|
||||
}
|
49
server/build/transpile.js
Normal file
49
server/build/transpile.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { dirname } from 'path'
|
||||
import fs from 'mz/fs'
|
||||
import mkdirp from 'mkdirp-then';
|
||||
import { transformFile } from 'babel-core'
|
||||
import preset2015 from 'babel-preset-es2015'
|
||||
import presetReact from 'babel-preset-react'
|
||||
import transformAsyncToGenerator from 'babel-plugin-transform-async-to-generator'
|
||||
import transformClassProperties from 'babel-plugin-transform-class-properties'
|
||||
import transformObjectRestSpread from 'babel-plugin-transform-object-rest-spread'
|
||||
import transformRuntime from 'babel-plugin-transform-runtime'
|
||||
import moduleAlias from 'babel-plugin-module-alias'
|
||||
|
||||
const babelRuntimePath = require.resolve('babel-runtime/package')
|
||||
.replace(/[\\\/]package\.json$/, '');
|
||||
|
||||
const babelOptions = {
|
||||
presets: [preset2015, presetReact],
|
||||
plugins: [
|
||||
transformAsyncToGenerator,
|
||||
transformClassProperties,
|
||||
transformObjectRestSpread,
|
||||
transformRuntime,
|
||||
[
|
||||
moduleAlias,
|
||||
[
|
||||
{ src: `npm:${babelRuntimePath}`, expose: 'babel-runtime' },
|
||||
{ src: `npm:${require.resolve('react')}`, expose: 'react' },
|
||||
{ src: `npm:${require.resolve('../lib/link')}`, expose: 'next/link' }
|
||||
]
|
||||
]
|
||||
],
|
||||
ast: false
|
||||
}
|
||||
|
||||
export default async function transpile (src, dst) {
|
||||
const code = await new Promise((resolve, reject) => {
|
||||
transformFile(src, babelOptions, (err, result) => {
|
||||
if (err) return reject(err)
|
||||
resolve(result.code)
|
||||
})
|
||||
})
|
||||
|
||||
await writeFile(dst, code)
|
||||
}
|
||||
|
||||
async function writeFile (path, data) {
|
||||
await mkdirp(dirname(path))
|
||||
await fs.writeFile(path, data, { encoding: 'utf8', flag: 'w+' })
|
||||
}
|
|
@ -5,8 +5,9 @@ import Router from './router'
|
|||
import { render, renderJSON } from './render'
|
||||
|
||||
export default class Server {
|
||||
constructor (root) {
|
||||
this.root = resolve(root)
|
||||
constructor ({ dir = '.', dev = false }) {
|
||||
this.dir = resolve(dir)
|
||||
this.dev = dev
|
||||
this.router = new Router()
|
||||
|
||||
this.http = http.createServer((req, res) => {
|
||||
|
@ -50,10 +51,10 @@ export default class Server {
|
|||
}
|
||||
|
||||
async render (req, res, path) {
|
||||
const { root } = this
|
||||
const { dir } = this
|
||||
let html
|
||||
try {
|
||||
html = await render(path, req, res, { root })
|
||||
html = await render(path, req, res, { dir })
|
||||
} catch (err) {
|
||||
if ('MODULE_NOT_FOUND' === err.code) {
|
||||
return this.render404(req, res)
|
||||
|
@ -66,10 +67,10 @@ export default class Server {
|
|||
}
|
||||
|
||||
async renderJSON (req, res, path) {
|
||||
const { root } = this
|
||||
const { dir } = this
|
||||
let json
|
||||
try {
|
||||
json = await renderJSON(path, { root })
|
||||
json = await renderJSON(path, { dir })
|
||||
} catch (err) {
|
||||
if ('MODULE_NOT_FOUND' === err.code) {
|
||||
return this.render404(req, res)
|
||||
|
|
|
@ -6,8 +6,8 @@ import Document from '../lib/document'
|
|||
import App from '../lib/app'
|
||||
import { StyleSheetServer } from '../lib/css'
|
||||
|
||||
export async function render (path, req, res, { root = process.cwd() } = {}) {
|
||||
const mod = require(resolve(root, '.next', 'pages', path)) || {}
|
||||
export async function render (path, req, res, { dir = process.cwd(), dev = false } = {}) {
|
||||
const mod = require(resolve(dir, '.next', 'pages', path)) || {}
|
||||
const Component = mod.default
|
||||
|
||||
let props = {}
|
||||
|
@ -15,7 +15,7 @@ export async function render (path, req, res, { root = process.cwd() } = {}) {
|
|||
props = await Component.getInitialProps({ req, res })
|
||||
}
|
||||
|
||||
const bundlePath = resolve(root, '.next', '.next', 'pages', (path || 'index') + '.js')
|
||||
const bundlePath = resolve(dir, '.next', '_bundles', 'pages', (path || 'index') + '.js')
|
||||
const component = await fs.readFile(bundlePath, 'utf8')
|
||||
|
||||
const { html, css } = StyleSheetServer.renderStatic(() => {
|
||||
|
@ -33,14 +33,15 @@ export async function render (path, req, res, { root = process.cwd() } = {}) {
|
|||
html: html,
|
||||
css: css,
|
||||
data: { component },
|
||||
hotReload: false
|
||||
hotReload: false,
|
||||
dev
|
||||
})
|
||||
|
||||
return '<!DOCTYPE html>' + renderToStaticMarkup(doc)
|
||||
}
|
||||
|
||||
export async function renderJSON (path, { root = process.cwd() }) {
|
||||
const bundlePath = resolve(root, '.next', '.next', 'pages', (path || 'index') + '.js')
|
||||
export async function renderJSON (path, { dir = process.cwd() }) {
|
||||
const bundlePath = resolve(dir, '.next', '_bundles', 'pages', (path || 'index') + '.js')
|
||||
const component = await fs.readFile(bundlePath, 'utf8')
|
||||
return { component }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue