mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Implement tslint for core files (#5952)
Fixes #5845 Implement tslint for core files **What is this?** Implements tslint for both next and next-server, but keeps standardjs/eslint for the .js files that are still there, we're gradually migrating to Typescript. **How does it work?** Before every commit (pre-commit) we execute the following `tslint` command: `tslint -c tslint.json 'packages/**/*.ts` **TSLint Rules** In order to avoid as much changes as possible I marked some rules as false. This way we can improve the linter but making sure this step will not break things. (see tslint.json) **Note** After merging this PR, you'll need to update your dependencies since it adds tslint to package.json
This commit is contained in:
parent
aabc72015c
commit
20fe65ce41
|
@ -33,7 +33,7 @@
|
||||||
"git add"
|
"git add"
|
||||||
],
|
],
|
||||||
"*.ts": [
|
"*.ts": [
|
||||||
"standard --parser typescript-eslint-parser --plugin typescript --fix",
|
"tslint -c tslint.json 'packages/**/*.ts'",
|
||||||
"git add"
|
"git add"
|
||||||
],
|
],
|
||||||
"packages/**/bin/*": [
|
"packages/**/bin/*": [
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
"standard": {
|
"standard": {
|
||||||
"parser": "babel-eslint",
|
"parser": "babel-eslint",
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"packages/next-server/server/next-server.ts",
|
"packages/**/*.ts",
|
||||||
"**/*.d.ts",
|
"**/*.d.ts",
|
||||||
"**/node_modules/**",
|
"**/node_modules/**",
|
||||||
"examples/with-ioc/**",
|
"examples/with-ioc/**",
|
||||||
|
@ -89,6 +89,8 @@
|
||||||
"rimraf": "2.6.2",
|
"rimraf": "2.6.2",
|
||||||
"standard": "11.0.1",
|
"standard": "11.0.1",
|
||||||
"taskr": "1.1.0",
|
"taskr": "1.1.0",
|
||||||
|
"tslint": "5.12.0",
|
||||||
|
"typescript": "3.1.1",
|
||||||
"typescript-eslint-parser": "21.0.1",
|
"typescript-eslint-parser": "21.0.1",
|
||||||
"wait-port": "0.2.2",
|
"wait-port": "0.2.2",
|
||||||
"wd": "1.10.3",
|
"wd": "1.10.3",
|
||||||
|
|
|
@ -2,7 +2,7 @@ export type ManifestItem = {
|
||||||
id: number|string,
|
id: number|string,
|
||||||
name: string,
|
name: string,
|
||||||
file: string,
|
file: string,
|
||||||
publicPath: string
|
publicPath: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Manifest = {[moduleId: string]: ManifestItem[]}
|
export type Manifest = {[moduleId: string]: ManifestItem[]}
|
||||||
|
@ -10,7 +10,7 @@ export type Manifest = {[moduleId: string]: ManifestItem[]}
|
||||||
type DynamicImportBundles = Set<ManifestItem>
|
type DynamicImportBundles = Set<ManifestItem>
|
||||||
|
|
||||||
// Based on https://github.com/jamiebuilds/react-loadable/pull/132
|
// Based on https://github.com/jamiebuilds/react-loadable/pull/132
|
||||||
export function getDynamicImportBundles (manifest: Manifest, moduleIds: string[]): DynamicImportBundles {
|
export function getDynamicImportBundles(manifest: Manifest, moduleIds: string[]): DynamicImportBundles {
|
||||||
return moduleIds.reduce((bundles: DynamicImportBundles, moduleId: string): DynamicImportBundles => {
|
return moduleIds.reduce((bundles: DynamicImportBundles, moduleId: string): DynamicImportBundles => {
|
||||||
if (typeof manifest[moduleId] === 'undefined') {
|
if (typeof manifest[moduleId] === 'undefined') {
|
||||||
return bundles
|
return bundles
|
||||||
|
|
|
@ -3,15 +3,16 @@ import { normalizePagePath } from './normalize-page-path'
|
||||||
export type BuildManifest = {
|
export type BuildManifest = {
|
||||||
devFiles: string[],
|
devFiles: string[],
|
||||||
pages: {
|
pages: {
|
||||||
[page: string]: string[]
|
[page: string]: string[],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPageFiles (buildManifest: BuildManifest, page: string): string[] {
|
export function getPageFiles(buildManifest: BuildManifest, page: string): string[] {
|
||||||
const normalizedPage = normalizePagePath(page)
|
const normalizedPage = normalizePagePath(page)
|
||||||
const files = buildManifest.pages[normalizedPage]
|
const files = buildManifest.pages[normalizedPage]
|
||||||
|
|
||||||
if (!files) {
|
if (!files) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.warn(`Could not find files for ${normalizedPage} in .next/build-manifest.json`)
|
console.warn(`Could not find files for ${normalizedPage} in .next/build-manifest.json`)
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,19 @@ import {join} from 'path'
|
||||||
import {CLIENT_STATIC_FILES_PATH, BUILD_MANIFEST, REACT_LOADABLE_MANIFEST, SERVER_DIRECTORY} from 'next-server/constants'
|
import {CLIENT_STATIC_FILES_PATH, BUILD_MANIFEST, REACT_LOADABLE_MANIFEST, SERVER_DIRECTORY} from 'next-server/constants'
|
||||||
import {requirePage} from './require'
|
import {requirePage} from './require'
|
||||||
|
|
||||||
function interopDefault (mod: any) {
|
function interopDefault(mod: any) {
|
||||||
return mod.default || mod
|
return mod.default || mod
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadComponents (distDir: string, buildId: string, pathname: string) {
|
export async function loadComponents(distDir: string, buildId: string, pathname: string) {
|
||||||
const documentPath = join(distDir, SERVER_DIRECTORY, CLIENT_STATIC_FILES_PATH, buildId, 'pages', '_document')
|
const documentPath = join(distDir, SERVER_DIRECTORY, CLIENT_STATIC_FILES_PATH, buildId, 'pages', '_document')
|
||||||
const appPath = join(distDir, SERVER_DIRECTORY, CLIENT_STATIC_FILES_PATH, buildId, 'pages', '_app')
|
const appPath = join(distDir, SERVER_DIRECTORY, CLIENT_STATIC_FILES_PATH, buildId, 'pages', '_app')
|
||||||
let [buildManifest, reactLoadableManifest, Component, Document, App] = await Promise.all([
|
const [buildManifest, reactLoadableManifest, Component, Document, App] = await Promise.all([
|
||||||
require(join(distDir, BUILD_MANIFEST)),
|
require(join(distDir, BUILD_MANIFEST)),
|
||||||
require(join(distDir, REACT_LOADABLE_MANIFEST)),
|
require(join(distDir, REACT_LOADABLE_MANIFEST)),
|
||||||
interopDefault(requirePage(pathname, distDir)),
|
interopDefault(requirePage(pathname, distDir)),
|
||||||
interopDefault(require(documentPath)),
|
interopDefault(require(documentPath)),
|
||||||
interopDefault(require(appPath))
|
interopDefault(require(appPath)),
|
||||||
])
|
])
|
||||||
|
|
||||||
return {buildManifest, reactLoadableManifest, Component, Document, App}
|
return {buildManifest, reactLoadableManifest, Component, Document, App}
|
||||||
|
|
|
@ -21,7 +21,7 @@ type ServerConstructor = {
|
||||||
dir?: string,
|
dir?: string,
|
||||||
staticMarkup?: boolean,
|
staticMarkup?: boolean,
|
||||||
quiet?: boolean,
|
quiet?: boolean,
|
||||||
conf?: NextConfig
|
conf?: NextConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Server {
|
export default class Server {
|
||||||
|
@ -35,11 +35,11 @@ export default class Server {
|
||||||
buildId: string,
|
buildId: string,
|
||||||
generateEtags: boolean,
|
generateEtags: boolean,
|
||||||
runtimeConfig?: {[key: string]: any},
|
runtimeConfig?: {[key: string]: any},
|
||||||
assetPrefix?: string
|
assetPrefix?: string,
|
||||||
}
|
}
|
||||||
router: Router
|
router: Router
|
||||||
|
|
||||||
public constructor ({ dir = '.', staticMarkup = false, quiet = false, conf = null }: ServerConstructor = {}) {
|
public constructor({ dir = '.', staticMarkup = false, quiet = false, conf = null }: ServerConstructor = {}) {
|
||||||
this.dir = resolve(dir)
|
this.dir = resolve(dir)
|
||||||
this.quiet = quiet
|
this.quiet = quiet
|
||||||
const phase = this.currentPhase()
|
const phase = this.currentPhase()
|
||||||
|
@ -54,7 +54,7 @@ export default class Server {
|
||||||
this.renderOpts = {
|
this.renderOpts = {
|
||||||
staticMarkup,
|
staticMarkup,
|
||||||
buildId: this.buildId,
|
buildId: this.buildId,
|
||||||
generateEtags
|
generateEtags,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only the `publicRuntimeConfig` key is exposed to the client side
|
// Only the `publicRuntimeConfig` key is exposed to the client side
|
||||||
|
@ -66,7 +66,7 @@ export default class Server {
|
||||||
// Initialize next/config with the environment configuration
|
// Initialize next/config with the environment configuration
|
||||||
envConfig.setConfig({
|
envConfig.setConfig({
|
||||||
serverRuntimeConfig,
|
serverRuntimeConfig,
|
||||||
publicRuntimeConfig
|
publicRuntimeConfig,
|
||||||
})
|
})
|
||||||
|
|
||||||
const routes = this.generateRoutes()
|
const routes = this.generateRoutes()
|
||||||
|
@ -74,16 +74,17 @@ export default class Server {
|
||||||
this.setAssetPrefix(assetPrefix)
|
this.setAssetPrefix(assetPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
private currentPhase (): string {
|
private currentPhase(): string {
|
||||||
return PHASE_PRODUCTION_SERVER
|
return PHASE_PRODUCTION_SERVER
|
||||||
}
|
}
|
||||||
|
|
||||||
private logError(...args: any): void {
|
private logError(...args: any): void {
|
||||||
if(this.quiet) return
|
if (this.quiet) return
|
||||||
|
// tslint:disable-next-line
|
||||||
console.error(...args)
|
console.error(...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleRequest (req: IncomingMessage, res: ServerResponse, parsedUrl?: UrlWithParsedQuery): Promise<void> {
|
private handleRequest(req: IncomingMessage, res: ServerResponse, parsedUrl?: UrlWithParsedQuery): Promise<void> {
|
||||||
// Parse url if parsedUrl not provided
|
// Parse url if parsedUrl not provided
|
||||||
if (!parsedUrl || typeof parsedUrl !== 'object') {
|
if (!parsedUrl || typeof parsedUrl !== 'object') {
|
||||||
const url: any = req.url
|
const url: any = req.url
|
||||||
|
@ -104,26 +105,26 @@ export default class Server {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRequestHandler () {
|
public getRequestHandler() {
|
||||||
return this.handleRequest.bind(this)
|
return this.handleRequest.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
public setAssetPrefix (prefix?: string) {
|
public setAssetPrefix(prefix?: string) {
|
||||||
this.renderOpts.assetPrefix = prefix ? prefix.replace(/\/$/, '') : ''
|
this.renderOpts.assetPrefix = prefix ? prefix.replace(/\/$/, '') : ''
|
||||||
asset.setAssetPrefix(this.renderOpts.assetPrefix)
|
asset.setAssetPrefix(this.renderOpts.assetPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backwards compatibility
|
// Backwards compatibility
|
||||||
public async prepare (): Promise<void> {}
|
public async prepare(): Promise<void> {}
|
||||||
|
|
||||||
// Backwards compatibility
|
// Backwards compatibility
|
||||||
private async close (): Promise<void> {}
|
private async close(): Promise<void> {}
|
||||||
|
|
||||||
private setImmutableAssetCacheControl (res: ServerResponse) {
|
private setImmutableAssetCacheControl(res: ServerResponse) {
|
||||||
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
|
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateRoutes (): Route[] {
|
private generateRoutes(): Route[] {
|
||||||
const routes: Route[] = [
|
const routes: Route[] = [
|
||||||
{
|
{
|
||||||
match: route('/_next/static/:path*'),
|
match: route('/_next/static/:path*'),
|
||||||
|
@ -136,14 +137,14 @@ export default class Server {
|
||||||
}
|
}
|
||||||
const p = join(this.distDir, CLIENT_STATIC_FILES_PATH, ...(params.path || []))
|
const p = join(this.distDir, CLIENT_STATIC_FILES_PATH, ...(params.path || []))
|
||||||
await this.serveStatic(req, res, p, parsedUrl)
|
await this.serveStatic(req, res, p, parsedUrl)
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: route('/_next/:path*'),
|
match: route('/_next/:path*'),
|
||||||
// This path is needed because `render()` does a check for `/_next` and the calls the routing again
|
// This path is needed because `render()` does a check for `/_next` and the calls the routing again
|
||||||
fn: async (req, res, _params, parsedUrl) => {
|
fn: async (req, res, _params, parsedUrl) => {
|
||||||
await this.render404(req, res, parsedUrl)
|
await this.render404(req, res, parsedUrl)
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// It's very important to keep this route's param optional.
|
// It's very important to keep this route's param optional.
|
||||||
|
@ -154,8 +155,8 @@ export default class Server {
|
||||||
fn: async (req, res, params, parsedUrl) => {
|
fn: async (req, res, params, parsedUrl) => {
|
||||||
const p = join(this.dir, 'static', ...(params.path || []))
|
const p = join(this.dir, 'static', ...(params.path || []))
|
||||||
await this.serveStatic(req, res, p, parsedUrl)
|
await this.serveStatic(req, res, p, parsedUrl)
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
if (this.nextConfig.useFileSystemPublicRoutes) {
|
if (this.nextConfig.useFileSystemPublicRoutes) {
|
||||||
|
@ -167,18 +168,18 @@ export default class Server {
|
||||||
match: route('/:path*'),
|
match: route('/:path*'),
|
||||||
fn: async (req, res, _params, parsedUrl) => {
|
fn: async (req, res, _params, parsedUrl) => {
|
||||||
const { pathname, query } = parsedUrl
|
const { pathname, query } = parsedUrl
|
||||||
if(!pathname) {
|
if (!pathname) {
|
||||||
throw new Error('pathname is undefined')
|
throw new Error('pathname is undefined')
|
||||||
}
|
}
|
||||||
await this.render(req, res, pathname, query, parsedUrl)
|
await this.render(req, res, pathname, query, parsedUrl)
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
private async run (req: IncomingMessage, res: ServerResponse, parsedUrl: UrlWithParsedQuery) {
|
private async run(req: IncomingMessage, res: ServerResponse, parsedUrl: UrlWithParsedQuery) {
|
||||||
try {
|
try {
|
||||||
const fn = this.router.match(req, res, parsedUrl)
|
const fn = this.router.match(req, res, parsedUrl)
|
||||||
if (fn) {
|
if (fn) {
|
||||||
|
@ -206,7 +207,7 @@ export default class Server {
|
||||||
return sendHTML(req, res, html, {generateEtags})
|
return sendHTML(req, res, html, {generateEtags})
|
||||||
}
|
}
|
||||||
|
|
||||||
public async render (req: IncomingMessage, res: ServerResponse, pathname: string, query: ParsedUrlQuery = {}, parsedUrl?: UrlWithParsedQuery): Promise<void> {
|
public async render(req: IncomingMessage, res: ServerResponse, pathname: string, query: ParsedUrlQuery = {}, parsedUrl?: UrlWithParsedQuery): Promise<void> {
|
||||||
const url: any = req.url
|
const url: any = req.url
|
||||||
if (isInternalUrl(url)) {
|
if (isInternalUrl(url)) {
|
||||||
return this.handleRequest(req, res, parsedUrl)
|
return this.handleRequest(req, res, parsedUrl)
|
||||||
|
@ -233,7 +234,7 @@ export default class Server {
|
||||||
return renderToHTML(req, res, pathname, query, {...result, ...opts})
|
return renderToHTML(req, res, pathname, query, {...result, ...opts})
|
||||||
}
|
}
|
||||||
|
|
||||||
public async renderToHTML (req: IncomingMessage, res: ServerResponse, pathname: string, query: ParsedUrlQuery = {}): Promise<string|null> {
|
public async renderToHTML(req: IncomingMessage, res: ServerResponse, pathname: string, query: ParsedUrlQuery = {}): Promise<string|null> {
|
||||||
try {
|
try {
|
||||||
// To make sure the try/catch is executed
|
// To make sure the try/catch is executed
|
||||||
const html = await this.renderToHTMLWithComponents(req, res, pathname, query, this.renderOpts)
|
const html = await this.renderToHTMLWithComponents(req, res, pathname, query, this.renderOpts)
|
||||||
|
@ -250,30 +251,30 @@ export default class Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async renderError (err: Error|null, req: IncomingMessage, res: ServerResponse, pathname: string, query: ParsedUrlQuery = {}): Promise<void> {
|
public async renderError(err: Error|null, req: IncomingMessage, res: ServerResponse, pathname: string, query: ParsedUrlQuery = {}): Promise<void> {
|
||||||
res.setHeader('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
|
res.setHeader('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
|
||||||
const html = await this.renderErrorToHTML(err, req, res, pathname, query)
|
const html = await this.renderErrorToHTML(err, req, res, pathname, query)
|
||||||
if(html === null) {
|
if (html === null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return this.sendHTML(req, res, html)
|
return this.sendHTML(req, res, html)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async renderErrorToHTML (err: Error|null, req: IncomingMessage, res: ServerResponse, _pathname: string, query: ParsedUrlQuery = {}) {
|
public async renderErrorToHTML(err: Error|null, req: IncomingMessage, res: ServerResponse, _pathname: string, query: ParsedUrlQuery = {}) {
|
||||||
return this.renderToHTMLWithComponents(req, res, '/_error', query, {...this.renderOpts, err})
|
return this.renderToHTMLWithComponents(req, res, '/_error', query, {...this.renderOpts, err})
|
||||||
}
|
}
|
||||||
|
|
||||||
public async render404 (req: IncomingMessage, res: ServerResponse, parsedUrl?: UrlWithParsedQuery): Promise<void> {
|
public async render404(req: IncomingMessage, res: ServerResponse, parsedUrl?: UrlWithParsedQuery): Promise<void> {
|
||||||
const url: any = req.url
|
const url: any = req.url
|
||||||
const { pathname, query } = parsedUrl ? parsedUrl : parseUrl(url, true)
|
const { pathname, query } = parsedUrl ? parsedUrl : parseUrl(url, true)
|
||||||
if(!pathname) {
|
if (!pathname) {
|
||||||
throw new Error('pathname is undefined')
|
throw new Error('pathname is undefined')
|
||||||
}
|
}
|
||||||
res.statusCode = 404
|
res.statusCode = 404
|
||||||
return this.renderError(null, req, res, pathname, query)
|
return this.renderError(null, req, res, pathname, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async serveStatic (req: IncomingMessage, res: ServerResponse, path: string, parsedUrl?: UrlWithParsedQuery): Promise<void> {
|
public async serveStatic(req: IncomingMessage, res: ServerResponse, path: string, parsedUrl?: UrlWithParsedQuery): Promise<void> {
|
||||||
if (!this.isServeableUrl(path)) {
|
if (!this.isServeableUrl(path)) {
|
||||||
return this.render404(req, res, parsedUrl)
|
return this.render404(req, res, parsedUrl)
|
||||||
}
|
}
|
||||||
|
@ -289,7 +290,7 @@ export default class Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isServeableUrl (path: string): boolean {
|
private isServeableUrl(path: string): boolean {
|
||||||
const resolved = resolve(path)
|
const resolved = resolve(path)
|
||||||
if (
|
if (
|
||||||
resolved.indexOf(join(this.distDir) + sep) !== 0 &&
|
resolved.indexOf(join(this.distDir) + sep) !== 0 &&
|
||||||
|
@ -302,7 +303,7 @@ export default class Server {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private readBuildId (): string {
|
private readBuildId(): string {
|
||||||
const buildIdFile = join(this.distDir, BUILD_ID_FILE)
|
const buildIdFile = join(this.distDir, BUILD_ID_FILE)
|
||||||
try {
|
try {
|
||||||
return fs.readFileSync(buildIdFile, 'utf8').trim()
|
return fs.readFileSync(buildIdFile, 'utf8').trim()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { posix } from 'path'
|
import { posix } from 'path'
|
||||||
export function normalizePagePath (page: string): string {
|
export function normalizePagePath(page: string): string {
|
||||||
// If the page is `/` we need to append `/index`, otherwise the returned directory root will be bundles instead of pages
|
// If the page is `/` we need to append `/index`, otherwise the returned directory root will be bundles instead of pages
|
||||||
if (page === '/') {
|
if (page === '/') {
|
||||||
page = '/index'
|
page = '/index'
|
||||||
|
|
|
@ -2,19 +2,20 @@ import {join} from 'path'
|
||||||
import {PAGES_MANIFEST, SERVER_DIRECTORY} from 'next-server/constants'
|
import {PAGES_MANIFEST, SERVER_DIRECTORY} from 'next-server/constants'
|
||||||
import { normalizePagePath } from './normalize-page-path'
|
import { normalizePagePath } from './normalize-page-path'
|
||||||
|
|
||||||
export function pageNotFoundError (page: string): Error {
|
export function pageNotFoundError(page: string): Error {
|
||||||
const err: any = new Error(`Cannot find module for page: ${page}`)
|
const err: any = new Error(`Cannot find module for page: ${page}`)
|
||||||
err.code = 'ENOENT'
|
err.code = 'ENOENT'
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPagePath (page: string, distDir: string): string {
|
export function getPagePath(page: string, distDir: string): string {
|
||||||
const serverBuildPath = join(distDir, SERVER_DIRECTORY)
|
const serverBuildPath = join(distDir, SERVER_DIRECTORY)
|
||||||
const pagesManifest = require(join(serverBuildPath, PAGES_MANIFEST))
|
const pagesManifest = require(join(serverBuildPath, PAGES_MANIFEST))
|
||||||
|
|
||||||
try {
|
try {
|
||||||
page = normalizePagePath(page)
|
page = normalizePagePath(page)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.error(err)
|
console.error(err)
|
||||||
throw pageNotFoundError(page)
|
throw pageNotFoundError(page)
|
||||||
}
|
}
|
||||||
|
@ -26,7 +27,7 @@ export function getPagePath (page: string, distDir: string): string {
|
||||||
return join(serverBuildPath, pagesManifest[page])
|
return join(serverBuildPath, pagesManifest[page])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function requirePage (page: string, distDir: string): any {
|
export function requirePage(page: string, distDir: string): any {
|
||||||
const pagePath = getPagePath(page, distDir)
|
const pagePath = getPagePath(page, distDir)
|
||||||
return require(pagePath)
|
return require(pagePath)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,20 +8,20 @@ type Params = {[param: string]: string}
|
||||||
|
|
||||||
export type Route = {
|
export type Route = {
|
||||||
match: (pathname: string|undefined) => false|Params,
|
match: (pathname: string|undefined) => false|Params,
|
||||||
fn: (req: IncomingMessage, res: ServerResponse, params: Params, parsedUrl: UrlWithParsedQuery) => void
|
fn: (req: IncomingMessage, res: ServerResponse, params: Params, parsedUrl: UrlWithParsedQuery) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Router {
|
export default class Router {
|
||||||
routes: Route[]
|
routes: Route[]
|
||||||
constructor (routes: Route[] = []) {
|
constructor(routes: Route[] = []) {
|
||||||
this.routes = routes
|
this.routes = routes
|
||||||
}
|
}
|
||||||
|
|
||||||
add (route: Route) {
|
add(route: Route) {
|
||||||
this.routes.unshift(route)
|
this.routes.unshift(route)
|
||||||
}
|
}
|
||||||
|
|
||||||
match (req: IncomingMessage, res: ServerResponse, parsedUrl: UrlWithParsedQuery) {
|
match(req: IncomingMessage, res: ServerResponse, parsedUrl: UrlWithParsedQuery) {
|
||||||
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import generateETag from 'etag'
|
||||||
import fresh from 'fresh'
|
import fresh from 'fresh'
|
||||||
import { isResSent } from '../lib/utils'
|
import { isResSent } from '../lib/utils'
|
||||||
|
|
||||||
export function sendHTML (req: IncomingMessage, res: ServerResponse, html: string, { generateEtags }: {generateEtags: boolean}) {
|
export function sendHTML(req: IncomingMessage, res: ServerResponse, html: string, { generateEtags }: {generateEtags: boolean}) {
|
||||||
if (isResSent(res)) return
|
if (isResSent(res)) return
|
||||||
const etag = generateEtags ? generateETag(html) : undefined
|
const etag = generateEtags ? generateETag(html) : undefined
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import send from 'send'
|
||||||
// since send doesn't support wasm yet
|
// since send doesn't support wasm yet
|
||||||
send.mime.define({ 'application/wasm': ['wasm'] })
|
send.mime.define({ 'application/wasm': ['wasm'] })
|
||||||
|
|
||||||
export function serveStatic (req: IncomingMessage, res: ServerResponse, path: string): Promise<void> {
|
export function serveStatic(req: IncomingMessage, res: ServerResponse, path: string): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
send(req, path)
|
send(req, path)
|
||||||
.on('directory', () => {
|
.on('directory', () => {
|
||||||
|
|
|
@ -2,10 +2,10 @@ import { BLOCKED_PAGES } from 'next-server/constants'
|
||||||
|
|
||||||
const internalPrefixes = [
|
const internalPrefixes = [
|
||||||
/^\/_next\//,
|
/^\/_next\//,
|
||||||
/^\/static\//
|
/^\/static\//,
|
||||||
]
|
]
|
||||||
|
|
||||||
export function isInternalUrl (url: string): boolean {
|
export function isInternalUrl(url: string): boolean {
|
||||||
for (const prefix of internalPrefixes) {
|
for (const prefix of internalPrefixes) {
|
||||||
if (prefix.test(url)) {
|
if (prefix.test(url)) {
|
||||||
return true
|
return true
|
||||||
|
@ -15,6 +15,6 @@ export function isInternalUrl (url: string): boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isBlockedPage (pathname: string): boolean {
|
export function isBlockedPage(pathname: string): boolean {
|
||||||
return (BLOCKED_PAGES.indexOf(pathname) !== -1)
|
return (BLOCKED_PAGES.indexOf(pathname) !== -1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ const args = arg({
|
||||||
// Types
|
// Types
|
||||||
'--help': Boolean,
|
'--help': Boolean,
|
||||||
// Aliases
|
// Aliases
|
||||||
'-h': '--help'
|
'-h': '--help',
|
||||||
})
|
})
|
||||||
|
|
||||||
if (args['--help']) {
|
if (args['--help']) {
|
||||||
|
@ -45,6 +45,7 @@ if (!existsSync(join(dir, 'pages'))) {
|
||||||
|
|
||||||
build(dir)
|
build(dir)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.error('> Build error occurred')
|
console.error('> Build error occurred')
|
||||||
printAndExit(err)
|
printAndExit(err)
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,10 +14,11 @@ const args = arg({
|
||||||
// Aliases
|
// Aliases
|
||||||
'-h': '--help',
|
'-h': '--help',
|
||||||
'-p': '--port',
|
'-p': '--port',
|
||||||
'-H': '--hostname'
|
'-H': '--hostname',
|
||||||
})
|
})
|
||||||
|
|
||||||
if (args['--help']) {
|
if (args['--help']) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log(`
|
console.log(`
|
||||||
Description
|
Description
|
||||||
Starts the application in development mode (hot-code reloading, error
|
Starts the application in development mode (hot-code reloading, error
|
||||||
|
@ -56,6 +57,7 @@ if (!existsSync(join(dir, 'pages'))) {
|
||||||
const port = args['--port'] || 3000
|
const port = args['--port'] || 3000
|
||||||
startServer({dir, dev: true}, port, args['--hostname'])
|
startServer({dir, dev: true}, port, args['--hostname'])
|
||||||
.then(async (app) => {
|
.then(async (app) => {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log(`> Ready on http://${args['--hostname'] || 'localhost'}:${port}`)
|
console.log(`> Ready on http://${args['--hostname'] || 'localhost'}:${port}`)
|
||||||
await app.prepare()
|
await app.prepare()
|
||||||
})
|
})
|
||||||
|
@ -63,18 +65,19 @@ startServer({dir, dev: true}, port, args['--hostname'])
|
||||||
if (err.code === 'EADDRINUSE') {
|
if (err.code === 'EADDRINUSE') {
|
||||||
let errorMessage = `Port ${port} is already in use.`
|
let errorMessage = `Port ${port} is already in use.`
|
||||||
const pkgAppPath = require('find-up').sync('package.json', {
|
const pkgAppPath = require('find-up').sync('package.json', {
|
||||||
cwd: dir
|
cwd: dir,
|
||||||
})
|
})
|
||||||
const appPackage = require(pkgAppPath)
|
const appPackage = require(pkgAppPath)
|
||||||
if (appPackage.scripts) {
|
if (appPackage.scripts) {
|
||||||
const nextScript = Object.entries(appPackage.scripts).find(scriptLine => scriptLine[1] === 'next')
|
const nextScript = Object.entries(appPackage.scripts).find((scriptLine) => scriptLine[1] === 'next')
|
||||||
if (nextScript) {
|
if (nextScript) {
|
||||||
errorMessage += `\nUse \`npm run ${nextScript[0]} -- -p <some other port>\`.`
|
errorMessage += `\nUse \`npm run ${nextScript[0]} -- -p <some other port>\`.`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// tslint:disable-next-line
|
||||||
console.error(errorMessage)
|
console.error(errorMessage)
|
||||||
} else {
|
} else {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
process.nextTick(() => process.exit(1))
|
process.nextTick(() => process.exit(1))
|
||||||
|
|
|
@ -16,10 +16,11 @@ const args = arg({
|
||||||
// Aliases
|
// Aliases
|
||||||
'-h': '--help',
|
'-h': '--help',
|
||||||
'-s': '--silent',
|
'-s': '--silent',
|
||||||
'-o': '--outdir'
|
'-o': '--outdir',
|
||||||
})
|
})
|
||||||
|
|
||||||
if (args['--help']) {
|
if (args['--help']) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log(`
|
console.log(`
|
||||||
Description
|
Description
|
||||||
Exports the application for production deployment
|
Exports the application for production deployment
|
||||||
|
@ -57,7 +58,7 @@ const options = {
|
||||||
silent: args['--silent'] || false,
|
silent: args['--silent'] || false,
|
||||||
threads: args['--threads'],
|
threads: args['--threads'],
|
||||||
concurrency: args['--concurrency'],
|
concurrency: args['--concurrency'],
|
||||||
outdir: args['--outdir'] ? resolve(args['--outdir']) : join(dir, 'out')
|
outdir: args['--outdir'] ? resolve(args['--outdir']) : join(dir, 'out'),
|
||||||
}
|
}
|
||||||
|
|
||||||
exportApp(dir, options)
|
exportApp(dir, options)
|
||||||
|
|
|
@ -13,10 +13,11 @@ const args = arg({
|
||||||
// Aliases
|
// Aliases
|
||||||
'-h': '--help',
|
'-h': '--help',
|
||||||
'-p': '--port',
|
'-p': '--port',
|
||||||
'-H': '--hostname'
|
'-H': '--hostname',
|
||||||
})
|
})
|
||||||
|
|
||||||
if (args['--help']) {
|
if (args['--help']) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log(`
|
console.log(`
|
||||||
Description
|
Description
|
||||||
Starts the application in production mode.
|
Starts the application in production mode.
|
||||||
|
@ -42,10 +43,12 @@ const dir = resolve(args._[0] || '.')
|
||||||
const port = args['--port'] || 3000
|
const port = args['--port'] || 3000
|
||||||
startServer({dir}, port, args['--hostname'])
|
startServer({dir}, port, args['--hostname'])
|
||||||
.then(async (app) => {
|
.then(async (app) => {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log(`> Ready on http://${args['--hostname']}:${port}`)
|
console.log(`> Ready on http://${args['--hostname']}:${port}`)
|
||||||
await app.prepare()
|
await app.prepare()
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.error(err)
|
console.error(err)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,11 +3,12 @@ import { join } from 'path'
|
||||||
import spawn from 'cross-spawn'
|
import spawn from 'cross-spawn'
|
||||||
import arg from 'arg'
|
import arg from 'arg'
|
||||||
|
|
||||||
['react', 'react-dom'].forEach(dependency => {
|
['react', 'react-dom'].forEach((dependency) => {
|
||||||
try {
|
try {
|
||||||
// When 'npm link' is used it checks the clone location. Not the project.
|
// When 'npm link' is used it checks the clone location. Not the project.
|
||||||
require.resolve(dependency)
|
require.resolve(dependency)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.warn(`The module '${dependency}' was not found. Next.js requires that you include it in 'dependencies' of your 'package.json'. To add it, run 'npm install --save ${dependency}'`)
|
console.warn(`The module '${dependency}' was not found. Next.js requires that you include it in 'dependencies' of your 'package.json'. To add it, run 'npm install --save ${dependency}'`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -17,7 +18,7 @@ const commands = [
|
||||||
'build',
|
'build',
|
||||||
'start',
|
'start',
|
||||||
'export',
|
'export',
|
||||||
defaultCommand
|
defaultCommand,
|
||||||
]
|
]
|
||||||
|
|
||||||
const args = arg({
|
const args = arg({
|
||||||
|
@ -28,34 +29,36 @@ const args = arg({
|
||||||
|
|
||||||
// Aliases
|
// Aliases
|
||||||
'-v': '--version',
|
'-v': '--version',
|
||||||
'-h': '--help'
|
'-h': '--help',
|
||||||
}, {
|
}, {
|
||||||
permissive: true
|
permissive: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Version is inlined into the file using taskr build pipeline
|
// Version is inlined into the file using taskr build pipeline
|
||||||
if (args['--version']) {
|
if (args['--version']) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log(`Next.js v${process.env.NEXT_VERSION}`)
|
console.log(`Next.js v${process.env.NEXT_VERSION}`)
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we are running `next <subcommand>` or `next`
|
// Check if we are running `next <subcommand>` or `next`
|
||||||
const foundCommand = args._.find(cmd => commands.includes(cmd))
|
const foundCommand = args._.find((cmd) => commands.includes(cmd))
|
||||||
|
|
||||||
// Makes sure the `next <subcommand> --help` case is covered
|
// Makes sure the `next <subcommand> --help` case is covered
|
||||||
// This help message is only showed for `next --help`
|
// This help message is only showed for `next --help`
|
||||||
if (!foundCommand && args['--help']) {
|
if (!foundCommand && args['--help']) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log(`
|
console.log(`
|
||||||
Usage
|
Usage
|
||||||
$ next <command>
|
$ next <command>
|
||||||
|
|
||||||
Available commands
|
Available commands
|
||||||
${commands.join(', ')}
|
${commands.join(', ')}
|
||||||
|
|
||||||
Options
|
Options
|
||||||
--version, -p Version number
|
--version, -p Version number
|
||||||
--inspect Enable the Node.js inspector
|
--inspect Enable the Node.js inspector
|
||||||
--help, -h Displays this message
|
--help, -h Displays this message
|
||||||
|
|
||||||
For more information run a command with the --help flag
|
For more information run a command with the --help flag
|
||||||
$ next build --help
|
$ next build --help
|
||||||
|
@ -65,12 +68,13 @@ if (!foundCommand && args['--help']) {
|
||||||
|
|
||||||
const nodeArguments: string[] = []
|
const nodeArguments: string[] = []
|
||||||
if (args['--inspect']) {
|
if (args['--inspect']) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log('Passing "--inspect" to Node.js')
|
console.log('Passing "--inspect" to Node.js')
|
||||||
nodeArguments.push('--inspect')
|
nodeArguments.push('--inspect')
|
||||||
}
|
}
|
||||||
|
|
||||||
const command = foundCommand || defaultCommand
|
const command = foundCommand || defaultCommand
|
||||||
const forwardedArgs = args._.filter(arg => arg !== command)
|
const forwardedArgs = args._.filter((arg) => arg !== command)
|
||||||
|
|
||||||
// Make sure the `next <subcommand> --help` case is covered
|
// Make sure the `next <subcommand> --help` case is covered
|
||||||
if (args['--help']) {
|
if (args['--help']) {
|
||||||
|
@ -92,12 +96,14 @@ const startProcess = () => {
|
||||||
if (signal === 'SIGKILL') {
|
if (signal === 'SIGKILL') {
|
||||||
process.exit(137)
|
process.exit(137)
|
||||||
}
|
}
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log(`got signal ${signal}, exiting`)
|
console.log(`got signal ${signal}, exiting`)
|
||||||
process.exit(signal === 'SIGINT' ? 0 : 1)
|
process.exit(signal === 'SIGINT' ? 0 : 1)
|
||||||
}
|
}
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
})
|
})
|
||||||
proc.on('error', (err) => {
|
proc.on('error', (err) => {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.error(err)
|
console.error(err)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
})
|
})
|
||||||
|
@ -106,7 +112,7 @@ const startProcess = () => {
|
||||||
|
|
||||||
let proc = startProcess()
|
let proc = startProcess()
|
||||||
|
|
||||||
function wrapper () {
|
function wrapper() {
|
||||||
if (proc) {
|
if (proc) {
|
||||||
proc.kill()
|
proc.kill()
|
||||||
}
|
}
|
||||||
|
@ -121,6 +127,7 @@ if (command === 'dev') {
|
||||||
const {watchFile} = require('fs')
|
const {watchFile} = require('fs')
|
||||||
watchFile(`${process.cwd()}/${CONFIG_FILE}`, (cur: any, prev: any) => {
|
watchFile(`${process.cwd()}/${CONFIG_FILE}`, (cur: any, prev: any) => {
|
||||||
if (cur.size > 0 || prev.size > 0) {
|
if (cur.size > 0 || prev.size > 0) {
|
||||||
|
// tslint:disable-next-line
|
||||||
console.log(`\n> Found a change in ${CONFIG_FILE}, restarting the server...`)
|
console.log(`\n> Found a change in ${CONFIG_FILE}, restarting the server...`)
|
||||||
// Don't listen to 'close' now since otherwise parent gets killed by listener
|
// Don't listen to 'close' now since otherwise parent gets killed by listener
|
||||||
proc.removeAllListeners('close')
|
proc.removeAllListeners('close')
|
||||||
|
|
30
tslint.json
Normal file
30
tslint.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"defaultSeverity": "error",
|
||||||
|
"extends": [
|
||||||
|
"tslint:recommended"
|
||||||
|
],
|
||||||
|
"jsRules": {},
|
||||||
|
"rules": {
|
||||||
|
"curly": false,
|
||||||
|
"no-empty": false,
|
||||||
|
"object-literal-sort-keys": false,
|
||||||
|
"variable-name": false,
|
||||||
|
"max-line-length": false,
|
||||||
|
"interface-over-type-literal": false,
|
||||||
|
"no-shadowed-variable": false,
|
||||||
|
"no-var-requires": false,
|
||||||
|
"semicolon": false,
|
||||||
|
"quotemark": false,
|
||||||
|
"ordered-imports": false,
|
||||||
|
"member-access": false,
|
||||||
|
"member-ordering": false
|
||||||
|
},
|
||||||
|
"rulesDirectory": [],
|
||||||
|
"linterOptions": {
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**",
|
||||||
|
"**/build/**",
|
||||||
|
"**/types/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue