mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Use Typescript to transpile Next.js core files instead of Babel (#5747)
- Replaces taskr-babel with taskr-typescript for the `next` package - Makes sure Node 8+ is used, no unneeded transpilation - Compile Next.js client side files through babel the same way pages are - Compile Next.js client side files to esmodules, not commonjs, so that tree shaking works. - Move error-debug.js out of next-server as it's only used/require in development - Drop ansi-html as dependency from next-server - Make next/link esmodule (for tree-shaking) - Make next/router esmodule (for tree-shaking) - add typescript compilation to next-server - Remove last remains of Flow - Move hoist-non-react-statics to next, out of next-server - Move htmlescape to next, out of next-server - Remove runtime-corejs2 from next-server
This commit is contained in:
parent
c801a96631
commit
15bb1c5e79
|
@ -52,8 +52,8 @@
|
|||
"fkill": "5.1.0",
|
||||
"flatten": "1.0.2",
|
||||
"get-port": "3.2.0",
|
||||
"jest-junit": "^5.0.0",
|
||||
"jest-cli": "23.6.0",
|
||||
"jest-junit": "^5.0.0",
|
||||
"lerna": "^3.4.0",
|
||||
"lint-staged": "4.2.3",
|
||||
"mkdirp": "0.5.1",
|
||||
|
@ -67,7 +67,8 @@
|
|||
"standard": "11.0.1",
|
||||
"taskr": "1.1.0",
|
||||
"wait-port": "0.2.2",
|
||||
"wd": "1.10.3"
|
||||
"wd": "1.10.3",
|
||||
"webpack-bundle-analyzer": "3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
module.exports = {
|
||||
'presets': [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react'
|
||||
],
|
||||
'plugins': [
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
['@babel/plugin-transform-runtime', {
|
||||
'corejs': 2
|
||||
}],
|
||||
['babel-plugin-transform-define', {
|
||||
'process.env.NEXT_VERSION': require('./package.json').version
|
||||
}]
|
||||
]
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
/* global __NEXT_DATA__ */
|
||||
|
||||
import { parse, format } from 'url'
|
||||
import EventEmitter from '../EventEmitter'
|
||||
import shallowEquals from '../shallow-equals'
|
||||
import EventEmitter from '../event-emitter'
|
||||
import shallowEquals from './shallow-equals'
|
||||
import { loadGetInitialProps, getURL } from '../utils'
|
||||
import { _rewriteUrlForNextExport } from './'
|
||||
|
||||
export default class Router {
|
||||
static events = new EventEmitter()
|
||||
|
@ -46,6 +45,30 @@ export default class Router {
|
|||
}
|
||||
}
|
||||
|
||||
static _rewriteUrlForNextExport (url) {
|
||||
const [, hash] = url.split('#')
|
||||
url = url.replace(/#.*/, '')
|
||||
|
||||
let [path, qs] = url.split('?')
|
||||
path = path.replace(/\/$/, '')
|
||||
|
||||
let newPath = path
|
||||
// Append a trailing slash if this path does not have an extension
|
||||
if (!/\.[^/]+\/?$/.test(path)) {
|
||||
newPath = `${path}/`
|
||||
}
|
||||
|
||||
if (qs) {
|
||||
newPath = `${newPath}?${qs}`
|
||||
}
|
||||
|
||||
if (hash) {
|
||||
newPath = `${newPath}#${hash}`
|
||||
}
|
||||
|
||||
return newPath
|
||||
}
|
||||
|
||||
onPopState = e => {
|
||||
if (!e.state) {
|
||||
// We get state as undefined for two reasons.
|
||||
|
@ -147,7 +170,7 @@ export default class Router {
|
|||
// Add the ending slash to the paths. So, we can serve the
|
||||
// "<page>/index.html" directly for the SSR page.
|
||||
if (__NEXT_DATA__.nextExport) {
|
||||
as = _rewriteUrlForNextExport(as)
|
||||
as = Router._rewriteUrlForNextExport(as)
|
||||
}
|
||||
|
||||
this.abortComponentLoad(as)
|
||||
|
|
|
@ -34,8 +34,7 @@ export function isResSent (res) {
|
|||
export async function loadGetInitialProps (Component, ctx) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (Component.prototype && Component.prototype.getInitialProps) {
|
||||
const compName = getDisplayName(Component)
|
||||
const message = `"${compName}.getInitialProps()" is defined as an instance method - visit https://err.sh/zeit/next.js/get-initial-props-as-an-instance-method for more information.`
|
||||
const message = `"${getDisplayName(Component)}.getInitialProps()" is defined as an instance method - visit https://err.sh/zeit/next.js/get-initial-props-as-an-instance-method for more information.`
|
||||
throw new Error(message)
|
||||
}
|
||||
}
|
||||
|
@ -49,8 +48,7 @@ export async function loadGetInitialProps (Component, ctx) {
|
|||
}
|
||||
|
||||
if (!props) {
|
||||
const compName = getDisplayName(Component)
|
||||
const message = `"${compName}.getInitialProps()" should resolve to an object. But found "${props}" instead.`
|
||||
const message = `"${getDisplayName(Component)}.getInitialProps()" should resolve to an object. But found "${props}" instead.`
|
||||
throw new Error(message)
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('./dist/lib/link')
|
|
@ -22,17 +22,13 @@
|
|||
},
|
||||
"taskr": {
|
||||
"requires": [
|
||||
"./taskfile-babel.js"
|
||||
"./taskfile-typescript.js"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime-corejs2": "7.1.2",
|
||||
"ansi-html": "0.0.7",
|
||||
"etag": "1.8.1",
|
||||
"find-up": "3.0.0",
|
||||
"fresh": "0.5.2",
|
||||
"hoist-non-react-statics": "3.0.1",
|
||||
"htmlescape": "1.1.1",
|
||||
"path-to-regexp": "2.1.0",
|
||||
"prop-types": "15.6.2",
|
||||
"send": "0.16.1",
|
||||
|
@ -43,16 +39,10 @@
|
|||
"react-dom": "^16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.1.2",
|
||||
"@babel/plugin-proposal-class-properties": "7.1.0",
|
||||
"@babel/plugin-proposal-object-rest-spread": "7.0.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "7.0.0",
|
||||
"@babel/plugin-transform-runtime": "7.1.0",
|
||||
"@babel/preset-env": "7.1.0",
|
||||
"@babel/preset-react": "7.0.0",
|
||||
"@taskr/clear": "1.1.0",
|
||||
"@taskr/watch": "1.1.0",
|
||||
"taskr": "1.1.0"
|
||||
"taskr": "1.1.0",
|
||||
"typescript": "3.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('./dist/lib/router')
|
|
@ -5,10 +5,9 @@ import send from 'send'
|
|||
import generateETag from 'etag'
|
||||
import fresh from 'fresh'
|
||||
import requirePage, {normalizePagePath} from './require'
|
||||
import { Router } from '../lib/router'
|
||||
import Router from '../lib/router/router'
|
||||
import { loadGetInitialProps, isResSent } from '../lib/utils'
|
||||
import Head, { defaultHead } from '../lib/head'
|
||||
import ErrorDebug from '../lib/error-debug'
|
||||
import Loadable from '../lib/loadable'
|
||||
import LoadableCapture from '../lib/loadable-capture'
|
||||
import { BUILD_MANIFEST, REACT_LOADABLE_MANIFEST, SERVER_DIRECTORY, CLIENT_STATIC_FILES_PATH } from 'next-server/constants'
|
||||
|
@ -137,6 +136,7 @@ async function doRender (req, res, pathname, query, {
|
|||
|
||||
try {
|
||||
if (err && dev) {
|
||||
const ErrorDebug = require(join(distDir, SERVER_DIRECTORY, 'error-debug')).default
|
||||
html = render(<ErrorDebug error={err} />)
|
||||
} else {
|
||||
html = render(app)
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
// taskr babel plugin with Babel 7 support
|
||||
// https://github.com/lukeed/taskr/pull/305
|
||||
'use strict'
|
||||
|
||||
const transform = require('@babel/core').transform
|
||||
const flatten = require('flatten')
|
||||
|
||||
const BABEL_REGEX = /(^@babel\/)(preset|plugin)-(.*)/i
|
||||
|
||||
function getBabels () {
|
||||
const pkg = require('./package.json')
|
||||
return flatten(
|
||||
['devDependencies', 'dependencies'].map(s => Object.keys(pkg[s] || {}))
|
||||
).filter(s => BABEL_REGEX.test(s))
|
||||
}
|
||||
|
||||
module.exports = function (task) {
|
||||
let cache
|
||||
|
||||
task.plugin('babel', {}, function * (file, opts) {
|
||||
if (opts.preload) {
|
||||
delete opts.preload
|
||||
// get dependencies
|
||||
cache = cache || getBabels()
|
||||
|
||||
// attach any deps to babel's `opts`
|
||||
cache.forEach(dep => {
|
||||
const segs = BABEL_REGEX.exec(dep)
|
||||
const type = `${segs[2]}s`
|
||||
const name = `@babel/${segs[2]}-${segs[3]}`
|
||||
|
||||
opts[type] = opts[type] || []
|
||||
|
||||
// flatten all (advanced entries are arrays)
|
||||
if (flatten(opts[type]).indexOf(name) === -1) {
|
||||
opts[type] = opts[type].concat(name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// attach file's name
|
||||
opts.filename = file.base
|
||||
|
||||
const output = transform(file.data, opts)
|
||||
|
||||
if (output.map) {
|
||||
const map = `${file.base}.map`
|
||||
|
||||
// append `sourceMappingURL` to original file
|
||||
if (opts.sourceMaps !== 'both') {
|
||||
output.code += Buffer.from(`\n//# sourceMappingURL=${map}`)
|
||||
}
|
||||
|
||||
// add sourcemap to `files` array
|
||||
this._.files.push({
|
||||
base: map,
|
||||
dir: file.dir,
|
||||
data: Buffer.from(JSON.stringify(output.map))
|
||||
})
|
||||
}
|
||||
|
||||
// update file's data
|
||||
file.data = Buffer.from(output.code)
|
||||
})
|
||||
}
|
43
packages/next-server/taskfile-typescript.js
Normal file
43
packages/next-server/taskfile-typescript.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
'use strict'
|
||||
try {
|
||||
const ts = require('typescript')
|
||||
const extname = require('path').extname
|
||||
const config = require('./tsconfig.json')
|
||||
|
||||
module.exports = function (task) {
|
||||
task.plugin('typescript', { every: true }, function * (file, options) {
|
||||
const opts = {
|
||||
fileName: file.base,
|
||||
compilerOptions: {
|
||||
...config.compilerOptions,
|
||||
...options
|
||||
}
|
||||
}
|
||||
|
||||
const ext = extname(file.base)
|
||||
// For example files without an extension don't have to be rewritten
|
||||
if (ext) {
|
||||
// Replace `.ts` with `.js`
|
||||
const extRegex = new RegExp(ext.replace('.', '\\.') + '$', 'i')
|
||||
file.base = file.base.replace(extRegex, '.js')
|
||||
}
|
||||
|
||||
// compile output
|
||||
const result = ts.transpileModule(file.data.toString(), opts)
|
||||
|
||||
if (opts.compilerOptions.sourceMap && result.sourceMapText) {
|
||||
// add sourcemap to `files` array
|
||||
this._.files.push({
|
||||
dir: file.dir,
|
||||
base: `${file.base}.map`,
|
||||
data: Buffer.from(JSON.stringify(result.sourceMapText), 'utf8')
|
||||
})
|
||||
}
|
||||
|
||||
// update file's data
|
||||
file.data = Buffer.from(result.outputText.replace(/process\.env\.NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8')
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
|
@ -1,27 +1,21 @@
|
|||
const notifier = require('node-notifier')
|
||||
|
||||
export async function bin (task, opts) {
|
||||
await task.source(opts.src || 'bin/*').babel().target('dist/bin', {mode: '0755'})
|
||||
notify('Compiled binaries')
|
||||
}
|
||||
|
||||
export async function lib (task, opts) {
|
||||
await task.source(opts.src || 'lib/**/*.js').babel().target('dist/lib')
|
||||
await task.source(opts.src || 'lib/**/*.js').typescript({module: 'commonjs'}).target('dist/lib')
|
||||
notify('Compiled lib files')
|
||||
}
|
||||
|
||||
export async function server (task, opts) {
|
||||
await task.source(opts.src || 'server/**/*.js').babel().target('dist/server')
|
||||
await task.source(opts.src || 'server/**/*.js').typescript({module: 'commonjs'}).target('dist/server')
|
||||
notify('Compiled server files')
|
||||
}
|
||||
|
||||
export async function build (task) {
|
||||
await task.parallel(['bin', 'server', 'lib'])
|
||||
await task.parallel(['server', 'lib'])
|
||||
}
|
||||
|
||||
export default async function (task) {
|
||||
await task.start('build')
|
||||
await task.watch('bin/*', 'bin')
|
||||
await task.watch('server/**/*.js', 'server')
|
||||
await task.watch('lib/**/*.js', 'lib')
|
||||
}
|
||||
|
|
10
packages/next-server/tsconfig.json
Normal file
10
packages/next-server/tsconfig.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
"module": "esnext",
|
||||
"target": "ES2017",
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react"
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
[ignore]
|
||||
<PROJECT_ROOT>/.*.json
|
|
@ -1,17 +0,0 @@
|
|||
module.exports = {
|
||||
'presets': [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react'
|
||||
],
|
||||
'plugins': [
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
['@babel/plugin-transform-runtime', {
|
||||
'corejs': 2
|
||||
}],
|
||||
['babel-plugin-transform-define', {
|
||||
'process.env.NEXT_VERSION': require('./package.json').version
|
||||
}]
|
||||
]
|
||||
}
|
|
@ -19,12 +19,6 @@ export default function ({ types: t, template }) {
|
|||
if (source === 'next/head') {
|
||||
path.node.source.value = 'next-server/head'
|
||||
}
|
||||
if (source === 'next/link') {
|
||||
path.node.source.value = 'next-server/link'
|
||||
}
|
||||
if (source === 'next/router') {
|
||||
path.node.source.value = 'next-server/router'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import BuildManifestPlugin from './webpack/plugins/build-manifest-plugin'
|
|||
import ChunkNamesPlugin from './webpack/plugins/chunk-names-plugin'
|
||||
import { ReactLoadablePlugin } from './webpack/plugins/react-loadable-plugin'
|
||||
import {SERVER_DIRECTORY, REACT_LOADABLE_MANIFEST, CLIENT_STATIC_FILES_RUNTIME_WEBPACK, CLIENT_STATIC_FILES_RUNTIME_MAIN} from 'next-server/constants'
|
||||
import {NEXT_PROJECT_ROOT, NEXT_PROJECT_ROOT_NODE_MODULES, NEXT_PROJECT_ROOT_DIST, DEFAULT_PAGES_DIR} from '../lib/constants'
|
||||
import {NEXT_PROJECT_ROOT, NEXT_PROJECT_ROOT_NODE_MODULES, NEXT_PROJECT_ROOT_DIST_CLIENT, NEXT_PROJECT_ROOT_DIST_SERVER, DEFAULT_PAGES_DIR} from '../lib/constants'
|
||||
import AutoDllPlugin from 'autodll-webpack-plugin'
|
||||
import TerserPlugin from 'terser-webpack-plugin'
|
||||
import AssetsSizePlugin from './webpack/plugins/assets-size-plugin'
|
||||
|
@ -58,7 +58,7 @@ function externalsConfig (dir, isServer, lambdas) {
|
|||
]
|
||||
}
|
||||
|
||||
const notExternalModules = ['next/app', 'next/document', 'next/error', 'http-status', 'string-hash']
|
||||
const notExternalModules = ['next/app', 'next/document', 'next/link', 'next/router', 'next/error', 'http-status', 'string-hash', 'ansi-html', 'hoist-non-react-statics', 'htmlescape']
|
||||
|
||||
externals.push((context, request, callback) => {
|
||||
if (notExternalModules.indexOf(request) !== -1) {
|
||||
|
@ -71,11 +71,7 @@ function externalsConfig (dir, isServer, lambdas) {
|
|||
}
|
||||
|
||||
// Default pages have to be transpiled
|
||||
if (res.match(/next[/\\]dist[/\\]pages/)) {
|
||||
return callback()
|
||||
}
|
||||
|
||||
if (res.match(/node_modules[/\\]@babel[/\\]runtime[/\\]/)) {
|
||||
if (res.match(/next[/\\]dist[/\\]pages/) || res.match(/next[/\\]dist[/\\]client/) || res.match(/node_modules[/\\]@babel[/\\]runtime[/\\]/) || res.match(/node_modules[/\\]@babel[/\\]runtime-corejs2[/\\]/)) {
|
||||
return callback()
|
||||
}
|
||||
|
||||
|
@ -200,9 +196,12 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
|
|||
// Backwards compatibility
|
||||
'main.js': [],
|
||||
[CLIENT_STATIC_FILES_RUNTIME_MAIN]: [
|
||||
path.join(NEXT_PROJECT_ROOT_DIST, 'client', (dev ? `next-dev` : 'next'))
|
||||
path.join(NEXT_PROJECT_ROOT_DIST_CLIENT, (dev ? `next-dev` : 'next'))
|
||||
].filter(Boolean)
|
||||
} : {}
|
||||
const devServerEntries = dev && isServer ? {
|
||||
'error-debug.js': path.join(NEXT_PROJECT_ROOT_DIST_SERVER, 'error-debug.js')
|
||||
} : {}
|
||||
|
||||
const resolveConfig = {
|
||||
// Disable .mjs for node_modules bundling
|
||||
|
@ -233,6 +232,7 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
|
|||
entry: async () => {
|
||||
return {
|
||||
...clientEntries,
|
||||
...devServerEntries,
|
||||
// Only _error and _document when in development. The rest is handled by on-demand-entries
|
||||
...pagesEntries
|
||||
}
|
||||
|
@ -273,8 +273,14 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
|
|||
},
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
include: [dir],
|
||||
exclude: /node_modules/,
|
||||
include: [dir, NEXT_PROJECT_ROOT_DIST_CLIENT, DEFAULT_PAGES_DIR],
|
||||
exclude: (path) => {
|
||||
if (path.indexOf(NEXT_PROJECT_ROOT_DIST_CLIENT) === 0 || path.indexOf(DEFAULT_PAGES_DIR) === 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
return /node_modules/.exec(path)
|
||||
},
|
||||
use: defaultLoaders.babel
|
||||
}
|
||||
].filter(Boolean)
|
||||
|
|
|
@ -37,11 +37,15 @@ export default class NextJsSsrImportPlugin {
|
|||
// If the chunk is not part of the pages directory we have to keep the original behavior,
|
||||
// otherwise webpack will error out when the file is used before the compilation finishes
|
||||
// this is the case with mini-css-extract-plugin
|
||||
if (!IS_BUNDLED_PAGE_REGEX.exec(chunk.name)) {
|
||||
if (!IS_BUNDLED_PAGE_REGEX.exec(chunk.name) && chunk.name !== 'error-debug.js') {
|
||||
return originalFn(source, chunk)
|
||||
}
|
||||
const pagePath = join(outputPath, dirname(chunk.name))
|
||||
const relativePathToBaseDir = relative(pagePath, join(outputPath, SSR_MODULE_CACHE_FILENAME))
|
||||
let relativePathToBaseDir = relative(pagePath, join(outputPath, SSR_MODULE_CACHE_FILENAME))
|
||||
if (chunk.name === 'error-debug.js') {
|
||||
relativePathToBaseDir = `./${relativePathToBaseDir}`
|
||||
}
|
||||
|
||||
// Make sure even in windows, the path looks like in unix
|
||||
// Node.js require system will convert it accordingly
|
||||
const relativePathToBaseDirNormalized = relativePathToBaseDir.replace(/\\/g, '/')
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import HeadManager from './head-manager'
|
||||
import { createRouter } from 'next-server/dist/lib/router'
|
||||
import EventEmitter from 'next-server/dist/lib/EventEmitter'
|
||||
import { createRouter } from 'next/router'
|
||||
import EventEmitter from 'next-server/dist/lib/event-emitter'
|
||||
import {loadGetInitialProps, getURL} from 'next-server/dist/lib/utils'
|
||||
import PageLoader from '../lib/page-loader'
|
||||
import PageLoader from './page-loader'
|
||||
import * as asset from 'next-server/asset'
|
||||
import * as envConfig from 'next-server/config'
|
||||
import ErrorBoundary from './error-boundary'
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
import { resolve, format, parse } from 'url'
|
||||
import React, { Component, Children } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Router, { _rewriteUrlForNextExport } from './router'
|
||||
import {execOnce, getLocationOrigin} from './utils'
|
||||
import Router, {Router as _Router} from 'next/router'
|
||||
import {execOnce, getLocationOrigin} from 'next-server/dist/lib/utils'
|
||||
|
||||
function isLocal (href) {
|
||||
const url = parse(href, false, true)
|
||||
|
@ -145,7 +145,7 @@ class Link extends Component {
|
|||
typeof __NEXT_DATA__ !== 'undefined' &&
|
||||
__NEXT_DATA__.nextExport
|
||||
) {
|
||||
props.href = _rewriteUrlForNextExport(props.href)
|
||||
props.href = _Router._rewriteUrlForNextExport(props.href)
|
||||
}
|
||||
|
||||
return React.cloneElement(child, props)
|
|
@ -1,6 +1,6 @@
|
|||
/* global location */
|
||||
|
||||
import Router from 'next-server/router'
|
||||
import Router from 'next/router'
|
||||
import fetch from 'unfetch'
|
||||
|
||||
export default ({assetPrefix}) => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* global document */
|
||||
import EventEmitter from 'next-server/dist/lib/EventEmitter'
|
||||
import EventEmitter from 'next-server/dist/lib/event-emitter'
|
||||
|
||||
// smaller version of https://gist.github.com/igrigorik/a02f2359f3bc50ca7a9c
|
||||
function supportsPreload (list) {
|
|
@ -1,6 +1,5 @@
|
|||
/* global window */
|
||||
import _Router from './router'
|
||||
import { execOnce } from '../utils'
|
||||
import _Router from 'next-server/dist/lib/router/router'
|
||||
|
||||
const SingletonRouter = {
|
||||
router: null, // holds the actual router instance
|
||||
|
@ -62,18 +61,6 @@ routerEvents.forEach((event) => {
|
|||
})
|
||||
})
|
||||
|
||||
const warnAboutRouterOnAppUpdated = execOnce(() => {
|
||||
console.warn(`Router.onAppUpdated is removed - visit https://err.sh/zeit/next.js/no-on-app-updated-hook for more information.`)
|
||||
})
|
||||
|
||||
Object.defineProperty(SingletonRouter, 'onAppUpdated', {
|
||||
get () { return null },
|
||||
set () {
|
||||
warnAboutRouterOnAppUpdated()
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
function throwIfNoRouter () {
|
||||
if (!SingletonRouter.router) {
|
||||
const message = 'No router instance found.\n' +
|
||||
|
@ -86,7 +73,7 @@ function throwIfNoRouter () {
|
|||
export default SingletonRouter
|
||||
|
||||
// Reexport the withRoute HOC
|
||||
export { default as withRouter } from './with-router'
|
||||
export { default as withRouter } from '../lib/with-router'
|
||||
|
||||
// INTERNAL APIS
|
||||
// -------------
|
||||
|
@ -106,30 +93,6 @@ export const createRouter = function (...args) {
|
|||
// Export the actual Router class, which is usually used inside the server
|
||||
export const Router = _Router
|
||||
|
||||
export function _rewriteUrlForNextExport (url) {
|
||||
const [, hash] = url.split('#')
|
||||
url = url.replace(/#.*/, '')
|
||||
|
||||
let [path, qs] = url.split('?')
|
||||
path = path.replace(/\/$/, '')
|
||||
|
||||
let newPath = path
|
||||
// Append a trailing slash if this path does not have an extension
|
||||
if (!/\.[^/]+\/?$/.test(path)) {
|
||||
newPath = `${path}/`
|
||||
}
|
||||
|
||||
if (qs) {
|
||||
newPath = `${newPath}?${qs}`
|
||||
}
|
||||
|
||||
if (hash) {
|
||||
newPath = `${newPath}#${hash}`
|
||||
}
|
||||
|
||||
return newPath
|
||||
}
|
||||
|
||||
// This function is used to create the `withRouter` router instance
|
||||
export function makePublicRouterInstance (router) {
|
||||
const instance = {}
|
|
@ -1,6 +1,6 @@
|
|||
import 'event-source-polyfill'
|
||||
import connect from './dev-error-overlay/hot-dev-client'
|
||||
import Router from 'next-server/router'
|
||||
import Router from 'next/router'
|
||||
|
||||
const handlers = {
|
||||
reload (route) {
|
||||
|
|
|
@ -3,3 +3,5 @@ export const NEXT_PROJECT_ROOT = join(__dirname, '..', '..')
|
|||
export const NEXT_PROJECT_ROOT_DIST = join(NEXT_PROJECT_ROOT, 'dist')
|
||||
export const NEXT_PROJECT_ROOT_NODE_MODULES = join(NEXT_PROJECT_ROOT, 'node_modules')
|
||||
export const DEFAULT_PAGES_DIR = join(NEXT_PROJECT_ROOT_DIST, 'pages')
|
||||
export const NEXT_PROJECT_ROOT_DIST_CLIENT = join(NEXT_PROJECT_ROOT_DIST, 'client')
|
||||
export const NEXT_PROJECT_ROOT_DIST_SERVER = join(NEXT_PROJECT_ROOT_DIST, 'server')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import hoistStatics from 'hoist-non-react-statics'
|
||||
import { getDisplayName } from '../utils'
|
||||
import { getDisplayName } from 'next-server/dist/lib/utils'
|
||||
|
||||
export default function withRouter (ComposedComponent) {
|
||||
const displayName = getDisplayName(ComposedComponent)
|
||||
|
@ -14,12 +14,10 @@ export default function withRouter (ComposedComponent) {
|
|||
static displayName = `withRouter(${displayName})`
|
||||
|
||||
render () {
|
||||
const props = {
|
||||
router: this.context.router,
|
||||
...this.props
|
||||
}
|
||||
|
||||
return <ComposedComponent {...props} />
|
||||
return <ComposedComponent
|
||||
router={this.context.router}
|
||||
{...this.props}
|
||||
/>
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
module.exports = require('next-server/link')
|
||||
export {default} from './dist/client/link'
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
},
|
||||
"taskr": {
|
||||
"requires": [
|
||||
"./taskfile-babel.js"
|
||||
"./taskfile-typescript.js"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -60,6 +60,8 @@
|
|||
"fresh": "0.5.2",
|
||||
"friendly-errors-webpack-plugin": "1.7.0",
|
||||
"glob": "7.1.2",
|
||||
"hoist-non-react-statics": "3.2.0",
|
||||
"htmlescape": "1.1.1",
|
||||
"http-status": "1.0.1",
|
||||
"launch-editor": "2.2.1",
|
||||
"loader-utils": "1.1.0",
|
||||
|
@ -91,7 +93,8 @@
|
|||
"@taskr/clear": "1.1.0",
|
||||
"@taskr/esnext": "1.1.0",
|
||||
"@taskr/watch": "1.1.0",
|
||||
"taskr": "1.1.0"
|
||||
"taskr": "1.1.0",
|
||||
"typescript": "3.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { execOnce, loadGetInitialProps } from 'next-server/dist/lib/utils'
|
||||
import { makePublicRouterInstance } from 'next-server/router'
|
||||
import { makePublicRouterInstance } from 'next/router'
|
||||
|
||||
export default class App extends Component {
|
||||
static childContextTypes = {
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
module.exports = require('next-server/router')
|
||||
export * from './dist/client/router'
|
||||
export {default} from './dist/client/router'
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
// taskr babel plugin with Babel 7 support
|
||||
// https://github.com/lukeed/taskr/pull/305
|
||||
'use strict'
|
||||
|
||||
const transform = require('@babel/core').transform
|
||||
const flatten = require('flatten')
|
||||
|
||||
const BABEL_REGEX = /(^@babel\/)(preset|plugin)-(.*)/i
|
||||
|
||||
function getBabels () {
|
||||
const pkg = require('./package.json')
|
||||
return flatten(
|
||||
['devDependencies', 'dependencies'].map(s => Object.keys(pkg[s] || {}))
|
||||
).filter(s => BABEL_REGEX.test(s))
|
||||
}
|
||||
|
||||
module.exports = function (task) {
|
||||
let cache
|
||||
|
||||
task.plugin('babel', {}, function * (file, opts) {
|
||||
if (opts.preload) {
|
||||
delete opts.preload
|
||||
// get dependencies
|
||||
cache = cache || getBabels()
|
||||
|
||||
// attach any deps to babel's `opts`
|
||||
cache.forEach(dep => {
|
||||
const segs = BABEL_REGEX.exec(dep)
|
||||
const type = `${segs[2]}s`
|
||||
const name = `@babel/${segs[2]}-${segs[3]}`
|
||||
|
||||
opts[type] = opts[type] || []
|
||||
|
||||
// flatten all (advanced entries are arrays)
|
||||
if (flatten(opts[type]).indexOf(name) === -1) {
|
||||
opts[type] = opts[type].concat(name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// attach file's name
|
||||
opts.filename = file.base
|
||||
|
||||
const output = transform(file.data, opts)
|
||||
|
||||
if (output.map) {
|
||||
const map = `${file.base}.map`
|
||||
|
||||
// append `sourceMappingURL` to original file
|
||||
if (opts.sourceMaps !== 'both') {
|
||||
output.code += Buffer.from(`\n//# sourceMappingURL=${map}`)
|
||||
}
|
||||
|
||||
// add sourcemap to `files` array
|
||||
this._.files.push({
|
||||
base: map,
|
||||
dir: file.dir,
|
||||
data: Buffer.from(JSON.stringify(output.map))
|
||||
})
|
||||
}
|
||||
|
||||
// update file's data
|
||||
file.data = Buffer.from(output.code)
|
||||
})
|
||||
}
|
43
packages/next/taskfile-typescript.js
Normal file
43
packages/next/taskfile-typescript.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
'use strict'
|
||||
try {
|
||||
const ts = require('typescript')
|
||||
const extname = require('path').extname
|
||||
const config = require('./tsconfig.json')
|
||||
|
||||
module.exports = function (task) {
|
||||
task.plugin('typescript', { every: true }, function * (file, options) {
|
||||
const opts = {
|
||||
fileName: file.base,
|
||||
compilerOptions: {
|
||||
...config.compilerOptions,
|
||||
...options
|
||||
}
|
||||
}
|
||||
|
||||
const ext = extname(file.base)
|
||||
// For example files without an extension don't have to be rewritten
|
||||
if (ext) {
|
||||
// Replace `.ts` with `.js`
|
||||
const extRegex = new RegExp(ext.replace('.', '\\.') + '$', 'i')
|
||||
file.base = file.base.replace(extRegex, '.js')
|
||||
}
|
||||
|
||||
// compile output
|
||||
const result = ts.transpileModule(file.data.toString(), opts)
|
||||
|
||||
if (opts.compilerOptions.sourceMap && result.sourceMapText) {
|
||||
// add sourcemap to `files` array
|
||||
this._.files.push({
|
||||
dir: file.dir,
|
||||
base: `${file.base}.map`,
|
||||
data: Buffer.from(JSON.stringify(result.sourceMapText), 'utf8')
|
||||
})
|
||||
}
|
||||
|
||||
// update file's data
|
||||
file.data = Buffer.from(result.outputText, 'utf8')
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
|
@ -5,38 +5,38 @@ export async function compile (task) {
|
|||
}
|
||||
|
||||
export async function bin (task, opts) {
|
||||
await task.source(opts.src || 'bin/*').babel().target('dist/bin', {mode: '0755'})
|
||||
await task.source(opts.src || 'bin/*').typescript({module: 'commonjs'}).target('dist/bin', {mode: '0755'})
|
||||
notify('Compiled binaries')
|
||||
}
|
||||
|
||||
export async function lib (task, opts) {
|
||||
await task.source(opts.src || 'lib/**/*.js').babel().target('dist/lib')
|
||||
await task.source(opts.src || 'lib/**/*.js').typescript({module: 'commonjs'}).target('dist/lib')
|
||||
notify('Compiled lib files')
|
||||
}
|
||||
|
||||
export async function server (task, opts) {
|
||||
await task.source(opts.src || 'server/**/*.js').babel().target('dist/server')
|
||||
await task.source(opts.src || 'server/**/*.js').typescript({module: 'commonjs'}).target('dist/server')
|
||||
notify('Compiled server files')
|
||||
}
|
||||
|
||||
export async function nextbuild (task, opts) {
|
||||
await task.source(opts.src || 'build/**/*.js').babel().target('dist/build')
|
||||
await task.source(opts.src || 'build/**/*.js').typescript({module: 'commonjs'}).target('dist/build')
|
||||
notify('Compiled build files')
|
||||
}
|
||||
|
||||
export async function client (task, opts) {
|
||||
await task.source(opts.src || 'client/**/*.js').babel().target('dist/client')
|
||||
await task.source(opts.src || 'client/**/*.js').typescript().target('dist/client')
|
||||
notify('Compiled client files')
|
||||
}
|
||||
|
||||
// export is a reserved keyword for functions
|
||||
export async function nextbuildstatic (task, opts) {
|
||||
await task.source(opts.src || 'export/**/*.js').babel().target('dist/export')
|
||||
await task.source(opts.src || 'export/**/*.js').typescript({module: 'commonjs'}).target('dist/export')
|
||||
notify('Compiled export files')
|
||||
}
|
||||
|
||||
export async function pages (task, opts) {
|
||||
await task.source(opts.src || 'pages/**/*.js').babel().target('dist/pages')
|
||||
await task.source(opts.src || 'pages/**/*.js').typescript().target('dist/pages')
|
||||
}
|
||||
|
||||
export async function build (task) {
|
||||
|
|
10
packages/next/tsconfig.json
Normal file
10
packages/next/tsconfig.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
"module": "esnext",
|
||||
"target": "ES2017",
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react"
|
||||
}
|
||||
}
|
|
@ -1,4 +1,13 @@
|
|||
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer')
|
||||
module.exports = {
|
||||
webpack (config, {isServer}) {
|
||||
config.plugins.push(new BundleAnalyzerPlugin({
|
||||
analyzerMode: 'static',
|
||||
reportFilename: `dist/${isServer ? 'server' : 'client'}.html`,
|
||||
openAnalyzer: false
|
||||
}))
|
||||
return config
|
||||
},
|
||||
onDemandEntries: {
|
||||
// Make sure entries are not getting disposed.
|
||||
maxInactiveAge: 1000 * 60 * 60
|
||||
|
|
|
@ -66,6 +66,6 @@ describe('Production response size', () => {
|
|||
console.log(`Response Sizes:\n${responseSizes.map(obj => ` ${obj.url}: ${obj.bytes} (bytes)`).join('\n')} \nOverall: ${responseSizeKilobytes} KB`)
|
||||
|
||||
// These numbers are without gzip compression!
|
||||
expect(responseSizeKilobytes).toBeLessThanOrEqual(207) // Kilobytes
|
||||
expect(responseSizeKilobytes).toBeLessThanOrEqual(210) // Kilobytes
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* eslint-env jest */
|
||||
import EventEmitter from 'next-server/dist/lib/EventEmitter'
|
||||
import EventEmitter from 'next-server/dist/lib/event-emitter'
|
||||
|
||||
describe('EventEmitter', () => {
|
||||
describe('With listeners', () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-env jest */
|
||||
|
||||
import shallowEquals from 'next-server/dist/lib/shallow-equals'
|
||||
import shallowEquals from 'next-server/dist/lib/router/shallow-equals'
|
||||
|
||||
describe('Shallow Equals', () => {
|
||||
it('should be true if both objects are the same', () => {
|
||||
|
|
Loading…
Reference in a new issue