diff --git a/.github/ISSUE_TEMPLATE/1.Bug_report.md b/.github/ISSUE_TEMPLATE/1.Bug_report.md index 6172fe14ec482..6c10e9edc66b8 100644 --- a/.github/ISSUE_TEMPLATE/1.Bug_report.md +++ b/.github/ISSUE_TEMPLATE/1.Bug_report.md @@ -12,21 +12,25 @@ A clear and concise description of what the bug is. ## To Reproduce Steps to reproduce the behavior, please provide code snippets or a repository: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error ## Expected behavior + A clear and concise description of what you expected to happen. ## Screenshots + If applicable, add screenshots to help explain your problem. ## System information - - OS: [e.g. macOS, Windows] - - Browser (if applies) [e.g. chrome, safari] - - Version of Next.js: [e.g. 6.0.2] + +- OS: [e.g. macOS, Windows] +- Browser (if applies) [e.g. chrome, safari] +- Version of Next.js: [e.g. 6.0.2] ## Additional context diff --git a/.github/ISSUE_TEMPLATE/2.Feature_request.md b/.github/ISSUE_TEMPLATE/2.Feature_request.md index 6d6da1091c57d..92a257d1a7e80 100644 --- a/.github/ISSUE_TEMPLATE/2.Feature_request.md +++ b/.github/ISSUE_TEMPLATE/2.Feature_request.md @@ -6,13 +6,17 @@ about: Create a feature request for the Next.js core # Feature request ## Is your feature request related to a problem? Please describe. + A clear and concise description of what you want and what your use case is. ## Describe the solution you'd like + A clear and concise description of what you want to happen. ## Describe alternatives you've considered + A clear and concise description of any alternative solutions or features you've considered. ## Additional context + Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/3.Example_Bug_report.md b/.github/ISSUE_TEMPLATE/3.Example_Bug_report.md index be1f0d71892d1..a1640aee8e591 100644 --- a/.github/ISSUE_TEMPLATE/3.Example_Bug_report.md +++ b/.github/ISSUE_TEMPLATE/3.Example_Bug_report.md @@ -6,28 +6,35 @@ about: Create a bug report for one of the Next.js examples # Examples bug report ## Example name + Provide the example name ## Describe the bug + A clear and concise description of what the bug is. ## To Reproduce + Steps to reproduce the behavior, please provide code snippets or a repository: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error ## Expected behavior + A clear and concise description of what you expected to happen. ## Screenshots + If applicable, add screenshots to help explain your problem. ## System information - - OS: [e.g. macOS, Windows] - - Browser (if applies) [e.g. chrome, safari] - - Version of Next.js: [e.g. 6.0.2] + +- OS: [e.g. macOS, Windows] +- Browser (if applies) [e.g. chrome, safari] +- Version of Next.js: [e.g. 6.0.2] ## Additional context diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 09c934f1b8947..f264ef949da55 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,28 +1,28 @@ ## Code of Conduct - ### Our Pledge +### Our Pledge - In the interest of fostering an open and welcoming environment, we as +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - ### Our Standards +### Our Standards - Examples of behavior that contributes to creating a positive environment +Examples of behavior that contributes to creating a positive environment include: - - Using welcoming and inclusive language +- Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members - Examples of unacceptable behavior by participants include: +Examples of unacceptable behavior by participants include: - - The use of sexualized language or imagery and unwelcome sexual attention or +- The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment @@ -31,44 +31,44 @@ include: - Other conduct which could reasonably be considered inappropriate in a professional setting - ### Our Responsibilities +### Our Responsibilities - Project maintainers are responsible for clarifying the standards of acceptable +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - Project maintainers have the right and responsibility to remove, edit, or +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - ### Scope +### Scope - This Code of Conduct applies both within project spaces and in public spaces +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - ### Enforcement +### Enforcement - Instances of abusive, harassing, or otherwise unacceptable behavior may be +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [abuse@zeit.co](mailto:abuse@zeit.co). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - Project maintainers who do not follow or enforce the Code of Conduct in good +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - ### Attribution +### Attribution - This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] - [homepage]: http://contributor-covenant.org +[homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ diff --git a/README-zh-CN.md b/README-zh-CN.md index d617f60e8cb13..c306a19ad0f62 100644 --- a/README-zh-CN.md +++ b/README-zh-CN.md @@ -113,7 +113,7 @@ npm install --save next react react-dom 新建 `./pages/index.js` 到你的项目中: ```jsx -export default () =>
Welcome to next.js!
; +export default () =>
Welcome to next.js!
``` 运行 `npm run dev` 命令并打开 `http://localhost:3000`。 要使用其他端口,你可以运行 `npm run dev -- -p `. @@ -134,9 +134,9 @@ export default () =>
Welcome to next.js!
; 每个页面只会导入`import`中绑定以及被用到的代码. 这意味着页面不会加载不必要的代码 ```jsx -import cowsay from "cowsay-browser"; +import cowsay from 'cowsay-browser' -export default () =>
{cowsay.say({ text: "hi there!" })}
; +export default () =>
{cowsay.say({ text: 'hi there!' })}
``` @@ -178,7 +178,7 @@ export default () => ( } `} -); +) ``` 想查看更多案例可以点击 [styled-jsx documentation](https://www.npmjs.com/package/styled-jsx). @@ -197,7 +197,7 @@ export default () => ( 有些情况可以使用 CSS 内嵌 JS 写法。如下所示: ```jsx -export default () =>

hi there

; +export default () =>

hi there

``` 更复杂的内嵌样式解决方案,特别是服务端渲染时的样式更改。我们可以通过包裹自定义 Document,来添加样式,案例如下:[custom ``](#user-content-custom-document) @@ -220,7 +220,7 @@ export default () =>

hi there

; 在根目录下新建文件夹叫`static`。代码可以通过`/static/`来引入相关的静态资源。 ```jsx -export default () => my image; +export default () => my image ``` _注意:不要自定义静态文件夹的名字,只能叫`static` ,因为只有这个名字 Next.js 才会把它当作静态资源。_ @@ -242,7 +242,7 @@ _注意:不要自定义静态文件夹的名字,只能叫`static` ,因为 我们设置一个内置组件来装载``到页面中。 ```jsx -import Head from "next/head"; +import Head from 'next/head' export default () => (
@@ -252,13 +252,13 @@ export default () => (

Hello world!

-); +) ``` 我们定义`key`属性来避免重复的``标签,保证``只渲染一次,如下所示: ```jsx -import Head from "next/head"; +import Head from 'next/head' export default () => (
@@ -278,7 +278,7 @@ export default () => (

Hello world!

-); +) ``` 只有第二个``才被渲染。 @@ -297,16 +297,16 @@ _注意:在卸载组件时,``的内容将被清除。请确保每个 当你需要状态,生命周期钩子或初始数据填充时,你可以导出`React.Component`(而不是上面的无状态函数),如下所示: ```jsx -import React from "react"; +import React from 'react' export default class extends React.Component { static async getInitialProps({ req }) { - const userAgent = req ? req.headers["user-agent"] : navigator.userAgent; - return { userAgent }; + const userAgent = req ? req.headers['user-agent'] : navigator.userAgent + return { userAgent } } render() { - return
Hello World {this.props.userAgent}
; + return
Hello World {this.props.userAgent}
} } ``` @@ -331,15 +331,15 @@ export default class extends React.Component { 你也可以给无状态组件定义`getInitialProps`: ```jsx -const Page = ({ stars }) =>
Next stars: {stars}
; +const Page = ({ stars }) =>
Next stars: {stars}
Page.getInitialProps = async ({ req }) => { - const res = await fetch("https://api.github.com/repos/zeit/next.js"); - const json = await res.json(); - return { stars: json.stargazers_count }; -}; + const res = await fetch('https://api.github.com/repos/zeit/next.js') + const json = await res.json() + return { stars: json.stargazers_count } +} -export default Page; +export default Page ``` `getInitialProps`入参对象的属性如下: @@ -356,7 +356,7 @@ export default Page; ### 路由 -Next.js不会随应用程序中每个可能的路由一起发布路由清单,因此当前页面不知道客户端上的任何其他页面。出于可扩展性考虑,所有后续路由都会惰性加载。 +Next.js 不会随应用程序中每个可能的路由一起发布路由清单,因此当前页面不知道客户端上的任何其他页面。出于可扩展性考虑,所有后续路由都会惰性加载。 @@ -403,12 +403,12 @@ function About() { export default About ``` -**自定义路由 (使用URL中的props)** +**自定义路由 (使用 URL 中的 props)** `` 组件有两个主要属性: - `href`: `pages`目录内的路径+查询字符串. -- `as`: 将在浏览器URL栏中呈现的路径. +- `as`: 将在浏览器 URL 栏中呈现的路径. 例子: @@ -430,7 +430,7 @@ class Post extends React.Component { export default Post ``` -3. 将路由添加到 `express` (或者其他服务端) 的 `server.js` 文件 (这仅适用于SSR). 这将解析`/post/:slug`到`pages/post.js`并在getInitialProps中提供`slug`作为查询的一部分。 +3. 将路由添加到 `express` (或者其他服务端) 的 `server.js` 文件 (这仅适用于 SSR). 这将解析`/post/:slug`到`pages/post.js`并在 getInitialProps 中提供`slug`作为查询的一部分。 ```jsx server.get('/post/:slug', (req, res) => { @@ -439,6 +439,7 @@ server.get('/post/:slug', (req, res) => { ``` 4. 对于客户端路由,使用 `next/link`: + ```jsx ``` @@ -468,17 +469,17 @@ _注意:可以使用[``](#prefetching-pages)使链接和预加 ```jsx // pages/index.js -import Link from "next/link"; +import Link from 'next/link' export default () => (
- Click{" "} - + Click{' '} + here - {" "} + {' '} to read more
-); +) ``` 将生成 URL 字符串`/about?name=Zeit`,你可以使用任何在[Node.js URL module documentation](https://nodejs.org/api/url.html#url_url_strings_and_url_objects)定义过的属性。 @@ -491,17 +492,17 @@ export default () => ( ```jsx // pages/index.js -import Link from "next/link"; +import Link from 'next/link' export default () => (
- Click{" "} + Click{' '} here - {" "} + {' '} to read more
-); +) ``` @@ -512,16 +513,16 @@ export default () => ( ```jsx // pages/index.js -import Link from "next/link"; +import Link from 'next/link' export default () => (
- Click{" "} + Click{' '} image
-); +) ``` @@ -533,14 +534,14 @@ export default () => ( **注意**: 使用`a`之外的标签而且没有通过`passHref`的链接可能会使导航看上去正确,但是当搜索引擎爬行检测时,将不会识别成链接(由于缺乏 href 属性),这会对你网站的 SEO 产生负面影响。 ```jsx -import Link from "next/link"; -import Unexpected_A from "third-library"; +import Link from 'next/link' +import Unexpected_A from 'third-library' export default ({ href, name }) => ( {name} -); +) ``` @@ -570,13 +571,13 @@ export default ({ href, name }) => ( 你也可以用`next/router`实现客户端路由切换 ```jsx -import Router from "next/router"; +import Router from 'next/router' export default () => (
- Click Router.push("/about")}>here to read more + Click Router.push('/about')}>here to read more
-); +) ``` @@ -587,18 +588,18 @@ export default () => ( 比如,你可以操作 request 或强制 SSR 刷新 ```jsx -import Router from "next/router"; +import Router from 'next/router' Router.beforePopState(({ url, as, options }) => { // I only want to allow these two routes! - if (as !== "/" || as !== "/other") { + if (as !== '/' || as !== '/other') { // Have SSR render bad routes as a 404. - window.location.href = as; - return false; + window.location.href = as + return false } - return true; -}); + return true +}) ``` 如果你在`beforePopState`中返回 false,`Router`将不会执行`popstate`事件。 @@ -610,8 +611,8 @@ Router.beforePopState(({ url, as, options }) => { - `pathname` - 不包含查询内容的当前路径,为`String`类型 - `query` - 查询内容,被解析成`Object`类型. 默认为`{}` - `asPath` - 展现在浏览器上的实际路径,包含查询内容,为`String`类型 -- `push(url, as=url)` - 用给定的url调用`pushState` -- `replace(url, as=url)` - 用给定的url调用`replaceState` +- `push(url, as=url)` - 用给定的 url 调用`pushState` +- `replace(url, as=url)` - 用给定的 url 调用`replaceState` - `beforePopState(cb=function)` - 在路由器处理事件之前拦截. `push` 和 `replace` 函数的第二个参数`as`,是为了装饰 URL 作用。如果你在服务器端设置了自定义路由将会起作用。 @@ -623,19 +624,19 @@ Router.beforePopState(({ url, as, options }) => { `push` 或 `replace`可接收的 URL 对象(``组件的 URL 对象一样)来生成 URL。 ```jsx -import Router from "next/router"; +import Router from 'next/router' const handler = () => Router.push({ - pathname: "/about", - query: { name: "Zeit" } - }); + pathname: '/about', + query: { name: 'Zeit' }, + }) export default () => (
Click here to read more
-); +) ``` 也可以像``组件一样添加额外的参数。 @@ -660,26 +661,26 @@ export default () => ( ```js const handleRouteChange = url => { - console.log("App is changing to: ", url); -}; + console.log('App is changing to: ', url) +} -Router.events.on("routeChangeStart", handleRouteChange); +Router.events.on('routeChangeStart', handleRouteChange) ``` 如果你不想再监听该事件,你可以用`off`事件去取消监听: ```js -Router.events.off("routeChangeStart", handleRouteChange); +Router.events.off('routeChangeStart', handleRouteChange) ``` -如果路由加载被取消(比如快速连续双击链接),`routeChangeError`将触发。传递err,并且属性cancelled的值为true。 +如果路由加载被取消(比如快速连续双击链接),`routeChangeError`将触发。传递 err,并且属性 cancelled 的值为 true。 ```js -Router.events.on("routeChangeError", (err, url) => { +Router.events.on('routeChangeError', (err, url) => { if (err.cancelled) { - console.log(`Route to ${url} was cancelled!`); + console.log(`Route to ${url} was cancelled!`) } -}); +}) ``` @@ -699,9 +700,9 @@ Router.events.on("routeChangeError", (err, url) => { ```js // Current URL is "/" -const href = "/?counter=10"; -const as = href; -Router.push(href, as, { shallow: true }); +const href = '/?counter=10' +const as = href +Router.push(href, as, { shallow: true }) ``` 现在 URL 更新为`/?counter=10`。在组件里查看`this.props.router.query`你将会看到更新的 URL。 @@ -723,7 +724,7 @@ componentDidUpdate(prevProps) { > 浅层路由只作用于相同 URL 的参数改变,比如我们假定有个其他路由`about`,而你向下面代码样运行: > > ```js -> Router.push("/?counter=10", "/about?counter=10", { shallow: true }); +> Router.push('/?counter=10', '/about?counter=10', { shallow: true }) > ``` > > 那么这将会出现新页面,即使我们加了浅层路由,但是它还是会卸载当前页,会加载新的页面并触发新页面的`getInitialProps`。 @@ -742,27 +743,27 @@ componentDidUpdate(prevProps) { 如果你想应用里每个组件都处理路由对象,你可以使用`withRouter`高阶组件。下面是如何使用它: ```jsx -import { withRouter } from "next/router"; +import { withRouter } from 'next/router' const ActiveLink = ({ children, router, href }) => { const style = { marginRight: 10, - color: router.pathname === href ? "red" : "black" - }; + color: router.pathname === href ? 'red' : 'black', + } const handleClick = e => { - e.preventDefault(); - router.push(href); - }; + e.preventDefault() + router.push(href) + } return ( {children} - ); -}; + ) +} -export default withRouter(ActiveLink); +export default withRouter(ActiveLink) ``` 上面路由对象的 API 可以参考[`next/router`](#imperatively). @@ -791,7 +792,7 @@ Next.js 有允许你预加载页面的 API。 你可以给添加 `prefetch` 属性,Next.js 将会在后台预加载这些页面。 ```jsx -import Link from "next/link"; +import Link from 'next/link' // example header component export default () => ( @@ -814,7 +815,7 @@ export default () => ( -); +) ``` @@ -824,44 +825,44 @@ export default () => ( 大多数预加载是通过处理的,但是我们还提供了命令式 API 用于更复杂的场景。 ```jsx -import { withRouter } from "next/router"; +import { withRouter } from 'next/router' export default withRouter(({ router }) => (
- setTimeout(() => router.push("/dynamic"), 100)}> + setTimeout(() => router.push('/dynamic'), 100)}> A route transition will happen after 100ms {// but we can prefetch it! - router.prefetch("/dynamic")} + router.prefetch('/dynamic')}
-)); +)) ``` 路由实例只允许在应用程序的客户端。以防服务端渲染发生错误,建议 prefetch 事件写在`componentDidMount()`生命周期里。 ```jsx -import React from "react"; -import { withRouter } from "next/router"; +import React from 'react' +import { withRouter } from 'next/router' class MyLink extends React.Component { componentDidMount() { - const { router } = this.props; - router.prefetch("/dynamic"); + const { router } = this.props + router.prefetch('/dynamic') } render() { - const { router } = this.props; + const { router } = this.props return (
- setTimeout(() => router.push("/dynamic"), 100)}> + setTimeout(() => router.push('/dynamic'), 100)}> A route transition will happen after 100ms
- ); + ) } } -export default withRouter(MyLink); +export default withRouter(MyLink) ``` @@ -900,33 +901,33 @@ export default withRouter(MyLink); // This file doesn't go through babel or webpack transformation. // Make sure the syntax and sources this file requires are compatible with the current node version you are running // See https://github.com/zeit/next.js/issues/1245 for discussions on Universal Webpack or universal Babel -const { createServer } = require("http"); -const { parse } = require("url"); -const next = require("next"); +const { createServer } = require('http') +const { parse } = require('url') +const next = require('next') -const dev = process.env.NODE_ENV !== "production"; -const app = next({ dev }); -const handle = app.getRequestHandler(); +const dev = process.env.NODE_ENV !== 'production' +const app = next({ dev }) +const handle = app.getRequestHandler() app.prepare().then(() => { createServer((req, res) => { // Be sure to pass `true` as the second argument to `url.parse`. // This tells it to parse the query portion of the URL. - const parsedUrl = parse(req.url, true); - const { pathname, query } = parsedUrl; + const parsedUrl = parse(req.url, true) + const { pathname, query } = parsedUrl - if (pathname === "/a") { - app.render(req, res, "/b", query); - } else if (pathname === "/b") { - app.render(req, res, "/a", query); + if (pathname === '/a') { + app.render(req, res, '/b', query) + } else if (pathname === '/b') { + app.render(req, res, '/a', query) } else { - handle(req, res, parsedUrl); + handle(req, res, parsedUrl) } }).listen(3000, err => { - if (err) throw err; - console.log("> Ready on http://localhost:3000"); - }); -}); + if (err) throw err + console.log('> Ready on http://localhost:3000') + }) +}) ``` `next`的 API 如下所示 @@ -955,8 +956,8 @@ opts 的属性如下: ```js // next.config.js module.exports = { - useFileSystemPublicRoutes: false -}; + useFileSystemPublicRoutes: false, +} ``` 注意`useFileSystemPublicRoutes`只禁止服务端的文件路由;但是客户端的还是禁止不了。 @@ -972,33 +973,33 @@ module.exports = { 使用方法如下: ```js -const next = require("next"); -const micro = require("micro"); +const next = require('next') +const micro = require('micro') -const dev = process.env.NODE_ENV !== "production"; -const app = next({ dev }); -const handleNextRequests = app.getRequestHandler(); +const dev = process.env.NODE_ENV !== 'production' +const app = next({ dev }) +const handleNextRequests = app.getRequestHandler() app.prepare().then(() => { const server = micro((req, res) => { // Add assetPrefix support based on the hostname - if (req.headers.host === "my-app.com") { - app.setAssetPrefix("http://cdn.com/myapp"); + if (req.headers.host === 'my-app.com') { + app.setAssetPrefix('http://cdn.com/myapp') } else { - app.setAssetPrefix(""); + app.setAssetPrefix('') } - handleNextRequests(req, res); - }); + handleNextRequests(req, res) + }) server.listen(port, err => { if (err) { - throw err; + throw err } - console.log(`> Ready on http://localhost:${port}`); - }); -}); + console.log(`> Ready on http://localhost:${port}`) + }) +}) ``` @@ -1020,12 +1021,12 @@ ext.js 支持 JavaScript 的 TC39 提议[dynamic import proposal](https://github -#### 1. 基础用法 (也就是SSR) +#### 1. 基础用法 (也就是 SSR) ```jsx -import dynamic from "next/dynamic"; +import dynamic from 'next/dynamic' -const DynamicComponent = dynamic(import("../components/hello")); +const DynamicComponent = dynamic(import('../components/hello')) export default () => (
@@ -1033,7 +1034,7 @@ export default () => (

HOME PAGE is here!

-); +) ``` @@ -1041,14 +1042,14 @@ export default () => ( #### 2. 自定义加载组件 ```jsx -import dynamic from "next/dynamic"; +import dynamic from 'next/dynamic' const DynamicComponentWithCustomLoading = dynamic( - import("../components/hello2"), + import('../components/hello2'), { - loading: () =>

...

+ loading: () =>

...

, } -); +) export default () => (
@@ -1056,7 +1057,7 @@ export default () => (

HOME PAGE is here!

-); +) ``` @@ -1064,11 +1065,11 @@ export default () => ( #### 3. 禁止使用 SSR ```jsx -import dynamic from "next/dynamic"; +import dynamic from 'next/dynamic' -const DynamicComponentWithNoSSR = dynamic(import("../components/hello3"), { - ssr: false -}); +const DynamicComponentWithNoSSR = dynamic(import('../components/hello3'), { + ssr: false, +}) export default () => (
@@ -1076,7 +1077,7 @@ export default () => (

HOME PAGE is here!

-); +) ``` @@ -1084,16 +1085,16 @@ export default () => ( #### 4. 同时加载多个模块 ```jsx -import dynamic from "next/dynamic"; +import dynamic from 'next/dynamic' const HelloBundle = dynamic({ modules: () => { const components = { - Hello1: import("../components/hello1"), - Hello2: import("../components/hello2") - }; + Hello1: import('../components/hello1'), + Hello2: import('../components/hello2'), + } - return components; + return components }, render: (props, { Hello1, Hello2 }) => (
@@ -1101,10 +1102,10 @@ const HelloBundle = dynamic({
- ) -}); + ), +}) -export default () => ; +export default () => ``` @@ -1127,27 +1128,27 @@ export default () => ; 重写的话,新建`./pages/_app.js`文件,重写 App 模块如下所示: ```js -import App, { Container } from "next/app"; -import React from "react"; +import App, { Container } from 'next/app' +import React from 'react' export default class MyApp extends App { static async getInitialProps({ Component, router, ctx }) { - let pageProps = {}; + let pageProps = {} if (Component.getInitialProps) { - pageProps = await Component.getInitialProps(ctx); + pageProps = await Component.getInitialProps(ctx) } - return { pageProps }; + return { pageProps } } render() { - const { Component, pageProps } = this.props; + const { Component, pageProps } = this.props return ( - ); + ) } } ``` @@ -1173,12 +1174,12 @@ export default class MyApp extends App { // Event handlers like onClick can't be added to this file // ./pages/_document.js -import Document, { Head, Main, NextScript } from "next/document"; +import Document, { Head, Main, NextScript } from 'next/document' export default class MyDocument extends Document { static async getInitialProps(ctx) { - const initialProps = await Document.getInitialProps(ctx); - return { ...initialProps }; + const initialProps = await Document.getInitialProps(ctx) + return { ...initialProps } } render() { @@ -1192,7 +1193,7 @@ export default class MyDocument extends Document { - ); + ) } } ``` @@ -1207,7 +1208,7 @@ export default class MyDocument extends Document { #### 自定义 `renderPage` -🚧 应该注意的是,您应该定制“renderPage”的唯一原因是使用css-in-js库,需要将应用程序包装起来以正确使用服务端渲染。 🚧 +🚧 应该注意的是,您应该定制“renderPage”的唯一原因是使用 css-in-js 库,需要将应用程序包装起来以正确使用服务端渲染。 🚧 - 它将一个选项对象作为参数进行进一步的自定义: @@ -1223,7 +1224,7 @@ class MyDocument extends Document { // useful for wrapping the whole react tree enhanceApp: App => App, // useful for wrapping in a per-page basis - enhanceComponent: Component => Component + enhanceComponent: Component => Component, }) // Run the parent `getInitialProps` using `ctx` that now includes our custom `renderPage` @@ -1236,7 +1237,6 @@ class MyDocument extends Document { export default MyDocument ``` - ### 自定义错误处理 404 和 500 错误客户端和服务端都会通过`error.js`组件处理。如果你想改写它,则新建`_error.js`在文件夹中: @@ -1244,12 +1244,12 @@ export default MyDocument ⚠️ 该`pages/_error.js`组件仅用于生产。在开发过程中,您会收到调用堆栈错误,以了解错误源自何处。 ⚠️ ```jsx -import React from "react"; +import React from 'react' export default class Error extends React.Component { static getInitialProps({ res, err }) { - const statusCode = res ? res.statusCode : err ? err.statusCode : null; - return { statusCode }; + const statusCode = res ? res.statusCode : err ? err.statusCode : null + return { statusCode } } render() { @@ -1257,9 +1257,9 @@ export default class Error extends React.Component {

{this.props.statusCode ? `An error ${this.props.statusCode} occurred on server` - : "An error occurred on client"} + : 'An error occurred on client'}

- ); + ) } } ``` @@ -1271,25 +1271,25 @@ export default class Error extends React.Component { 如果你想渲染内置错误页面,你可以使用`next/error`: ```jsx -import React from "react"; -import Error from "next/error"; -import fetch from "isomorphic-unfetch"; +import React from 'react' +import Error from 'next/error' +import fetch from 'isomorphic-unfetch' export default class Page extends React.Component { static async getInitialProps() { - const res = await fetch("https://api.github.com/repos/zeit/next.js"); - const statusCode = res.statusCode > 200 ? res.statusCode : false; - const json = await res.json(); + const res = await fetch('https://api.github.com/repos/zeit/next.js') + const statusCode = res.statusCode > 200 ? res.statusCode : false + const json = await res.json() - return { statusCode, stars: json.stargazers_count }; + return { statusCode, stars: json.stargazers_count } } render() { if (this.props.statusCode) { - return ; + return } - return
Next stars: {this.props.stars}
; + return
Next stars: {this.props.stars}
} } ``` @@ -1308,7 +1308,7 @@ export default class Page extends React.Component { // next.config.js module.exports = { /* config options here */ -}; +} ``` 或使用一个函数: @@ -1319,26 +1319,26 @@ module.exports = (phase, { defaultConfig }) => { // https://github.com/zeit/ return { /* config options here */ - }; -}; + } +} ``` `phase`是配置文件被加载时的当前内容。你可看到所有的 phases 常量:[constants](./lib/constants.js) 这些常量可以通过`next/constants`引入: ```js -const { PHASE_DEVELOPMENT_SERVER } = require("next/constants"); +const { PHASE_DEVELOPMENT_SERVER } = require('next/constants') module.exports = (phase, { defaultConfig }) => { if (phase === PHASE_DEVELOPMENT_SERVER) { return { /* development only config options here */ - }; + } } return { /* config options for all phases except development here */ - }; -}; + } +} ``` @@ -1350,8 +1350,8 @@ module.exports = (phase, { defaultConfig }) => { ```js // next.config.js module.exports = { - distDir: "build" -}; + distDir: 'build', +} ``` @@ -1363,8 +1363,8 @@ module.exports = { ```js // next.config.js module.exports = { - generateEtags: false -}; + generateEtags: false, +} ``` @@ -1379,9 +1379,9 @@ module.exports = { // period (in ms) where the server will keep pages in the buffer maxInactiveAge: 25 * 1000, // number of pages that should be kept simultaneously without being disposed - pagesBufferLength: 2 - } -}; + pagesBufferLength: 2, + }, +} ``` 这个只是在开发环境才有的功能。如果你在生成环境中想缓存 SSR 页面,请查看[SSR-caching](https://github.com/zeit/next.js/tree/canary/examples/ssr-caching) @@ -1395,8 +1395,8 @@ module.exports = { ```js // next.config.js module.exports = { - pageExtensions: ["jsx", "js"] -}; + pageExtensions: ['jsx', 'js'], +} ``` @@ -1410,9 +1410,9 @@ Next.js 使用构建时生成的常量来标识你的应用服务是哪个版本 module.exports = { generateBuildId: async () => { // For example get the latest git commit hash here - return "my-build-id"; - } -}; + return 'my-build-id' + }, +} ``` @@ -1437,17 +1437,17 @@ _注意: `webpack`方法将被执行两次,一次在服务端一次在客户 多配置可以组合在一起,如: ```js -const withTypescript = require("@zeit/next-typescript"); -const withSass = require("@zeit/next-sass"); +const withTypescript = require('@zeit/next-typescript') +const withSass = require('@zeit/next-sass') module.exports = withTypescript( withSass({ webpack(config, options) { // Further custom configuration here - return config; - } + return config + }, }) -); +) ``` 为了扩展`webpack`使用,可以在`next.config.js`定义函数。 @@ -1459,14 +1459,14 @@ module.exports = { webpack: (config, { buildId, dev, isServer, defaultLoaders }) => { // Perform customizations to webpack config // Important: return the modified config - return config; + return config }, webpackDevMiddleware: config => { // Perform customizations to webpack dev middleware config // Important: return the modified config - return config; - } -}; + return config + }, +} ``` `webpack`的第二个参数是个对象,你可以自定义配置它,对象属性如下所示: @@ -1491,15 +1491,15 @@ module.exports = { use: [ options.defaultLoaders.babel, { - loader: "@mdx-js/loader", - options: pluginOptions.options - } - ] - }); + loader: '@mdx-js/loader', + options: pluginOptions.options, + }, + ], + }) - return config; - } -}; + return config + }, +} ``` @@ -1562,14 +1562,14 @@ presets / plugins 不允许添加到`.babelrc`中,然而你可以配置`next/b 在应用程序中通常需要提供配置值 -Next.js支持2种提供配置的方式: +Next.js 支持 2 种提供配置的方式: - 构建时配置 - 运行时配置 #### 构建时配置 -构建时配置的工作方式是将提供的值内联到Javascript包中。 +构建时配置的工作方式是将提供的值内联到 Javascript 包中。 你可以在`next.config.js`设置`env`: @@ -1577,8 +1577,8 @@ Next.js支持2种提供配置的方式: // next.config.js module.exports = { env: { - customKey: 'value' - } + customKey: 'value', + }, } ``` @@ -1597,7 +1597,7 @@ export default Index > ⚠️ 请注意,使用此选项时不可用 `target: 'serverless'` -> ⚠️ 通常,您希望使用构建时配置来提供配置。原因是运行时配置增加了一个小的rendering/initialization开销。 +> ⚠️ 通常,您希望使用构建时配置来提供配置。原因是运行时配置增加了一个小的 rendering/initialization 开销。 `next/config`模块使你应用运行时可以读取些存储在`next.config.js`的配置项。`serverRuntimeConfig`属性只在服务器端可用,`publicRuntimeConfig`属性在服务端和客户端可用。 @@ -1607,12 +1607,12 @@ module.exports = { serverRuntimeConfig: { // Will only be available on the server side mySecret: 'secret', - secondSecret: process.env.SECOND_SECRET // Pass through env variables + secondSecret: process.env.SECOND_SECRET, // Pass through env variables }, publicRuntimeConfig: { // Will be available on both server and client - staticFolder: '/static' - } + staticFolder: '/static', + }, } ``` @@ -1647,11 +1647,11 @@ export default MyImage 建立一个 CDN,你能配置`assetPrefix`选项,去配置你的 CDN 源。 ```js -const isProd = process.env.NODE_ENV === "production"; +const isProd = process.env.NODE_ENV === 'production' module.exports = { // You may only need to add assetPrefix in the production. - assetPrefix: isProd ? "https://cdn.mydomain.com" : "" -}; + assetPrefix: isProd ? 'https://cdn.mydomain.com' : '', +} ``` 注意:Next.js 运行时将会自动添加前缀,但是对于`/static`是没有效果的,如果你想这些静态资源也能使用 CDN,你需要自己添加前缀。有一个方法可以判断你的环境来加前缀,如 [in this example](https://github.com/zeit/next.js/tree/master/examples/with-universal-configuration-build-time)。 @@ -1694,7 +1694,6 @@ Next.js 也有其他托管解决方案。请查考 wiki 章节['Deployment'](htt - ### 无服务器部署
@@ -1706,24 +1705,24 @@ Next.js 也有其他托管解决方案。请查考 wiki 章节['Deployment'](htt
-无服务器部署通过将应用程序拆分为更小的部分(也称为[**lambdas**](https://zeit.co/docs/v2/deployments/concepts/lambdas/))来显着提高可靠性和可伸缩性。在Next.js中,`pages`目录中的每个页面都变成了无服务器的lambda。 -对于无服务器的人来说,有[许多好处](https://zeit.co/blog/serverless-express-js-lambdas-with-now-2#benefits-of-serverless-express)。引用的链接在Express的上下文中讨论了其中的一些,但这些原则普遍适用:无服务器允许分布式故障点,无限的可扩展性,并且通过“为您使用的内容付费”的模式来提供难以置信的价格。 +无服务器部署通过将应用程序拆分为更小的部分(也称为[**lambdas**](https://zeit.co/docs/v2/deployments/concepts/lambdas/))来显着提高可靠性和可伸缩性。在 Next.js 中,`pages`目录中的每个页面都变成了无服务器的 lambda。 +对于无服务器的人来说,有[许多好处](https://zeit.co/blog/serverless-express-js-lambdas-with-now-2#benefits-of-serverless-express)。引用的链接在 Express 的上下文中讨论了其中的一些,但这些原则普遍适用:无服务器允许分布式故障点,无限的可扩展性,并且通过“为您使用的内容付费”的模式来提供难以置信的价格。 -要在Next.js中启用**无服务器模式**,可在`Next.config.js`中配置`target`值为`serverless`: +要在 Next.js 中启用**无服务器模式**,可在`Next.config.js`中配置`target`值为`serverless`: ```js // next.config.js module.exports = { - target: 'serverless' + target: 'serverless', } ``` -`serverless`将每页输出一个lambda。此文件是完全独立的,不需要运行任何依赖项: +`serverless`将每页输出一个 lambda。此文件是完全独立的,不需要运行任何依赖项: - `pages/index.js` => `.next/serverless/pages/index.js` - `pages/about.js` => `.next/serverless/pages/about.js` -Next.js无服务器功能的签名类似于Node.js HTTP服务器回调: +Next.js 无服务器功能的签名类似于 Node.js HTTP 服务器回调: ```ts export function render(req: http.IncomingMessage, res: http.ServerResponse) => void @@ -1731,15 +1730,15 @@ export function render(req: http.IncomingMessage, res: http.ServerResponse) => v - [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) - [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) -- `void` 指的是没有返回值的函数,它等同于JavaScript`undefined`。调用该函数将完成请求。 +- `void` 指的是没有返回值的函数,它等同于 JavaScript`undefined`。调用该函数将完成请求。 -使用无服务配置, 你可以讲Next.js部署到[ZEIT Now](https://zeit.co/now) 并提供所有的好处和易于控制; [custom routes](https://zeit.co/guides/custom-next-js-server-to-routes/) 缓存头. 要了解更多信息,请参阅 [ZEIT Guide for Deploying Next.js with Now](https://zeit.co/guides/deploying-nextjs-with-now/) +使用无服务配置, 你可以讲 Next.js 部署到[ZEIT Now](https://zeit.co/now) 并提供所有的好处和易于控制; [custom routes](https://zeit.co/guides/custom-next-js-server-to-routes/) 缓存头. 要了解更多信息,请参阅 [ZEIT Guide for Deploying Next.js with Now](https://zeit.co/guides/deploying-nextjs-with-now/) #### 降级部署 -Next.js为无服务器部署提供低级API,因为托管平台具有不同的功能签名。通常,您需要使用兼容性层包装Next.js无服务器构建的输出。 +Next.js 为无服务器部署提供低级 API,因为托管平台具有不同的功能签名。通常,您需要使用兼容性层包装 Next.js 无服务器构建的输出。 -例如,如果平台支持Node.js[`http.Server`](https://nodejs.org/api/http.html#http_class_http_server)类: +例如,如果平台支持 Node.js[`http.Server`](https://nodejs.org/api/http.html#http_class_http_server)类: ```js const http = require('http') @@ -1752,12 +1751,12 @@ server.listen(3000, () => console.log('Listening on http://localhost:3000')) #### 摘要 -- 用于实现无服务器部署的Low-level API +- 用于实现无服务器部署的 Low-level API - `pages`目录中的每个页面都成为无服务器功能(lambda) - 创建最小的无服务器功能 (50Kb base zip size) - 针对功能的快速[cold start](https://zeit.co/blog/serverless-ssr#cold-start) 进行了优化 -- 无服务器函数有0个依赖项 (依赖项包含在函数包中) -- 使用Node.js中的[http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)和[http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) +- 无服务器函数有 0 个依赖项 (依赖项包含在函数包中) +- 使用 Node.js 中的[http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)和[http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) - 选择使用`target: 'serverless'` in `next.config.js` - 在执行函数时不要加载`next.config.js`,请注意这意味着`publicRuntimeConfig` / `serverRuntimeConfig`不支持。 @@ -1806,15 +1805,15 @@ next export module.exports = { exportPathMap: async function(defaultPathMap) { return { - "/": { page: "/" }, - "/about": { page: "/about" }, - "/readme.md": { page: "/readme" }, - "/p/hello-nextjs": { page: "/post", query: { title: "hello-nextjs" } }, - "/p/learn-nextjs": { page: "/post", query: { title: "learn-nextjs" } }, - "/p/deploy-nextjs": { page: "/post", query: { title: "deploy-nextjs" } } - }; - } -}; + '/': { page: '/' }, + '/about': { page: '/about' }, + '/readme.md': { page: '/readme' }, + '/p/hello-nextjs': { page: '/post', query: { title: 'hello-nextjs' } }, + '/p/learn-nextjs': { page: '/post', query: { title: 'learn-nextjs' } }, + '/p/deploy-nextjs': { page: '/post', query: { title: 'deploy-nextjs' } }, + } + }, +} ``` > 注意:如果 path 的结尾是目录名,则将导出`/dir-name/index.html`,但是如果结尾有扩展名,将会导出对应的文件,如上`/readme.md`。如果你使用`.html`以外的扩展名解析文件时,你需要设置 header 的`Content-Type`头为"text/html". @@ -1859,13 +1858,13 @@ now ### 复制自定义文件 -如果您必须复制robots.txt等自定义文件或生成sitemap.xml,您可以在其中执行此操作`exportPathMap`。 `exportPathMap`获取一些上下文参数来帮助您创建/复制文件: +如果您必须复制 robots.txt 等自定义文件或生成 sitemap.xml,您可以在其中执行此操作`exportPathMap`。 `exportPathMap`获取一些上下文参数来帮助您创建/复制文件: - `dev` - `true`表示在开发环境下使用`exportPathMap`. `false`表示运行于`next export`. 在开发中,“exportpathmap”用于定义路由,不需要复制文件等行为。 - `dir` - 项目目录的绝对路径 - `outDir` - 指向`out`目录的绝对路径(可配置为`-o`或`--outdir`)。当`dev`为`true`时,`outdir`的值将为`null`。 - `distDir` - `.next`目录的绝对路径(可使用`distDir`配置键配置) -- `buildId` - 导出正在运行的buildId +- `buildId` - 导出正在运行的 buildId ```js // next.config.js @@ -1885,7 +1884,7 @@ module.exports = { // This will copy robots.txt from your project root into the out directory await copyFile(join(dir, 'robots.txt'), join(outDir, 'robots.txt')) return defaultPathMap - } + }, } ``` diff --git a/bench/readme.md b/bench/readme.md index 0ac01e4b1b426..71c7070d8f691 100644 --- a/bench/readme.md +++ b/bench/readme.md @@ -17,11 +17,13 @@ npm run start Then run one of these tests: - Stateless application which renders `

My component!

`. Runs 3000 http requests. + ``` npm run bench:stateless ``` - Stateless application which renders `
  • This is row {i}
  • ` 10.000 times. Runs 500 http requests. + ``` npm run bench:stateless-big ``` diff --git a/errors/cant-override-next-props.md b/errors/cant-override-next-props.md index d47b6b4d9ffe1..35bfc02c82f09 100644 --- a/errors/cant-override-next-props.md +++ b/errors/cant-override-next-props.md @@ -6,7 +6,7 @@ In your `pages/_app.js` you returned an object from `getInitialProps` that conta #### Possible Ways to Fix It -Look in your _app.js component's `getInitialProps` function and make sure neither of these property names are present in the object returned. +Look in your \_app.js component's `getInitialProps` function and make sure neither of these property names are present in the object returned. ### Useful Links diff --git a/errors/config-resolve-alias.md b/errors/config-resolve-alias.md index 3669e124de18f..feacf2e3a62eb 100644 --- a/errors/config-resolve-alias.md +++ b/errors/config-resolve-alias.md @@ -1,4 +1,4 @@ -# Invalid webpack resolve alias +# Invalid webpack resolve alias #### Why This Error Occurred diff --git a/errors/conflicting-amp-tag.md b/errors/conflicting-amp-tag.md index 6e5d87445288c..522aeb6fed30c 100644 --- a/errors/conflicting-amp-tag.md +++ b/errors/conflicting-amp-tag.md @@ -2,7 +2,7 @@ #### Why This Error Occurred -In AMP mode Next.js adds certain necessary tags automatically to comply with the AMP standard. You added a tag using `next/head` that conflicts with one of these automatically added tags. +In AMP mode Next.js adds certain necessary tags automatically to comply with the AMP standard. You added a tag using `next/head` that conflicts with one of these automatically added tags. #### Possible Ways to Fix It diff --git a/errors/doc-crossorigin-deprecated.md b/errors/doc-crossorigin-deprecated.md index 6a4c8913ebf11..48b99e30013d4 100644 --- a/errors/doc-crossorigin-deprecated.md +++ b/errors/doc-crossorigin-deprecated.md @@ -11,7 +11,7 @@ Add the config option: ```js // next.config.js module.exports = { - crossOrigin: 'anonymous' + crossOrigin: 'anonymous', } ``` diff --git a/errors/get-initial-props-as-an-instance-method.md b/errors/get-initial-props-as-an-instance-method.md index d9c58e617f182..bc1e9faed09b0 100644 --- a/errors/get-initial-props-as-an-instance-method.md +++ b/errors/get-initial-props-as-an-instance-method.md @@ -10,11 +10,11 @@ Use the static keyword. ```js export default class YourEntryComponent extends React.Component { - static getInitialProps () { + static getInitialProps() { return {} } - render () { + render() { return 'foo' } } @@ -23,7 +23,7 @@ export default class YourEntryComponent extends React.Component { or ```js -const YourEntryComponent = function () { +const YourEntryComponent = function() { return 'foo' } diff --git a/errors/multi-tabs.md b/errors/multi-tabs.md index 9b3b832069824..bf4f3f3d4abe3 100644 --- a/errors/multi-tabs.md +++ b/errors/multi-tabs.md @@ -10,4 +10,3 @@ More info here: https://tools.ietf.org/html/rfc6202#section-5.1 - Don't have too many tabs open to the same Next.js site open in development in the same browser at the same time. - If using Firefox you can increase this limit by navigating to `about:config` and setting `network.http.max-persistent-connections-per-server` to a higher number - diff --git a/errors/next-export-serverless.md b/errors/next-export-serverless.md index 56e7a1e5a07a0..f0224f770cda8 100644 --- a/errors/next-export-serverless.md +++ b/errors/next-export-serverless.md @@ -6,4 +6,4 @@ Next.js can only handle exporting when the `target` is set to `server` (this is #### Possible Ways to Fix It -Change `target` to `server`, run `next build`, then run `next export` again. \ No newline at end of file +Change `target` to `server`, run `next build`, then run `next export` again. diff --git a/errors/no-document-title.md b/errors/no-document-title.md index c71b6d5f6d007..53a3fa92a3d7b 100644 --- a/errors/no-document-title.md +++ b/errors/no-document-title.md @@ -1,4 +1,4 @@ -# `` should not be used in _document.js's `<Head>` +# `<title>` should not be used in \_document.js's `<Head>` #### Why This Error Occurred @@ -10,12 +10,12 @@ Set `<title>` in `pages/_app.js` instead: ```js // pages/_app.js -import App, {Container} from 'next/app' +import App, { Container } from 'next/app' import Head from 'next/head' import React from 'react' export default class MyApp extends App { - static async getInitialProps ({ Component, ctx }) { + static async getInitialProps({ Component, ctx }) { let pageProps = {} if (Component.getInitialProps) { @@ -25,7 +25,7 @@ export default class MyApp extends App { return { pageProps } } - render () { + render() { const { Component, pageProps } = this.props return ( @@ -40,7 +40,6 @@ export default class MyApp extends App { } ``` - ### Useful Links - [The issue this was reported in: #4596](https://github.com/zeit/next.js/issues/4596) diff --git a/errors/no-on-app-updated-hook.md b/errors/no-on-app-updated-hook.md index ec0e0524f88fe..c2ce7c5d7eacd 100644 --- a/errors/no-on-app-updated-hook.md +++ b/errors/no-on-app-updated-hook.md @@ -20,6 +20,6 @@ This is code for that: window.onbeforeunload = function(e) { // Get the application state (usually from a store like Redux) const appState = {} - localStorage.setItem('app-state', JSON.stringify(appState)); -}; + localStorage.setItem('app-state', JSON.stringify(appState)) +} ``` diff --git a/errors/no-router-instance.md b/errors/no-router-instance.md index 2381b0e72d6d1..504ce29ecd803 100644 --- a/errors/no-router-instance.md +++ b/errors/no-router-instance.md @@ -2,8 +2,8 @@ #### Why This Error Occurred -During SSR you might have tried to access a router method `push`, `replace`, `back`, which is not supported. +During SSR you might have tried to access a router method `push`, `replace`, `back`, which is not supported. #### Possible Ways to Fix It -Move any calls to router methods to `componentDidMount` or add a check such as `typeof window !== 'undefined'` before calling the methods \ No newline at end of file +Move any calls to router methods to `componentDidMount` or add a check such as `typeof window !== 'undefined'` before calling the methods diff --git a/errors/promise-in-next-config.md b/errors/promise-in-next-config.md index 781bf04972a87..7fb48b3b00419 100644 --- a/errors/promise-in-next-config.md +++ b/errors/promise-in-next-config.md @@ -8,7 +8,7 @@ The webpack function in `next.config.js` returned a promise which is not support module.exports = { webpack: async function(config) { return config - } + }, } ``` diff --git a/errors/serverless-publicRuntimeConfig.md b/errors/serverless-publicRuntimeConfig.md index e6feecbe19111..deb4ca5cecd93 100644 --- a/errors/serverless-publicRuntimeConfig.md +++ b/errors/serverless-publicRuntimeConfig.md @@ -3,6 +3,7 @@ #### Why This Error Occurred In the `serverless` target environment `next.config.js` is not loaded, so we don't support `publicRuntimeConfig`. + #### Possible Ways to Fix It Use config option `env` to set **build time** variables like such: @@ -11,12 +12,12 @@ Use config option `env` to set **build time** variables like such: // next.config.js module.exports = { env: { - special: "value" - } + special: 'value', + }, } ``` ```js // pages/index.js console.log(process.env.special) // value -``` \ No newline at end of file +``` diff --git a/errors/threw-undefined.md b/errors/threw-undefined.md index 79dd763b2bb8e..0d4129ef4f115 100644 --- a/errors/threw-undefined.md +++ b/errors/threw-undefined.md @@ -4,7 +4,6 @@ Somewhere in your code you `throw` an `undefined` value. Since this isn't a valid error there isn't a stack trace. We show this error instead to let you know what to look for. - #### Possible Ways to Fix It Look in your pages and find where an error could be throwing `undefined` diff --git a/errors/url-deprecated.md b/errors/url-deprecated.md index 3152f1427773b..d583128789469 100644 --- a/errors/url-deprecated.md +++ b/errors/url-deprecated.md @@ -22,7 +22,7 @@ import { withRouter } from 'next/router' class Page extends React.Component { render() { - const {router} = this.props + const { router } = this.props console.log(router) return <div>{router.pathname}</div> } diff --git a/examples/custom-server-actionhero/README.md b/examples/custom-server-actionhero/README.md index 5acfb98033886..f70e37f9b424a 100644 --- a/examples/custom-server-actionhero/README.md +++ b/examples/custom-server-actionhero/README.md @@ -43,62 +43,65 @@ yarn start ```js // initializers/next.js -const {Initializer, api} = require('actionhero') +const { Initializer, api } = require('actionhero') const next = require('next') module.exports = class NextInitializer extends Initializer { - constructor () { + constructor() { super() this.name = 'next' } - async initialize () { + async initialize() { api.next = { - render: async (connection) => { - if (connection.type !== 'web') { throw new Error('Connections for NEXT apps must be of type "web"') } + render: async connection => { + if (connection.type !== 'web') { + throw new Error('Connections for NEXT apps must be of type "web"') + } const req = connection.rawConnection.req const res = connection.rawConnection.res return api.next.handle(req, res) - } + }, } - api.next.dev = (api.env === 'development') - if (api.next.dev) { api.log('Running next in development mode...') } + api.next.dev = api.env === 'development' + if (api.next.dev) { + api.log('Running next in development mode...') + } - api.next.app = next({dev: api.next.dev}) + api.next.app = next({ dev: api.next.dev }) api.next.handle = api.next.app.getRequestHandler() await api.next.app.prepare() } - async stop () { + async stop() { await api.next.app.close() } } ``` -2. Create an action which will run the above `api.next.render(connection)`. Note that we will not be relying on ActionHero to respond to the client's request in this case, and leave that up to next (via: `data.toRender = false`) +2. Create an action which will run the above `api.next.render(connection)`. Note that we will not be relying on ActionHero to respond to the client's request in this case, and leave that up to next (via: `data.toRender = false`) ```js // actions/next.js -const {Action, api} = require('actionhero') +const { Action, api } = require('actionhero') module.exports = class CreateChatRoom extends Action { - constructor () { + constructor() { super() this.name = 'render' this.description = 'I render the next.js react website' } - async run (data) { + async run(data) { data.toRender = false return api.next.render(data.connection) } } - ``` -3. Tell ActionHero to use the api rather than the file server as the top-level route in `api.config.servers.web.rootEndpointType = 'api'`. This will allows "/" to listen to API requests. Also update `api.config.general.paths.public = [ path.join(__dirname, '/../static') ]`. In this configuration, the next 'static' renderer will take priority over the ActionHero 'public file' api. Note that any static assets (CSS, fonts, etc) will need to be in "./static" rather than "./public". +3. Tell ActionHero to use the api rather than the file server as the top-level route in `api.config.servers.web.rootEndpointType = 'api'`. This will allows "/" to listen to API requests. Also update `api.config.general.paths.public = [ path.join(__dirname, '/../static') ]`. In this configuration, the next 'static' renderer will take priority over the ActionHero 'public file' api. Note that any static assets (CSS, fonts, etc) will need to be in "./static" rather than "./public". Note that this is where the websocket server, if you enable it, will place the `ActionheroWebsocketClient` libraray.<br> @@ -108,14 +111,14 @@ Note that this is where the websocket server, if you enable it, will place the ` // config/routes.js exports['default'] = { - routes: (api) => { + routes: api => { return { get: [ { path: '/time', action: 'time' }, - { path: '/', matchTrailingPathParts: true, action: 'render' } - ] + { path: '/', matchTrailingPathParts: true, action: 'render' }, + ], } - } + }, } ``` diff --git a/examples/custom-server-koa/README.md b/examples/custom-server-koa/README.md index a1632000844c2..b617d1be04d0f 100644 --- a/examples/custom-server-koa/README.md +++ b/examples/custom-server-koa/README.md @@ -53,8 +53,8 @@ The most common Koa middleware for handling the gzip compression is [compress](h If you need to enable the gzip compression, the most simple way to do so is by wrapping the express-middleware [compression](https://github.com/expressjs/compression) with [koa-connect](https://github.com/vkurchatkin/koa-connect): ```javascript -const compression = require("compression"); -const koaConnect = require("koa-connect"); +const compression = require('compression') +const koaConnect = require('koa-connect') -server.use(koaConnect(compression())); +server.use(koaConnect(compression())) ``` diff --git a/examples/custom-server-reasonml/README.md b/examples/custom-server-reasonml/README.md index b08dce119b1eb..cc74993a867c6 100644 --- a/examples/custom-server-reasonml/README.md +++ b/examples/custom-server-reasonml/README.md @@ -1,6 +1,7 @@ # Custom server REASONML # Install it and run: + ```bash npm install npm run dev @@ -10,21 +11,25 @@ yarn dev ``` # Build the app + ```bash yarn next:build npm run next:build ``` # Run the production app + Run this command after yarn build. + ```bash yarn start ``` # The idea behind this example + ReasonML is an exciting new language and since it can compile directly to JS via bucklescript -that means that we can power our backend server with REASONML and also have the frontend built with +that means that we can power our backend server with REASONML and also have the frontend built with reasonreact, which is covered in another [example](https://github.com/zeit/next.js/tree/canary/examples/with-reasonml). This example shows how powerful & helpful it can be to build a next js custom server with a typesafe language. -The example has been built off the `custom-server` example that uses pure `nodejs` to build the custom server. \ No newline at end of file +The example has been built off the `custom-server` example that uses pure `nodejs` to build the custom server. diff --git a/examples/custom-server-reasonml/bsconfig.json b/examples/custom-server-reasonml/bsconfig.json index 328150f88e630..f04ac0bec3cc7 100644 --- a/examples/custom-server-reasonml/bsconfig.json +++ b/examples/custom-server-reasonml/bsconfig.json @@ -11,4 +11,4 @@ }, "suffix": ".bs.js", "bs-dependencies": [] -} \ No newline at end of file +} diff --git a/examples/custom-server-reasonml/package.json b/examples/custom-server-reasonml/package.json index df257b981ed80..46f956e38a777 100644 --- a/examples/custom-server-reasonml/package.json +++ b/examples/custom-server-reasonml/package.json @@ -23,4 +23,4 @@ "react": "^16.8.6", "react-dom": "^16.8.6" } -} \ No newline at end of file +} diff --git a/examples/custom-server-typescript/nodemon.json b/examples/custom-server-typescript/nodemon.json index b78f3ea8b7468..f9c1534edff8b 100644 --- a/examples/custom-server-typescript/nodemon.json +++ b/examples/custom-server-typescript/nodemon.json @@ -2,4 +2,3 @@ "watch": ["server", "static"], "exec": "ts-node --project tsconfig.server.json server/index.ts" } - diff --git a/examples/custom-server-typescript/server/index.ts b/examples/custom-server-typescript/server/index.ts index 43b8285307312..eac0e4f3491c5 100644 --- a/examples/custom-server-typescript/server/index.ts +++ b/examples/custom-server-typescript/server/index.ts @@ -7,8 +7,7 @@ const dev = process.env.NODE_ENV !== 'production' const app = next({ dev }) const handle = app.getRequestHandler() -app.prepare() -.then(() => { +app.prepare().then(() => { createServer((req, res) => { const parsedUrl = parse(req.url!, true) const { pathname, query } = parsedUrl @@ -20,9 +19,12 @@ app.prepare() } else { handle(req, res, parsedUrl) } - }) - .listen(port) + }).listen(port) // tslint:disable-next-line:no-console - console.log(`> Server listening at http://localhost:${port} as ${dev ? 'development' : process.env.NODE_ENV}`); + console.log( + `> Server listening at http://localhost:${port} as ${ + dev ? 'development' : process.env.NODE_ENV + }` + ) }) diff --git a/examples/public-file-serving/now.json b/examples/public-file-serving/now.json index 146cb2dea26b8..ca5c3456db8b0 100644 --- a/examples/public-file-serving/now.json +++ b/examples/public-file-serving/now.json @@ -3,10 +3,13 @@ "alias": "https://serverless-static-files.now.sh", "builds": [{ "src": "next.config.js", "use": "@now/next" }], "routes": [ - { "src": "/_next/static/(?:[^/]+/pages|chunks|runtime)/.+", "headers": { "cache-control": "immutable" } }, + { + "src": "/_next/static/(?:[^/]+/pages|chunks|runtime)/.+", + "headers": { "cache-control": "immutable" } + }, { "src": "^/(favicon.ico|manifest.json|humans.txt|sitemap.xml|sitemap.xsl)$", "headers": { "cache-control": "max-age=300 must-revalidate" } } ] -} \ No newline at end of file +} diff --git a/examples/ssr-caching/package.json b/examples/ssr-caching/package.json index 730ea9b865c7b..92f27fc69aa5a 100644 --- a/examples/ssr-caching/package.json +++ b/examples/ssr-caching/package.json @@ -14,4 +14,4 @@ "react-dom": "^16.7.0" }, "license": "ISC" -} \ No newline at end of file +} diff --git a/examples/with-apollo-and-redux-saga/README.md b/examples/with-apollo-and-redux-saga/README.md index 6f6fc12bea354..100b6fdff16e9 100644 --- a/examples/with-apollo-and-redux-saga/README.md +++ b/examples/with-apollo-and-redux-saga/README.md @@ -45,15 +45,15 @@ Note that you can access the redux store like you normally would using `react-re ```js const mapStateToProps = state => ({ - location: state.form.location -}); + location: state.form.location, +}) export default withReduxSaga( connect( mapStateToProps, null )(Index) -); +) ``` `connect` must go inside `withReduxSaga` otherwise `connect` will not be able to find the store. diff --git a/examples/with-apollo-and-redux/README.md b/examples/with-apollo-and-redux/README.md index dcf281ec8b0d3..4cd3b377dea8d 100644 --- a/examples/with-apollo-and-redux/README.md +++ b/examples/with-apollo-and-redux/README.md @@ -47,15 +47,15 @@ Note that you can access the redux store like you normally would using `react-re ```js const mapStateToProps = state => ({ - location: state.form.location -}); + location: state.form.location, +}) export default withRedux( connect( mapStateToProps, null )(Index) -); +) ``` ### Note: diff --git a/examples/with-carlo/README.md b/examples/with-carlo/README.md index 65a022b6fa52d..e5b5aa0008bc8 100644 --- a/examples/with-carlo/README.md +++ b/examples/with-carlo/README.md @@ -42,4 +42,4 @@ npm start ## The idea behind the example -This example show how you can use Next.js with [Carlo](https://github.com/GoogleChromeLabs/carlo). Here we use a [Custom server](https://github.com/zeit/next.js/blob/canary/examples/custom-server/README.md) to fit the carlo configs. \ No newline at end of file +This example show how you can use Next.js with [Carlo](https://github.com/GoogleChromeLabs/carlo). Here we use a [Custom server](https://github.com/zeit/next.js/blob/canary/examples/custom-server/README.md) to fit the carlo configs. diff --git a/examples/with-cerebral/README.md b/examples/with-cerebral/README.md index c0eb631cc9d01..4c373f5a7c9a7 100644 --- a/examples/with-cerebral/README.md +++ b/examples/with-cerebral/README.md @@ -44,31 +44,31 @@ Use [CerebralJS](https://cerebraljs.com/) to manage an apps state and side effec Declarative CerebralJS: ```js -[ +;[ setLoading(true), getUser, { success: setUser, - error: setError + error: setError, }, - setLoading(false) -]; + setLoading(false), +] ``` vs imperative JS: ```js function getUser() { - this.isLoading = true; + this.isLoading = true ajax - .get("/user") + .get('/user') .then(user => { - this.data = user; - this.isLoading = false; + this.data = user + this.isLoading = false }) .catch(error => { - this.error = error; - this.isLoading = false; - }); + this.error = error + this.isLoading = false + }) } ``` diff --git a/examples/with-cloud9/README.md b/examples/with-cloud9/README.md index b8da480690858..5f5521b4561a2 100644 --- a/examples/with-cloud9/README.md +++ b/examples/with-cloud9/README.md @@ -1,6 +1,6 @@ -# With Cloud 9 (c9.io) # +# With Cloud 9 (c9.io) -## Install NVM and set node to the latest version ## +## Install NVM and set node to the latest version Cloud 9 environment comes with a preinstalled nvm, but its better to use the latest version - follow the install instructions from the [NVM GitHub page](https://github.com/creationix/nvm) @@ -14,7 +14,7 @@ nvm alias default 10.12.0 nvm use node ``` -## Create a custom 'server.js' in the project root directory ## +## Create a custom 'server.js' in the project root directory // This file doesn't go through babel or webpack transformation. // Make sure the syntax and sources this file requires are compatible with the current node version you are running @@ -42,7 +42,7 @@ nvm use node }) }) -## Change 'package.json' scripts to use that file ## +## Change 'package.json' scripts to use that file "scripts": { "dev": "node server.js", @@ -50,7 +50,7 @@ nvm use node "start": "NODE_ENV=production node server.js" } -## Use dev preview within the Cloud9 VM IDE ## +## Use dev preview within the Cloud9 VM IDE After starting up the server (by using 'Run' button while having server.js open in the IDE editor or by using "npm run dev" in terminal) you should be able to access web server by diff --git a/examples/with-custom-reverse-proxy/README.md b/examples/with-custom-reverse-proxy/README.md index deb32ebf48866..a520c4af9f455 100644 --- a/examples/with-custom-reverse-proxy/README.md +++ b/examples/with-custom-reverse-proxy/README.md @@ -35,8 +35,8 @@ yarn dev This example applies this gist https://gist.github.com/jamsesso/67fd937b74989dc52e33 to Nextjs and provides: -* Reverse proxy in development mode by add `http-proxy-middleware` to custom server -* NOT a recommended approach to production scale (hence explicit dev flag) as we should scope proxy as outside UI applications and have separate web server taking care of that. +- Reverse proxy in development mode by add `http-proxy-middleware` to custom server +- NOT a recommended approach to production scale (hence explicit dev flag) as we should scope proxy as outside UI applications and have separate web server taking care of that. Sorry for the extra packages. I belong to the minority camp of writing ES6 code on Windows developers. Essentially you only need `http-proxy-middleware` on top of bare-bone Nextjs setup to run this example. diff --git a/examples/with-dynamic-app-layout/package.json b/examples/with-dynamic-app-layout/package.json index 3c2ce7636daa2..c6cf97f83ed6a 100644 --- a/examples/with-dynamic-app-layout/package.json +++ b/examples/with-dynamic-app-layout/package.json @@ -1,18 +1,18 @@ { - "name": "with-dynamic-app-layout", - "version": "1.0.0", - "description": "This example features:", - "main": "index.js", - "scripts": { - "dev": "next", - "build": "next build", - "start": "next start" - }, - "dependencies": { - "next": "latest", - "react": "^16.7.0", - "react-dom": "^16.7.0" - }, - "author": "", - "license": "ISC" + "name": "with-dynamic-app-layout", + "version": "1.0.0", + "description": "This example features:", + "main": "index.js", + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "latest", + "react": "^16.7.0", + "react-dom": "^16.7.0" + }, + "author": "", + "license": "ISC" } diff --git a/examples/with-firebase-hosting-and-docker/README.md b/examples/with-firebase-hosting-and-docker/README.md index 83d9051633316..50e2586310c9e 100644 --- a/examples/with-firebase-hosting-and-docker/README.md +++ b/examples/with-firebase-hosting-and-docker/README.md @@ -23,10 +23,10 @@ cd with-firebase-hosting-and-docker Set up firebase: -* create a project through the [firebase web console](https://console.firebase.google.com/) -* grab the projects ID from the web consoles URL: https://console.firebase.google.com/project/<projectId> -* update the `.env` with your FB_PROJECTID and FIREBASE_TOKEN ( see .env.example ) -* ADD `serviceAccountKey.json` to your project root +- create a project through the [firebase web console](https://console.firebase.google.com/) +- grab the projects ID from the web consoles URL: https://console.firebase.google.com/project/<projectId> +- update the `.env` with your FB_PROJECTID and FIREBASE_TOKEN ( see .env.example ) +- ADD `serviceAccountKey.json` to your project root ### Dev next @@ -58,6 +58,6 @@ If you're having issues, feel free to tag @sampsonjoliver in the [issue you crea ## Important -* The empty `placeholder.html` file is so Firebase Hosting does not error on an empty `public/` folder and still hosts at the Firebase project URL. -* `firebase.json` outlines the catchall rewrite rule for our Cloud Function. -* The [Firebase predeploy](https://firebase.google.com/docs/cli/#predeploy_and_postdeploy_hooks) hooks defined in `firebase.json` will handle linting and compiling of the next app and the functions sourceswhen `firebase deploy` is invoked. The only scripts you should need are `docker:dev`, `docker:serve` and `docker:deploy`. +- The empty `placeholder.html` file is so Firebase Hosting does not error on an empty `public/` folder and still hosts at the Firebase project URL. +- `firebase.json` outlines the catchall rewrite rule for our Cloud Function. +- The [Firebase predeploy](https://firebase.google.com/docs/cli/#predeploy_and_postdeploy_hooks) hooks defined in `firebase.json` will handle linting and compiling of the next app and the functions sourceswhen `firebase deploy` is invoked. The only scripts you should need are `docker:dev`, `docker:serve` and `docker:deploy`. diff --git a/examples/with-firebase-hosting-and-typescript/README.md b/examples/with-firebase-hosting-and-typescript/README.md index fc12fac6a914f..35a191813cb1b 100644 --- a/examples/with-firebase-hosting-and-typescript/README.md +++ b/examples/with-firebase-hosting-and-typescript/README.md @@ -23,11 +23,11 @@ cd with-firebase-hosting-and-typescript Set up firebase: -* install Firebase Tools: `npm i -g firebase-tools` -* create a project through the [firebase web console](https://console.firebase.google.com/) -* grab the projects ID from the web consoles URL: https://console.firebase.google.com/project/<projectId> -* update the `.firebaserc` default project ID to the newly created project -* login to the Firebase CLI tool with `firebase login` +- install Firebase Tools: `npm i -g firebase-tools` +- create a project through the [firebase web console](https://console.firebase.google.com/) +- grab the projects ID from the web consoles URL: https://console.firebase.google.com/project/<projectId> +- update the `.firebaserc` default project ID to the newly created project +- login to the Firebase CLI tool with `firebase login` #### Install project: @@ -69,10 +69,10 @@ If you're having issues, feel free to tag @sampsonjoliver in the [issue you crea ## Important -* The empty `placeholder.html` file is so Firebase Hosting does not error on an empty `public/` folder and still hosts at the Firebase project URL. -* `firebase.json` outlines the catchall rewrite rule for our Cloud Function. -* The [Firebase predeploy](https://firebase.google.com/docs/cli/#predeploy_and_postdeploy_hooks) hooks defined in `firebase.json` will handle linting and compiling of the next app and the functions sourceswhen `firebase deploy` is invoked. The only scripts you should need are `dev`, `clean` and `deploy`. -* Specifying [`"engines": {"node": "8"}`](package.json#L5-L7) in the `package.json` is required for firebase functions +- The empty `placeholder.html` file is so Firebase Hosting does not error on an empty `public/` folder and still hosts at the Firebase project URL. +- `firebase.json` outlines the catchall rewrite rule for our Cloud Function. +- The [Firebase predeploy](https://firebase.google.com/docs/cli/#predeploy_and_postdeploy_hooks) hooks defined in `firebase.json` will handle linting and compiling of the next app and the functions sourceswhen `firebase deploy` is invoked. The only scripts you should need are `dev`, `clean` and `deploy`. +- Specifying [`"engines": {"node": "8"}`](package.json#L5-L7) in the `package.json` is required for firebase functions to be deployed on Node 8 rather than Node 6 ([Firebase Blog Announcement](https://firebase.googleblog.com/2018/08/cloud-functions-for-firebase-config-node-8-timeout-memory-region.html)) . This is matched in by specifying target as `es2017` in [`src/functions/tsconfig.json`](src/functions/tsconfig) so that typescript output somewhat compacter and moderner code. diff --git a/examples/with-firebase-hosting-and-typescript/firebase.json b/examples/with-firebase-hosting-and-typescript/firebase.json index f83054d29c49b..ca60567acef99 100644 --- a/examples/with-firebase-hosting-and-typescript/firebase.json +++ b/examples/with-firebase-hosting-and-typescript/firebase.json @@ -2,13 +2,13 @@ "functions": { "source": "dist/functions", "predeploy": [ - "npm run lint-functions", - "npm run lint-app", - "npm run typecheck-app", - "npm run build-functions", - "npm run build-app", - "npm run copy-deps", - "npm run install-deps" + "npm run lint-functions", + "npm run lint-app", + "npm run typecheck-app", + "npm run build-functions", + "npm run build-app", + "npm run copy-deps", + "npm run install-deps" ] }, "hosting": { diff --git a/examples/with-firebase-hosting-and-typescript/src/app/tsconfig.json b/examples/with-firebase-hosting-and-typescript/src/app/tsconfig.json index 8c7b1dc33f471..3a4c85f9053e5 100644 --- a/examples/with-firebase-hosting-and-typescript/src/app/tsconfig.json +++ b/examples/with-firebase-hosting-and-typescript/src/app/tsconfig.json @@ -16,11 +16,7 @@ "skipLibCheck": true, "sourceMap": true, "noEmit": true, - "lib": [ - "es6", - "dom", - "es2016" - ], - "baseUrl": ".", + "lib": ["es6", "dom", "es2016"], + "baseUrl": "." } } diff --git a/examples/with-firebase-hosting-and-typescript/src/functions/index.ts b/examples/with-firebase-hosting-and-typescript/src/functions/index.ts index 6ced035b11784..78eccc8c087d1 100644 --- a/examples/with-firebase-hosting-and-typescript/src/functions/index.ts +++ b/examples/with-firebase-hosting-and-typescript/src/functions/index.ts @@ -1,11 +1,11 @@ -import * as functions from 'firebase-functions'; -import * as next from 'next'; +import * as functions from 'firebase-functions' +import * as next from 'next' -const dev = process.env.NODE_ENV !== 'production'; -const app = next({ dev, conf: { distDir: 'next' } }); -const handle = app.getRequestHandler(); +const dev = process.env.NODE_ENV !== 'production' +const app = next({ dev, conf: { distDir: 'next' } }) +const handle = app.getRequestHandler() export const nextApp = functions.https.onRequest((req, res) => { - console.log('File: ' + req.originalUrl); - return app.prepare().then(() => handle(req, res)); -}); + console.log('File: ' + req.originalUrl) + return app.prepare().then(() => handle(req, res)) +}) diff --git a/examples/with-firebase-hosting-and-typescript/src/functions/tslint.json b/examples/with-firebase-hosting-and-typescript/src/functions/tslint.json index c952af3910c16..981bec2a761b4 100644 --- a/examples/with-firebase-hosting-and-typescript/src/functions/tslint.json +++ b/examples/with-firebase-hosting-and-typescript/src/functions/tslint.json @@ -74,27 +74,26 @@ // Disallow duplicate imports in the same file. "no-duplicate-imports": true, - // -- Strong Warnings -- // These rules should almost never be needed, but may be included due to legacy code. // They are left as a warning to avoid frustration with blocked deploys when the developer // understand the warning and wants to deploy anyway. // Warn when an empty interface is defined. These are generally not useful. - "no-empty-interface": {"severity": "warning"}, + "no-empty-interface": { "severity": "warning" }, // Warn when an import will have side effects. - "no-import-side-effect": {"severity": "warning"}, + "no-import-side-effect": { "severity": "warning" }, // Warn when variables are defined with var. Var has subtle meaning that can lead to bugs. Strongly prefer const for // most values and let for values that will change. - "no-var-keyword": {"severity": "warning"}, + "no-var-keyword": { "severity": "warning" }, // Prefer === and !== over == and !=. The latter operators support overloads that are often accidental. - "triple-equals": {"severity": "warning"}, + "triple-equals": { "severity": "warning" }, // Warn when using deprecated APIs. - "deprecation": {"severity": "warning"}, + "deprecation": { "severity": "warning" }, // -- Light Warnigns -- // These rules are intended to help developers use better style. Simpler code has fewer bugs. These would be "info" @@ -102,16 +101,16 @@ // prefer for( ... of ... ) to an index loop when the index is only used to fetch an object from an array. // (Even better: check out utils like .map if transforming an array!) - "prefer-for-of": {"severity": "warning"}, + "prefer-for-of": { "severity": "warning" }, // Warns if function overloads could be unified into a single function with optional or rest parameters. - "unified-signatures": {"severity": "warning"}, + "unified-signatures": { "severity": "warning" }, // Prefer const for values that will not change. This better documents code. - "prefer-const": {"severity": "warning"}, + "prefer-const": { "severity": "warning" }, // Multi-line object liiterals and function calls should have a trailing comma. This helps avoid merge conflicts. - "trailing-comma": {"severity": "warning"} + "trailing-comma": { "severity": "warning" } }, "defaultSeverity": "error" diff --git a/examples/with-firebase-hosting/README.md b/examples/with-firebase-hosting/README.md index 7eb9c9f8a9418..13bb7feb5e442 100644 --- a/examples/with-firebase-hosting/README.md +++ b/examples/with-firebase-hosting/README.md @@ -27,11 +27,11 @@ cd with-firebase-hosting <details> <summary><b>Set up firebase</b></summary> -* install Firebase Tools: `npm i -g firebase-tools` -* create a project through the [firebase web console](https://console.firebase.google.com/) -* grab the projects ID from the web consoles URL: `https://console.firebase.google.com/project/<projectId>` -* update the `.firebaserc` default project ID to the newly created project -* login to the Firebase CLI tool with `firebase login` +- install Firebase Tools: `npm i -g firebase-tools` +- create a project through the [firebase web console](https://console.firebase.google.com/) +- grab the projects ID from the web consoles URL: `https://console.firebase.google.com/project/<projectId>` +- update the `.firebaserc` default project ID to the newly created project +- login to the Firebase CLI tool with `firebase login` </details> @@ -78,9 +78,9 @@ If you're having issues, feel free to tag @jthegedus in the [issue you create on ## Important -* The empty `placeholder.html` file is so Firebase Hosting does not error on an empty `public/` folder and still hosts at the Firebase project URL. -* `firebase.json` outlines the catchall rewrite rule for our Cloud Function. -* Specifying [`"engines": {"node": "8"}`](package.json#L5-L7) in the `package.json` is required for firebase functions +- The empty `placeholder.html` file is so Firebase Hosting does not error on an empty `public/` folder and still hosts at the Firebase project URL. +- `firebase.json` outlines the catchall rewrite rule for our Cloud Function. +- Specifying [`"engines": {"node": "8"}`](package.json#L5-L7) in the `package.json` is required for firebase functions to be deployed on Node 8 rather than Node 6 ([Firebase Blog Announcement](https://firebase.googleblog.com/2018/08/cloud-functions-for-firebase-config-node-8-timeout-memory-region.html)) . This is matched in [`src/functions/.babelrc`](src/functions/.babelrc) so that babel output somewhat compacter and moderner code. @@ -89,14 +89,14 @@ If you're having issues, feel free to tag @jthegedus in the [issue you create on Next App and Next Server development are separated into two different folders: -* app - `src/app/` -* server - `src/functions/` +- app - `src/app/` +- server - `src/functions/` If you wish to modify any configuration of the Next App, you should only modify the contents of `src/app`. For instance, the `.babelrc` in `src/functions` is used only to compile the Firebase Cloud Functions code, which is our the Next Server code. If you wish to customize the `.babelrc` for the Next App compilation, then you should create one at `src/app/.babelrc` and follow the [customization guide](https://github.com/zeit/next.js#customizing-babel-config). -### _app.js +### \_app.js If using `_app.js` you may receive the following error on your deployed Cloud Function: @@ -104,4 +104,4 @@ If using `_app.js` you may receive the following error on your deployed Cloud Fu { Error: Cannot find module '@babel/runtime/regenerator'... ``` -Despite next.js having `@babel/runtime` as a dependency, you must install it as a dependency directly in this project. \ No newline at end of file +Despite next.js having `@babel/runtime` as a dependency, you must install it as a dependency directly in this project. diff --git a/examples/with-jest-flow/README.md b/examples/with-jest-flow/README.md index b770f78807313..f1387a0d0f53b 100644 --- a/examples/with-jest-flow/README.md +++ b/examples/with-jest-flow/README.md @@ -43,5 +43,5 @@ yarn test This example features: -* An app with jest tests -* The [Flow](https://flowtype.org/) static type checker, with the transform-flow-strip-types babel plugin stripping flow type annotations from your output code. +- An app with jest tests +- The [Flow](https://flowtype.org/) static type checker, with the transform-flow-strip-types babel plugin stripping flow type annotations from your output code. diff --git a/examples/with-jest-typescript/README.md b/examples/with-jest-typescript/README.md index 8050fedc905f3..b308b367f2c51 100644 --- a/examples/with-jest-typescript/README.md +++ b/examples/with-jest-typescript/README.md @@ -41,4 +41,4 @@ yarn test ## The idea behind the example -This example shows a configuration and several examples for a running Jest tests in a NextJS TypeScript app \ No newline at end of file +This example shows a configuration and several examples for a running Jest tests in a NextJS TypeScript app diff --git a/examples/with-jest-typescript/src/modules/auth/types.ts b/examples/with-jest-typescript/src/modules/auth/types.ts index c234113c8aec3..36dc07076a31f 100644 --- a/examples/with-jest-typescript/src/modules/auth/types.ts +++ b/examples/with-jest-typescript/src/modules/auth/types.ts @@ -1,4 +1,4 @@ export interface LoginCredentials { - email: string; - password: string; -} \ No newline at end of file + email: string + password: string +} diff --git a/examples/with-jest-typescript/src/modules/cars/types.ts b/examples/with-jest-typescript/src/modules/cars/types.ts index e0f20427edbd2..5a1ee5acad47e 100644 --- a/examples/with-jest-typescript/src/modules/cars/types.ts +++ b/examples/with-jest-typescript/src/modules/cars/types.ts @@ -1,10 +1,10 @@ export interface Car { - make : string; - model : string; - engine : string; - year : number; - mileage : number; - equipment : string[]; + make: string + model: string + engine: string + year: number + mileage: number + equipment: string[] } -export type CarList = Array < Car >; \ No newline at end of file +export type CarList = Array<Car> diff --git a/examples/with-jest-typescript/tsconfig.json b/examples/with-jest-typescript/tsconfig.json index ace24fb16c70d..62bc21628bc35 100644 --- a/examples/with-jest-typescript/tsconfig.json +++ b/examples/with-jest-typescript/tsconfig.json @@ -1,33 +1,27 @@ { - "compileOnSave": false, - "compilerOptions": { - "target": "esnext", - "module": "esnext", - "jsx": "preserve", - "allowJs": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "removeComments": false, - "preserveConstEnums": true, - "sourceMap": true, - "skipLibCheck": true, - "baseUrl": ".", - "typeRoots": [ - "./node_modules/@types" - ], - "lib": [ - "dom", - "es2015", - "es2016" - ] - }, - "exclude": [ - "node_modules", - "**/*.spec.ts", - "**/*.spec.tsx", - "**/*.test.ts", - "**/*.test.tsx", - ] -} \ No newline at end of file + "compileOnSave": false, + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "jsx": "preserve", + "allowJs": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "removeComments": false, + "preserveConstEnums": true, + "sourceMap": true, + "skipLibCheck": true, + "baseUrl": ".", + "typeRoots": ["./node_modules/@types"], + "lib": ["dom", "es2015", "es2016"] + }, + "exclude": [ + "node_modules", + "**/*.spec.ts", + "**/*.spec.tsx", + "**/*.test.ts", + "**/*.test.tsx" + ] +} diff --git a/examples/with-lingui/components/withLang.js b/examples/with-lingui/components/withLang.js index 5cd77fd5adfe9..06cc73f5e0a02 100644 --- a/examples/with-lingui/components/withLang.js +++ b/examples/with-lingui/components/withLang.js @@ -23,10 +23,7 @@ export default (Component, defaultLang = 'en') => const { language, catalogs, ...restProps } = this.props return ( - <I18nProvider - language={language} - catalogs={catalogs} - > + <I18nProvider language={language} catalogs={catalogs}> <Component {...restProps} /> </I18nProvider> ) diff --git a/examples/with-lingui/package.json b/examples/with-lingui/package.json index 91bfa9aa227bb..c1e6addba6947 100644 --- a/examples/with-lingui/package.json +++ b/examples/with-lingui/package.json @@ -30,4 +30,4 @@ "format": "po" }, "license": "ISC" -} \ No newline at end of file +} diff --git a/examples/with-mobx-react-lite/README.md b/examples/with-mobx-react-lite/README.md index 48a421e1f7760..fb4a36f3b4b81 100644 --- a/examples/with-mobx-react-lite/README.md +++ b/examples/with-mobx-react-lite/README.md @@ -59,40 +59,40 @@ The initial store data is returned from the `initializeData` function that recyc ```jsx function initializeData(initialData = store || {}) { - const { lastUpdate = Date.now(), light } = initialData; + const { lastUpdate = Date.now(), light } = initialData return { lastUpdate, - light: Boolean(light) - }; + light: Boolean(light), + } } ``` The observable store is created in a function component by passing a plain JavaScript object to the `useObservable` hook. Actions on the observable store (`start` and `stop`) are created in the same scope as the `store` in `store.js` and exported as named exports. ```js -store = useObservable(initializeData(props.initialData)); +store = useObservable(initializeData(props.initialData)) start = useCallback( action(() => { // Async operation that mutates the store }) -); +) stop = () => { // Does not mutate the store -}; +} ``` The component creates and exports a new React context provider that will make the store accessible to all of its descendents. ```jsx -return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>; +return <StoreContext.Provider value={store}>{children}</StoreContext.Provider> ``` The store is accessible at any depth by using the `StoreContext`. ```js -const store = useContext(StoreContext); +const store = useContext(StoreContext) ``` The clock, under `components/Clock.js`, reacts to changes in the observable `store` by means of the `useObserver` hook. @@ -106,5 +106,5 @@ return ( ))} // ... </div> -); +) ``` diff --git a/examples/with-mobx-state-tree-typescript/stores/store.ts b/examples/with-mobx-state-tree-typescript/stores/store.ts index 52d37cc80acba..1f1dc1f79f0d1 100644 --- a/examples/with-mobx-state-tree-typescript/stores/store.ts +++ b/examples/with-mobx-state-tree-typescript/stores/store.ts @@ -1,6 +1,12 @@ -import { applySnapshot, Instance, SnapshotIn, SnapshotOut, types } from "mobx-state-tree"; +import { + applySnapshot, + Instance, + SnapshotIn, + SnapshotOut, + types, +} from 'mobx-state-tree' -let store: IStore = null as any; +let store: IStore = null as any const Store = types .model({ @@ -8,40 +14,40 @@ const Store = types lastUpdate: types.Date, light: false, }) - .actions((self) => { - let timer; + .actions(self => { + let timer const start = () => { timer = setInterval(() => { // mobx-state-tree doesn't allow anonymous callbacks changing data. // Pass off to another action instead (need to cast self as any // because typescript doesn't yet know about the actions we're // adding to self here) - (self as any).update(); - }, 1000); - }; + ;(self as any).update() + }, 1000) + } const update = () => { - self.lastUpdate = new Date(Date.now()); - self.light = true; - }; + self.lastUpdate = new Date(Date.now()) + self.light = true + } const stop = () => { - clearInterval(timer); - }; - return { start, stop, update }; - }); + clearInterval(timer) + } + return { start, stop, update } + }) -export type IStore = Instance<typeof Store>; -export type IStoreSnapshotIn = SnapshotIn<typeof Store>; -export type IStoreSnapshotOut = SnapshotOut<typeof Store>; +export type IStore = Instance<typeof Store> +export type IStoreSnapshotIn = SnapshotIn<typeof Store> +export type IStoreSnapshotOut = SnapshotOut<typeof Store> export const initializeStore = (isServer, snapshot = null) => { if (isServer) { - store = Store.create({ foo: 6, lastUpdate: Date.now() }); + store = Store.create({ foo: 6, lastUpdate: Date.now() }) } - if (store as any === null) { - store = Store.create({ foo: 6, lastUpdate: Date.now() }); + if ((store as any) === null) { + store = Store.create({ foo: 6, lastUpdate: Date.now() }) } if (snapshot) { - applySnapshot(store, snapshot); + applySnapshot(store, snapshot) } - return store; -}; + return store +} diff --git a/examples/with-mobx-state-tree-typescript/tsconfig.json b/examples/with-mobx-state-tree-typescript/tsconfig.json index 6d284303d217c..57ec3cda5e5ee 100644 --- a/examples/with-mobx-state-tree-typescript/tsconfig.json +++ b/examples/with-mobx-state-tree-typescript/tsconfig.json @@ -17,13 +17,7 @@ "sourceMap": true, "skipLibCheck": true, "baseUrl": ".", - "typeRoots": [ - "./node_modules/@types" - ], - "lib": [ - "dom", - "es2015", - "es2016" - ] + "typeRoots": ["./node_modules/@types"], + "lib": ["dom", "es2015", "es2016"] } } diff --git a/examples/with-mobx-state-tree-typescript/tslint.json b/examples/with-mobx-state-tree-typescript/tslint.json index 0dc58e4c865c5..f2d7a99d260b4 100644 --- a/examples/with-mobx-state-tree-typescript/tslint.json +++ b/examples/with-mobx-state-tree-typescript/tslint.json @@ -1,9 +1,5 @@ { - "extends": [ - "tslint-config-standard", - "tslint:latest", - "tslint-react" - ], + "extends": ["tslint-config-standard", "tslint:latest", "tslint-react"], "rules": { "indent": [true, "spaces"], "jsx-no-lambda": false, @@ -11,10 +7,7 @@ "max-line-length": false, "no-console": false, "no-object-literal-type-assertion": false, - "no-submodule-imports": [ - true, - "next" - ], + "no-submodule-imports": [true, "next"], "no-unused-variable": false, "space-before-function-paren": false, "ter-indent": [true, 2], diff --git a/examples/with-react-intl/lang/en.json b/examples/with-react-intl/lang/en.json index d8df06b128825..d6de3be22bb5e 100644 --- a/examples/with-react-intl/lang/en.json +++ b/examples/with-react-intl/lang/en.json @@ -4,4 +4,4 @@ "nav.about": "About", "description": "An example app integrating React Intl with Next.js", "greeting": "Hello, World!" -} \ No newline at end of file +} diff --git a/examples/with-react-multi-carousel/README.md b/examples/with-react-multi-carousel/README.md index e4cfdfe081ba5..c452c004126ec 100644 --- a/examples/with-react-multi-carousel/README.md +++ b/examples/with-react-multi-carousel/README.md @@ -4,7 +4,6 @@ Source code is hosted on the [react-multi-carorusel](https://github.com/YIZHUANG [![Demo](https://react-multi-carousel.now.sh/) - ### Usage Install and run: @@ -22,7 +21,7 @@ The reason for that is i needed to implement a Carousel component for my own pro ## How does it work with ssr? -* On the server-side, we detect the user's device to decide how many items we are showing and then using flex-basis to assign * width to the carousel item. -* On the client-side, old fashion getting width of the container and assign the average of it to each carousel item. +- On the server-side, we detect the user's device to decide how many items we are showing and then using flex-basis to assign \* width to the carousel item. +- On the client-side, old fashion getting width of the container and assign the average of it to each carousel item. The UI part of this example is copy paste from for the sake of simplicity. [with-material-ui](https://github.com/zeit/next.js/tree/canary/examples/with-material-ui) diff --git a/examples/with-react-multi-carousel/now.json b/examples/with-react-multi-carousel/now.json index 9d78481eaada9..7769cc4945df1 100644 --- a/examples/with-react-multi-carousel/now.json +++ b/examples/with-react-multi-carousel/now.json @@ -1,7 +1,5 @@ { - "version": 2, - "name": "nextjs", - "builds": [ - { "src": "package.json", "use": "@now/next" } - ] + "version": 2, + "name": "nextjs", + "builds": [{ "src": "package.json", "use": "@now/next" }] } diff --git a/examples/with-reasonml-todo/README.md b/examples/with-reasonml-todo/README.md index 86cb6d1ee43c4..e1fe39d0a6d73 100644 --- a/examples/with-reasonml-todo/README.md +++ b/examples/with-reasonml-todo/README.md @@ -1,6 +1,6 @@ # Example app using ReasonML & ReasonReact components -This example builds upon the original `with-reasonml` example to sho how a +This example builds upon the original `with-reasonml` example to sho how a global state object can be used to track state across page within the application. It is intended to show how to build a simple, stateful application using hooks diff --git a/examples/with-redux-observable/README.md b/examples/with-redux-observable/README.md index c524654c84c1c..a8251c735f927 100644 --- a/examples/with-redux-observable/README.md +++ b/examples/with-redux-observable/README.md @@ -31,7 +31,6 @@ yarn yarn dev ``` - ### The idea behind the example This example is a page that renders information about Star-Wars characters. It diff --git a/examples/with-redux-saga/README.md b/examples/with-redux-saga/README.md index 2213f9a0cc7ed..ca03c564c4004 100644 --- a/examples/with-redux-saga/README.md +++ b/examples/with-redux-saga/README.md @@ -68,12 +68,12 @@ The digital clock is updated every second using the `runClockSaga` found in `sag All pages are also being wrapped by `next-redux-saga` using a helper function from `store.js`: ```js -import withRedux from "next-redux-wrapper"; -import nextReduxSaga from "next-redux-saga"; -import configureStore from "./store"; +import withRedux from 'next-redux-wrapper' +import nextReduxSaga from 'next-redux-saga' +import configureStore from './store' export function withReduxSaga(BaseComponent) { - return withRedux(configureStore)(nextReduxSaga(BaseComponent)); + return withRedux(configureStore)(nextReduxSaga(BaseComponent)) } /** @@ -90,13 +90,13 @@ export function withReduxSaga(BaseComponent) { If you need to pass `react-redux` connect args to your page, you could use the following helper instead: ```js -import withRedux from "next-redux-wrapper"; -import nextReduxSaga from "next-redux-saga"; -import configureStore from "./store"; +import withRedux from 'next-redux-wrapper' +import nextReduxSaga from 'next-redux-saga' +import configureStore from './store' export function withReduxSaga(...connectArgs) { return BaseComponent => - withRedux(configureStore, ...connectArgs)(nextReduxSaga(BaseComponent)); + withRedux(configureStore, ...connectArgs)(nextReduxSaga(BaseComponent)) } /** diff --git a/examples/with-redux/package.json b/examples/with-redux/package.json index 681921ca6e52e..93cf5165d4076 100644 --- a/examples/with-redux/package.json +++ b/examples/with-redux/package.json @@ -1,18 +1,18 @@ { - "name": "with-redux", - "version": "1.0.0", - "scripts": { - "dev": "next", - "build": "next build", - "start": "next start" - }, - "dependencies": { - "next": "latest", - "react": "^16.7.0", - "redux-devtools-extension": "^2.13.2", - "react-dom": "^16.7.0", - "react-redux": "^5.0.1", - "redux": "^3.6.0" - }, - "license": "ISC" - } \ No newline at end of file + "name": "with-redux", + "version": "1.0.0", + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "latest", + "react": "^16.7.0", + "redux-devtools-extension": "^2.13.2", + "react-dom": "^16.7.0", + "react-redux": "^5.0.1", + "redux": "^3.6.0" + }, + "license": "ISC" +} diff --git a/examples/with-sentry-simple/README.md b/examples/with-sentry-simple/README.md index e9b3a4d6d1700..93418892fd2e2 100644 --- a/examples/with-sentry-simple/README.md +++ b/examples/with-sentry-simple/README.md @@ -63,8 +63,8 @@ The Sentry DSN should then be updated in `_app.js`. ```js Sentry.init({ - dsn: 'PUT_YOUR_SENTRY_DSN_HERE' -}); + dsn: 'PUT_YOUR_SENTRY_DSN_HERE', +}) ``` _Note: Committing environment variables is not secure and is done here only for demonstration purposes. See the [`with-dotenv`](../with-dotenv) or [`with-now-env`](../with-now-env) for examples of how to set environment variables safely._ diff --git a/examples/with-sitemap-and-robots-express-server-typescript/README.md b/examples/with-sitemap-and-robots-express-server-typescript/README.md index dab0648fe1ec0..2b98ca1114e76 100644 --- a/examples/with-sitemap-and-robots-express-server-typescript/README.md +++ b/examples/with-sitemap-and-robots-express-server-typescript/README.md @@ -56,6 +56,7 @@ When you start this example locally: - robots.txt will be located at http://localhost:8000/robots.txt In case you want to deploy this example, replace the URL in the following locations with your own domain: + - `hostname` in `src/server/sitemap.ts` - `ROOT_URL` in `src/server/app.ts` - `Sitemap` at the bottom of `src/server/robots.txt` diff --git a/examples/with-sitemap-and-robots-express-server-typescript/now.json b/examples/with-sitemap-and-robots-express-server-typescript/now.json index 42b80ae7ba576..bb166af656ce8 100644 --- a/examples/with-sitemap-and-robots-express-server-typescript/now.json +++ b/examples/with-sitemap-and-robots-express-server-typescript/now.json @@ -1,6 +1,6 @@ { "env": { - "NODE_ENV": "production" + "NODE_ENV": "production" }, "scale": { "sfo1": { @@ -9,4 +9,4 @@ } }, "alias": "https://sitemap-robots-typescript.now.sh" -} \ No newline at end of file +} diff --git a/examples/with-sitemap-and-robots-express-server-typescript/src/server/app.ts b/examples/with-sitemap-and-robots-express-server-typescript/src/server/app.ts index d2f9ce03fd2e8..360d4eba41369 100644 --- a/examples/with-sitemap-and-robots-express-server-typescript/src/server/app.ts +++ b/examples/with-sitemap-and-robots-express-server-typescript/src/server/app.ts @@ -1,29 +1,31 @@ -import * as express from "express"; -import * as next from "next"; -import { addSitemap } from "./sitemap"; +import * as express from 'express' +import * as next from 'next' +import { addSitemap } from './sitemap' -const dev = process.env.NODE_ENV !== "production"; -const port = process.env.PORT || 8000; +const dev = process.env.NODE_ENV !== 'production' +const port = process.env.PORT || 8000 const ROOT_URL = dev ? `http://localhost:${port}` - : "https://sitemap-robots-typescript.now.sh"; + : 'https://sitemap-robots-typescript.now.sh' -const app = next({ dev }); -const handle = app.getRequestHandler(); +const app = next({ dev }) +const handle = app.getRequestHandler() // Nextjs's server prepared app.prepare().then(() => { - const server = express(); + const server = express() - addSitemap({ server }); + addSitemap({ server }) - server.get("*", (req, res) => { handle(req, res); }); + server.get('*', (req, res) => { + handle(req, res) + }) // starting express server - server.listen(port, (err) => { + server.listen(port, err => { if (err) { - throw err; + throw err } - console.log(`> Ready on ${ROOT_URL}`); - }); -}); + console.log(`> Ready on ${ROOT_URL}`) + }) +}) diff --git a/examples/with-sitemap-and-robots-express-server-typescript/src/server/posts.ts b/examples/with-sitemap-and-robots-express-server-typescript/src/server/posts.ts index 1fc4469c13d47..0623b3b750d8e 100644 --- a/examples/with-sitemap-and-robots-express-server-typescript/src/server/posts.ts +++ b/examples/with-sitemap-and-robots-express-server-typescript/src/server/posts.ts @@ -1,16 +1,16 @@ interface IPost { - name:string; - slug:string; + name: string + slug: string } const posts = () => { - const arrayOfPosts:IPost[] = []; - const n = 5; + const arrayOfPosts: IPost[] = [] + const n = 5 for (let i = 1; i < n + 1; i += 1) { - arrayOfPosts.push({ name: `Post ${i}`, slug: `post-${i}` }); + arrayOfPosts.push({ name: `Post ${i}`, slug: `post-${i}` }) } - return arrayOfPosts; -}; + return arrayOfPosts +} -export { IPost, posts }; +export { IPost, posts } diff --git a/examples/with-sitemap-and-robots-express-server-typescript/src/server/sitemap.ts b/examples/with-sitemap-and-robots-express-server-typescript/src/server/sitemap.ts index 32f481536765d..229c1c7bca862 100644 --- a/examples/with-sitemap-and-robots-express-server-typescript/src/server/sitemap.ts +++ b/examples/with-sitemap-and-robots-express-server-typescript/src/server/sitemap.ts @@ -1,45 +1,45 @@ -import * as path from "path"; -import * as sm from "sitemap"; -import { posts } from "./posts"; +import * as path from 'path' +import * as sm from 'sitemap' +import { posts } from './posts' const sitemap = sm.createSitemap({ cacheTime: 600000, // 600 sec - cache purge period - hostname: "https://sitemap-robots-typescript.now.sh", -}); + hostname: 'https://sitemap-robots-typescript.now.sh', +}) const addSitemap = ({ server }) => { - const Posts = posts(); + const Posts = posts() for (const post of Posts) { sitemap.add({ - changefreq: "daily", + changefreq: 'daily', priority: 0.9, url: `/posts/${post.slug}`, - }); + }) } sitemap.add({ - changefreq: "daily", + changefreq: 'daily', priority: 1, - url: "/a", - }); + url: '/a', + }) sitemap.add({ - changefreq: "daily", + changefreq: 'daily', priority: 1, - url: "/b", - }); + url: '/b', + }) // Note {} in next line is a placeholder filling the spot where the req parameter // would normally be listed (but isn't listed here since we aren't using it) - server.get("/sitemap.xml", ({}, res) => { + server.get('/sitemap.xml', ({}, res) => { sitemap.toXML((err, xml) => { if (err) { - res.status(500).end(); - return; + res.status(500).end() + return } - res.header("Content-Type", "application/xml"); - res.send(xml); - }); - }); -}; + res.header('Content-Type', 'application/xml') + res.send(xml) + }) + }) +} -export { addSitemap }; +export { addSitemap } diff --git a/examples/with-sitemap-and-robots-express-server-typescript/tsconfig.express.json b/examples/with-sitemap-and-robots-express-server-typescript/tsconfig.express.json index da376a498f3af..4efa10c193df5 100644 --- a/examples/with-sitemap-and-robots-express-server-typescript/tsconfig.express.json +++ b/examples/with-sitemap-and-robots-express-server-typescript/tsconfig.express.json @@ -17,15 +17,9 @@ "preserveConstEnums": true, "sourceMap": true, "skipLibCheck": true, - "typeRoots": [ - "./node_modules/@types" - ], + "typeRoots": ["./node_modules/@types"], "outDir": "./dist/server", - "lib": [ - "dom", - "es2015", - "es2016" - ] + "lib": ["dom", "es2015", "es2016"] }, "include": ["./src/server/**/*"] } diff --git a/examples/with-sitemap-and-robots-express-server-typescript/tsconfig.next.json b/examples/with-sitemap-and-robots-express-server-typescript/tsconfig.next.json index 9e56e62ac7f61..853628a6f5e20 100644 --- a/examples/with-sitemap-and-robots-express-server-typescript/tsconfig.next.json +++ b/examples/with-sitemap-and-robots-express-server-typescript/tsconfig.next.json @@ -17,15 +17,9 @@ "preserveConstEnums": true, "sourceMap": true, "skipLibCheck": true, - "typeRoots": [ - "./node_modules/@types" - ], + "typeRoots": ["./node_modules/@types"], "outDir": "./dist", - "lib": [ - "dom", - "es2015", - "es2016" - ] + "lib": ["dom", "es2015", "es2016"] }, "include": ["./src/**/*"], "exclude": ["./src/server/**/*"] diff --git a/examples/with-sitemap-and-robots-express-server-typescript/tslint.json b/examples/with-sitemap-and-robots-express-server-typescript/tslint.json index 0dc58e4c865c5..f2d7a99d260b4 100644 --- a/examples/with-sitemap-and-robots-express-server-typescript/tslint.json +++ b/examples/with-sitemap-and-robots-express-server-typescript/tslint.json @@ -1,9 +1,5 @@ { - "extends": [ - "tslint-config-standard", - "tslint:latest", - "tslint-react" - ], + "extends": ["tslint-config-standard", "tslint:latest", "tslint-react"], "rules": { "indent": [true, "spaces"], "jsx-no-lambda": false, @@ -11,10 +7,7 @@ "max-line-length": false, "no-console": false, "no-object-literal-type-assertion": false, - "no-submodule-imports": [ - true, - "next" - ], + "no-submodule-imports": [true, "next"], "no-unused-variable": false, "space-before-function-paren": false, "ter-indent": [true, 2], diff --git a/examples/with-sitemap-and-robots-express-server/README.md b/examples/with-sitemap-and-robots-express-server/README.md index 00e6d6354c3b6..fbff3700bb8fe 100644 --- a/examples/with-sitemap-and-robots-express-server/README.md +++ b/examples/with-sitemap-and-robots-express-server/README.md @@ -57,6 +57,7 @@ When you start this example locally: - robots.txt will be located at http://localhost:8000/robots.txt In case you want to deploy this example, replace the URL in the following locations with your own domain: + - `hostname` in `server/sitemap.js` - `ROOT_URL` in `server/app.js` - `Sitemap` at the bottom of `robots.txt` diff --git a/examples/with-sitemap-and-robots-express-server/now.json b/examples/with-sitemap-and-robots-express-server/now.json index 02ed5e70b6526..aa36e4bab8345 100644 --- a/examples/with-sitemap-and-robots-express-server/now.json +++ b/examples/with-sitemap-and-robots-express-server/now.json @@ -1,6 +1,6 @@ { "env": { - "NODE_ENV": "production" + "NODE_ENV": "production" }, "scale": { "sfo1": { @@ -9,4 +9,4 @@ } }, "alias": "https://sitemap-robots.now.sh" -} \ No newline at end of file +} diff --git a/examples/with-ts-node/server/index.ts b/examples/with-ts-node/server/index.ts index 6d15fa39f36cf..1497de98c8106 100644 --- a/examples/with-ts-node/server/index.ts +++ b/examples/with-ts-node/server/index.ts @@ -2,15 +2,15 @@ import { createServer } from 'http' import { parse } from 'url' import * as next from 'next' -const port = parseInt(process.env.PORT, 10) || 3000; -const dev = process.env.NODE_ENV !== 'production'; -const app = next({ dev }); -const handle = app.getRequestHandler(); +const port = parseInt(process.env.PORT, 10) || 3000 +const dev = process.env.NODE_ENV !== 'production' +const app = next({ dev }) +const handle = app.getRequestHandler() app.prepare().then(() => { createServer((req, res) => { - const parsedUrl = parse(req.url, true); - const { pathname, query } = parsedUrl; + const parsedUrl = parse(req.url, true) + const { pathname, query } = parsedUrl if (pathname === '/a') { app.render(req, res, '/a', query) @@ -19,9 +19,8 @@ app.prepare().then(() => { } else { handle(req, res, parsedUrl) } - }) - .listen(port, (err) => { + }).listen(port, err => { if (err) throw err console.log(`> Ready on http://localhost:${port}`) }) -}); +}) diff --git a/examples/with-ts-node/tsconfig.json b/examples/with-ts-node/tsconfig.json index 87a7898ab8014..ec2e8f75e0542 100644 --- a/examples/with-ts-node/tsconfig.json +++ b/examples/with-ts-node/tsconfig.json @@ -15,13 +15,7 @@ "skipLibCheck": true, "rootDir": ".", "baseUrl": ".", - "typeRoots": [ - "./node_modules/@types" - ], - "lib": [ - "dom", - "es2015", - "es2016" - ] + "typeRoots": ["./node_modules/@types"], + "lib": ["dom", "es2015", "es2016"] } } diff --git a/examples/with-typescript-styled-components/tsconfig.json b/examples/with-typescript-styled-components/tsconfig.json index 9bccadf45eeef..a5a071f65e061 100644 --- a/examples/with-typescript-styled-components/tsconfig.json +++ b/examples/with-typescript-styled-components/tsconfig.json @@ -15,6 +15,6 @@ "removeComments": false, "preserveConstEnums": true, "sourceMap": true, - "esModuleInterop": true, + "esModuleInterop": true } } diff --git a/examples/with-typescript/interfaces/index.ts b/examples/with-typescript/interfaces/index.ts index 6f5f6e663af59..bd2fc1ec4c80a 100644 --- a/examples/with-typescript/interfaces/index.ts +++ b/examples/with-typescript/interfaces/index.ts @@ -5,6 +5,6 @@ // import User from 'path/to/interfaces'; export type User = { - id: number, - name: string, + id: number + name: string } diff --git a/examples/with-typescript/tsconfig.json b/examples/with-typescript/tsconfig.json index 382a0ac315510..c65399cb28e5d 100644 --- a/examples/with-typescript/tsconfig.json +++ b/examples/with-typescript/tsconfig.json @@ -6,10 +6,7 @@ "forceConsistentCasingInFileNames": true, "isolatedModules": true, "jsx": "preserve", - "lib": [ - "dom", - "es2017" - ], + "lib": ["dom", "es2017"], "module": "esnext", "moduleResolution": "node", "noEmit": true, @@ -21,11 +18,6 @@ "strict": true, "target": "esnext" }, - "exclude": [ - "node_modules" - ], - "include": [ - "**/*.ts", - "**/*.tsx" - ] + "exclude": ["node_modules"], + "include": ["**/*.ts", "**/*.tsx"] } diff --git a/examples/with-typescript/utils/sample-api.ts b/examples/with-typescript/utils/sample-api.ts index 07ae8754062a9..a326dfa976fa2 100644 --- a/examples/with-typescript/utils/sample-api.ts +++ b/examples/with-typescript/utils/sample-api.ts @@ -1,4 +1,4 @@ -import { User } from "../interfaces"; +import { User } from '../interfaces' /** Dummy user data. */ export const dataArray: User[] = [ @@ -6,7 +6,7 @@ export const dataArray: User[] = [ { id: 102, name: 'Bob' }, { id: 103, name: 'Caroline' }, { id: 104, name: 'Dave' }, -]; +] /** * Calls a mock API which finds a user by ID from the list above. @@ -14,7 +14,7 @@ export const dataArray: User[] = [ * Throws an error if not found. */ export async function findData(id: number | string) { - const selected = dataArray.find((data) => data.id === Number(id)) + const selected = dataArray.find(data => data.id === Number(id)) if (!selected) { throw new Error('Cannot find user') diff --git a/examples/with-typings-for-css-modules/style.css.d.ts b/examples/with-typings-for-css-modules/style.css.d.ts index 36996950a1ddb..eeebb52704b08 100644 --- a/examples/with-typings-for-css-modules/style.css.d.ts +++ b/examples/with-typings-for-css-modules/style.css.d.ts @@ -1,3 +1,3 @@ -export const example: string; -export const example__description: string; -export const exampleDescription: string; +export const example: string +export const example__description: string +export const exampleDescription: string diff --git a/examples/with-typings-for-css-modules/tsconfig.json b/examples/with-typings-for-css-modules/tsconfig.json index 06b51be310ede..b358694983ed7 100644 --- a/examples/with-typings-for-css-modules/tsconfig.json +++ b/examples/with-typings-for-css-modules/tsconfig.json @@ -15,4 +15,4 @@ "preserveConstEnums": true, "sourceMap": true } -} \ No newline at end of file +} diff --git a/examples/with-yarn-workspaces/package.json b/examples/with-yarn-workspaces/package.json index 99be3b76589a8..60a794a3f006d 100644 --- a/examples/with-yarn-workspaces/package.json +++ b/examples/with-yarn-workspaces/package.json @@ -1,6 +1,8 @@ { "private": true, - "workspaces": ["packages/*"], + "workspaces": [ + "packages/*" + ], "scripts": { "dev": "yarn --cwd packages/web-app dev", "build": "yarn --cwd packages/web-app build", diff --git a/examples/with-zones/blog/now.json b/examples/with-zones/blog/now.json index cd0f93b816af2..79c8f30c9086f 100644 --- a/examples/with-zones/blog/now.json +++ b/examples/with-zones/blog/now.json @@ -1,13 +1,11 @@ { - "version": 2, - "name": "with-zones-blog", - "alias": "with-zones-blog.nextjs.org", - "build": { - "env": { - "DEPLOY": "true" - } - }, - "builds": [ - { "src": "package.json", "use": "@now/next" } - ] -} \ No newline at end of file + "version": 2, + "name": "with-zones-blog", + "alias": "with-zones-blog.nextjs.org", + "build": { + "env": { + "DEPLOY": "true" + } + }, + "builds": [{ "src": "package.json", "use": "@now/next" }] +} diff --git a/examples/with-zones/home/now.json b/examples/with-zones/home/now.json index a7ced4f31364e..cdede10bbd8f7 100644 --- a/examples/with-zones/home/now.json +++ b/examples/with-zones/home/now.json @@ -1,16 +1,12 @@ { - "version": 2, - "name": "with-zones-home", - "alias": "with-zones.nextjs.org", - "build": { - "env": { - "DEPLOY": "true" - } - }, - "builds": [ - { "src": "package.json", "use": "@now/next" } - ], - "routes": [ - { "src": "/blog", "dest": "https://with-zones-blog.nextjs.org" } - ] -} \ No newline at end of file + "version": 2, + "name": "with-zones-home", + "alias": "with-zones.nextjs.org", + "build": { + "env": { + "DEPLOY": "true" + } + }, + "builds": [{ "src": "package.json", "use": "@now/next" }], + "routes": [{ "src": "/blog", "dest": "https://with-zones-blog.nextjs.org" }] +} diff --git a/examples/with-zones/rules-dev.json b/examples/with-zones/rules-dev.json index efa6027cdfa09..fa3350a131371 100644 --- a/examples/with-zones/rules-dev.json +++ b/examples/with-zones/rules-dev.json @@ -1,6 +1,6 @@ { "rules": [ - {"pathname": "/blog", "dest": "http://localhost:5000"}, - {"pathname": "/**", "dest": "http://localhost:4000"} + { "pathname": "/blog", "dest": "http://localhost:5000" }, + { "pathname": "/**", "dest": "http://localhost:4000" } ] } diff --git a/lerna.json b/lerna.json index a374ee370efc2..579e2ae82a42b 100644 --- a/lerna.json +++ b/lerna.json @@ -1,19 +1,14 @@ { "npmClient": "yarn", "useWorkspaces": true, - "packages": [ - "packages/*" - ], + "packages": ["packages/*"], "command": { "version": { "exact": true }, "publish": { "npmClient": "npm", - "allowBranch": [ - "master", - "canary" - ], + "allowBranch": ["master", "canary"], "registry": "https://registry.npmjs.org/" } }, diff --git a/package.json b/package.json index b68bddc49ee7b..8c9a5ca0c7538 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "coveralls": "cat ./test/coverage/lcov.info | coveralls", "lint": "lerna run typescript && standard && standard --parser typescript-eslint-parser --plugin typescript \"packages/**/*.ts\"", "lint-fix": "standard --fix && standard --fix --parser typescript-eslint-parser --plugin typescript \"packages/**/*.ts\"", - "prettier": "prettier --write \"examples/**/*.js\" && yarn lint-fix", + "prettier": "prettier --write \"**/*.{ts,md}\" \"{packages,examples}/**/*.{js,json}\" && yarn lint-fix", "typescript": "lerna run typescript", "prepublish": "lerna run prepublish", "publish-canary": "lerna version prerelease --preid canary --force-publish && release --pre", @@ -33,15 +33,13 @@ "git add" ], "*.js": [ + "prettier --write", "standard --fix", "git add" ], "*.{ts,tsx}": [ - "tslint -c tslint.json --fix", - "git add" - ], - "packages/**/bin/*": [ - "standard --fix", + "prettier --write", + "standard --fix --parser typescript-eslint-parser --plugin typescript", "git add" ] }, @@ -103,7 +101,6 @@ "standard": "12.0.1", "taskr": "1.1.0", "tree-kill": "1.2.1", - "tslint": "5.16.0", "typescript": "3.4.5", "typescript-eslint-parser": "22.0.0", "wait-port": "0.2.2", diff --git a/packages/next-bundle-analyzer/index.js b/packages/next-bundle-analyzer/index.js index de09b33a3b8bd..19ea5bbd2a324 100644 --- a/packages/next-bundle-analyzer/index.js +++ b/packages/next-bundle-analyzer/index.js @@ -6,7 +6,9 @@ module.exports = ({ enabled = true } = {}) => (nextConfig = {}) => { config.plugins.push( new BundleAnalyzerPlugin({ analyzerMode: 'static', - reportFilename: options.isServer ? '../analyze/server.html' : './analyze/client.html' + reportFilename: options.isServer + ? '../analyze/server.html' + : './analyze/client.html' }) ) } diff --git a/packages/next-bundle-analyzer/readme.md b/packages/next-bundle-analyzer/readme.md index fa69257f42cec..18aa9dedeb114 100644 --- a/packages/next-bundle-analyzer/readme.md +++ b/packages/next-bundle-analyzer/readme.md @@ -19,8 +19,10 @@ yarn add @next/bundle-analyzer Create a next.config.js (and make sure you have next-bundle-analyzer set up) ```js -const withBundleAnalyzer = require("@next/bundle-analyzer")({ enabled: process.env.ANALYZE === "true" }); -module.exports = withBundleAnalyzer({}); +const withBundleAnalyzer = require('@next/bundle-analyzer')({ + enabled: process.env.ANALYZE === 'true', +}) +module.exports = withBundleAnalyzer({}) ``` Then you can run the command below: diff --git a/packages/next-mdx/readme.md b/packages/next-mdx/readme.md index 79b2a70466e22..6b3c0cf7f64bb 100644 --- a/packages/next-mdx/readme.md +++ b/packages/next-mdx/readme.md @@ -30,13 +30,9 @@ Optionally you can provide [MDX options](https://github.com/mdx-js/mdx#options): // next.config.js const withMDX = require('@next/mdx')({ options: { - mdPlugins: [ - - ], - hastPlugins: [ - - ] - } + mdPlugins: [], + hastPlugins: [], + }, }) module.exports = withMDX() ``` @@ -49,7 +45,7 @@ const withMDX = require('@next/mdx')() module.exports = withMDX({ webpack(config, options) { return config - } + }, }) ``` @@ -58,7 +54,7 @@ Optionally you can match other file extensions for MDX compilation, by default o ```js // next.config.js const withMDX = require('@next/mdx')({ - extension: /\.(md|mdx)$/ + extension: /\.(md|mdx)$/, }) module.exports = withMDX() ``` @@ -70,9 +66,9 @@ Define the `pagesExtensions` option to have Next.js handle `.mdx` files in the ` ```js // next.config.js const withMDX = require('@next/mdx')({ - extension: /\.mdx?$/ + extension: /\.mdx?$/, }) module.exports = withMDX({ - pageExtensions: ['js', 'jsx', 'mdx'] + pageExtensions: ['js', 'jsx', 'mdx'], }) ``` diff --git a/packages/next-server/dynamic.d.ts b/packages/next-server/dynamic.d.ts index e3eca5332e103..73a3c2391c171 100644 --- a/packages/next-server/dynamic.d.ts +++ b/packages/next-server/dynamic.d.ts @@ -1,2 +1,2 @@ export * from './dist/lib/dynamic' -export {default} from './dist/lib/dynamic' +export { default } from './dist/lib/dynamic' diff --git a/packages/next-server/head.d.ts b/packages/next-server/head.d.ts index 393b748a3693b..a474f2d17b022 100644 --- a/packages/next-server/head.d.ts +++ b/packages/next-server/head.d.ts @@ -1,2 +1,2 @@ export * from './dist/lib/head' -export {default} from './dist/lib/head' +export { default } from './dist/lib/head' diff --git a/packages/next-server/index.d.ts b/packages/next-server/index.d.ts index 71df82686d68f..a59671c2036c0 100644 --- a/packages/next-server/index.d.ts +++ b/packages/next-server/index.d.ts @@ -1,2 +1,2 @@ -import Server, {ServerConstructor} from './dist/server/next-server' +import Server, { ServerConstructor } from './dist/server/next-server' export default function(options: ServerConstructor): Server diff --git a/packages/next-server/lib/amp.ts b/packages/next-server/lib/amp.ts index 0acc53f00b0be..116ca6d96e913 100644 --- a/packages/next-server/lib/amp.ts +++ b/packages/next-server/lib/amp.ts @@ -1,10 +1,10 @@ import React from 'react' -import {AmpModeContext} from './amphtml-context' +import { AmpModeContext } from './amphtml-context' export function isAmp({ - enabled= false, - hybrid= false, - hasQuery= false, + enabled = false, + hybrid = false, + hasQuery = false, } = {}) { return enabled && (!hybrid || (hybrid && hasQuery)) } @@ -15,11 +15,8 @@ export function useAmp() { return isAmp(ampMode) // && ampMode.hasQuery } -export function withAmp( - Component: any, - { hybrid = false } = {}, -): any { - function WithAmpWrapper(props= {}) { +export function withAmp(Component: any, { hybrid = false } = {}): any { + function WithAmpWrapper(props = {}) { const ampMode = React.useContext(AmpModeContext) ampMode.enabled = true ampMode.hybrid = hybrid diff --git a/packages/next-server/lib/constants.ts b/packages/next-server/lib/constants.ts index bb832b95aa4b5..2a2834aba5da8 100644 --- a/packages/next-server/lib/constants.ts +++ b/packages/next-server/lib/constants.ts @@ -10,10 +10,7 @@ export const SERVER_DIRECTORY = 'server' export const SERVERLESS_DIRECTORY = 'serverless' export const CONFIG_FILE = 'next.config.js' export const BUILD_ID_FILE = 'BUILD_ID' -export const BLOCKED_PAGES = [ - '/_document', - '/_app', -] +export const BLOCKED_PAGES = ['/_document', '/_app'] export const CLIENT_PUBLIC_FILES_PATH = 'public' export const CLIENT_STATIC_FILES_PATH = 'static' export const CLIENT_STATIC_FILES_RUNTIME = 'runtime' diff --git a/packages/next-server/lib/loadable-context.ts b/packages/next-server/lib/loadable-context.ts index dafe8a72a7cac..503127c2c9751 100644 --- a/packages/next-server/lib/loadable-context.ts +++ b/packages/next-server/lib/loadable-context.ts @@ -3,4 +3,6 @@ import * as React from 'react' type CaptureFn = (moduleName: string) => void // @ts-ignore for some reason the React types don't like this, but it's correct. -export const LoadableContext: React.Context<CaptureFn | null> = React.createContext(null) +export const LoadableContext: React.Context<CaptureFn | null> = React.createContext( + null +) diff --git a/packages/next-server/lib/loadable.d.ts b/packages/next-server/lib/loadable.d.ts index 86ccc1a86a377..1c68ec67aa27c 100644 --- a/packages/next-server/lib/loadable.d.ts +++ b/packages/next-server/lib/loadable.d.ts @@ -9,6 +9,6 @@ declare namespace LoadableExport { } } -declare const LoadableExport: LoadableExport.ILoadable; +declare const LoadableExport: LoadableExport.ILoadable export = LoadableExport diff --git a/packages/next-server/lib/loadable.js b/packages/next-server/lib/loadable.js index 38f0b4cffa162..758b077c272c7 100644 --- a/packages/next-server/lib/loadable.js +++ b/packages/next-server/lib/loadable.js @@ -136,9 +136,13 @@ function createLoadableComponent (loadFn, options) { } // Client only - if (!initialized && typeof window !== 'undefined' && typeof opts.webpack === 'function') { + if ( + !initialized && + typeof window !== 'undefined' && + typeof opts.webpack === 'function' + ) { const moduleIds = opts.webpack() - READY_INITIALIZERS.push((ids) => { + READY_INITIALIZERS.push(ids => { for (const moduleId of moduleIds) { if (ids.indexOf(moduleId) !== -1) { return init() @@ -237,7 +241,7 @@ function createLoadableComponent (loadFn, options) { this.setState({ error: null, loading: true, timedOut: false }) res = loadFn(opts.loader) this._loadModule() - }; + } render () { if (this.state.loading || this.state.error) { @@ -292,8 +296,8 @@ Loadable.preloadAll = () => { }) } -Loadable.preloadReady = (ids) => { - return new Promise((resolve) => { +Loadable.preloadReady = ids => { + return new Promise(resolve => { const res = () => { initialized = true return resolve() diff --git a/packages/next-server/lib/mitt.ts b/packages/next-server/lib/mitt.ts index 7def05b0ed3c9..e0e3a90ec036f 100644 --- a/packages/next-server/lib/mitt.ts +++ b/packages/next-server/lib/mitt.ts @@ -19,7 +19,7 @@ type Handler = (...evts: any[]) => void export type MittEmitter = { on(type: string, handler: Handler): void off(type: string, handler: Handler): void - emit(type: string, ...evts: any[]): void, + emit(type: string, ...evts: any[]): void } export default function mitt(): MittEmitter { @@ -27,7 +27,7 @@ export default function mitt(): MittEmitter { return { on(type: string, handler: Handler) { - (all[type] || (all[type] = [])).push(handler) + ;(all[type] || (all[type] = [])).push(handler) }, off(type: string, handler: Handler) { @@ -38,7 +38,9 @@ export default function mitt(): MittEmitter { }, emit(type: string, ...evts: any[]) { - (all[type] || []).slice().map((handler: Handler) => { handler(...evts) }) + ;(all[type] || []).slice().map((handler: Handler) => { + handler(...evts) + }) }, } } diff --git a/packages/next-server/lib/router/router.ts b/packages/next-server/lib/router/router.ts index aa0e77a065f18..d4551adb8747a 100644 --- a/packages/next-server/lib/router/router.ts +++ b/packages/next-server/lib/router/router.ts @@ -1,15 +1,19 @@ /* global __NEXT_DATA__ */ // tslint:disable:no-console -import { ParsedUrlQuery } from 'querystring'; -import { ComponentType } from 'react'; -import { parse } from 'url'; +import { ParsedUrlQuery } from 'querystring' +import { ComponentType } from 'react' +import { parse } from 'url' -import mitt, { MittEmitter } from '../mitt'; +import mitt, { MittEmitter } from '../mitt' import { - AppContextType, formatWithValidation, getURL, loadGetInitialProps, NextPageContext, -} from '../utils'; -import { rewriteUrlForNextExport } from './rewrite-url-for-export'; -import { getRouteRegex } from './utils'; + AppContextType, + formatWithValidation, + getURL, + loadGetInitialProps, + NextPageContext, +} from '../utils' +import { rewriteUrlForNextExport } from './rewrite-url-for-export' +import { getRouteRegex } from './utils' function toRoute(path: string): string { return path.replace(/\/$/, '') || '/' @@ -19,17 +23,17 @@ export type BaseRouter = { route: string pathname: string query: ParsedUrlQuery - asPath: string, + asPath: string } type RouteInfo = { - Component: ComponentType, - props?: any, + Component: ComponentType + props?: any err?: Error - error?: any, + error?: any } -type Subscription = (data: {App?: ComponentType} & RouteInfo) => void +type Subscription = (data: { App?: ComponentType } & RouteInfo) => void type BeforePopStateCallback = (state: any) => boolean @@ -41,7 +45,7 @@ export default class Router implements BaseRouter { /** * Map of all components loaded in `Router` */ - components: {[pathname: string]: RouteInfo} + components: { [pathname: string]: RouteInfo } subscriptions: Set<Subscription> componentLoadCancel: (() => void) | null pageLoader: any @@ -49,7 +53,24 @@ export default class Router implements BaseRouter { static events: MittEmitter = mitt() - constructor(pathname: string, query: ParsedUrlQuery, as: string, { initialProps, pageLoader, App, Component, err }: {initialProps: any, pageLoader: any, Component: ComponentType, App: ComponentType, err?: Error}) { + constructor( + pathname: string, + query: ParsedUrlQuery, + as: string, + { + initialProps, + pageLoader, + App, + Component, + err, + }: { + initialProps: any + pageLoader: any + Component: ComponentType + App: ComponentType + err?: Error + } + ) { // represents the current component key this.route = toRoute(pathname) @@ -79,7 +100,11 @@ export default class Router implements BaseRouter { if (typeof window !== 'undefined') { // in order for `e.state` to work on the `onpopstate` event // we have to register the initial route upon initialization - this.changeState('replaceState', formatWithValidation({ pathname, query }), as) + this.changeState( + 'replaceState', + formatWithValidation({ pathname, query }), + as + ) window.addEventListener('popstate', this.onPopState) window.addEventListener('unload', () => { @@ -87,7 +112,10 @@ export default class Router implements BaseRouter { // navigating back from an external site if (history.state) { const { url, as, options }: any = history.state - this.changeState('replaceState', url, as, { ...options, fromExternal: true }) + this.changeState('replaceState', url, as, { + ...options, + fromExternal: true, + }) } }) } @@ -109,7 +137,11 @@ export default class Router implements BaseRouter { // Actually, for (1) we don't need to nothing. But it's hard to detect that event. // So, doing the following for (1) does no harm. const { pathname, query } = this - this.changeState('replaceState', formatWithValidation({ pathname, query }), getURL()) + this.changeState( + 'replaceState', + formatWithValidation({ pathname, query }), + getURL() + ) return } @@ -128,11 +160,13 @@ export default class Router implements BaseRouter { const { url, as, options } = e.state if (process.env.NODE_ENV !== 'production') { if (typeof url === 'undefined' || typeof as === 'undefined') { - console.warn('`popstate` event triggered but `event.state` did not have `url` or `as` https://err.sh/zeit/next.js/popstate-state-empty') + console.warn( + '`popstate` event triggered but `event.state` did not have `url` or `as` https://err.sh/zeit/next.js/popstate-state-empty' + ) } } this.replace(url, as, options) - }; + } update(route: string, Component: ComponentType) { const data = this.components[route] @@ -185,7 +219,12 @@ export default class Router implements BaseRouter { return this.change('replaceState', url, as, options) } - change(method: string, _url: string, _as: string, options: any): Promise<boolean> { + change( + method: string, + _url: string, + _as: string, + options: any + ): Promise<boolean> { return new Promise((resolve, reject) => { // If url and as provided as an object representation, // we'll format them into the string version here. @@ -234,11 +273,13 @@ export default class Router implements BaseRouter { const { re: routeRegex, groups } = getRouteRegex(route) const routeMatch = routeRegex.exec(as) if (!routeMatch) { - console.error("Your `<Link>`'s `as` value is incompatible with the `href` value. This is invalid.") + console.error( + "Your `<Link>`'s `as` value is incompatible with the `href` value. This is invalid." + ) return resolve(false) } - Object.keys(groups).forEach((slugName) => { + Object.keys(groups).forEach(slugName => { const m = routeMatch[groups[slugName]] if (m !== undefined) { query[slugName] = decodeURIComponent(m) @@ -250,7 +291,7 @@ export default class Router implements BaseRouter { // If shallow is true and the route exists in the router cache we reuse the previous result // @ts-ignore pathname is always a string - this.getRouteInfo(route, pathname, query, as, shallow).then((routeInfo) => { + this.getRouteInfo(route, pathname, query, as, shallow).then(routeInfo => { const { error } = routeInfo if (error && error.cancelled) { @@ -294,7 +335,13 @@ export default class Router implements BaseRouter { } } - getRouteInfo(route: string, pathname: string, query: any, as: string, shallow: boolean = false): Promise<RouteInfo> { + getRouteInfo( + route: string, + pathname: string, + query: any, + as: string, + shallow: boolean = false + ): Promise<RouteInfo> { const cachedRouteInfo = this.components[route] // If there is a shallow route transition possible @@ -308,69 +355,90 @@ export default class Router implements BaseRouter { return resolve(cachedRouteInfo) } - this.fetchComponent(route).then((Component) => resolve({Component}), reject) - }) as Promise<RouteInfo>).then((routeInfo: RouteInfo) => { - const { Component } = routeInfo - - if (process.env.NODE_ENV !== 'production') { - const { isValidElementType } = require('react-is') - if (!isValidElementType(Component)) { - throw new Error(`The default export is not a React Component in page: "${pathname}"`) + this.fetchComponent(route).then( + Component => resolve({ Component }), + reject + ) + }) as Promise<RouteInfo>) + .then((routeInfo: RouteInfo) => { + const { Component } = routeInfo + + if (process.env.NODE_ENV !== 'production') { + const { isValidElementType } = require('react-is') + if (!isValidElementType(Component)) { + throw new Error( + `The default export is not a React Component in page: "${pathname}"` + ) + } } - } - return (new Promise((resolve, reject) => { - const ctx = { pathname, query, asPath: as } - this.getInitialProps(Component, ctx).then((props) => { - routeInfo.props = props - this.components[route] = routeInfo - resolve(routeInfo) - }, reject) - }) as Promise<RouteInfo>) - }).catch((err) => { - return (new Promise((resolve) => { - if (err.code === 'PAGE_LOAD_ERROR') { - // If we can't load the page it could be one of following reasons - // 1. Page doesn't exists - // 2. Page does exist in a different zone - // 3. Internal error while loading the page - - // So, doing a hard reload is the proper way to deal with this. - window.location.href = as - - // Changing the URL doesn't block executing the current code path. - // So, we need to mark it as a cancelled error and stop the routing logic. - err.cancelled = true - // @ts-ignore TODO: fix the control flow here - return resolve({ error: err }) - } + return new Promise((resolve, reject) => { + const ctx = { pathname, query, asPath: as } + this.getInitialProps(Component, ctx).then(props => { + routeInfo.props = props + this.components[route] = routeInfo + resolve(routeInfo) + }, reject) + }) as Promise<RouteInfo> + }) + .catch(err => { + return new Promise(resolve => { + if (err.code === 'PAGE_LOAD_ERROR') { + // If we can't load the page it could be one of following reasons + // 1. Page doesn't exists + // 2. Page does exist in a different zone + // 3. Internal error while loading the page + + // So, doing a hard reload is the proper way to deal with this. + window.location.href = as + + // Changing the URL doesn't block executing the current code path. + // So, we need to mark it as a cancelled error and stop the routing logic. + err.cancelled = true + // @ts-ignore TODO: fix the control flow here + return resolve({ error: err }) + } - if (err.cancelled) { - // @ts-ignore TODO: fix the control flow here - return resolve({ error: err }) - } + if (err.cancelled) { + // @ts-ignore TODO: fix the control flow here + return resolve({ error: err }) + } - resolve(this.fetchComponent('/_error').then((Component) => { - const routeInfo: RouteInfo = { Component, err } - const ctx = { err, pathname, query } - return (new Promise((resolve) => { - this.getInitialProps(Component, ctx).then((props) => { - routeInfo.props = props - routeInfo.error = err - resolve(routeInfo) - }, (gipErr) => { - console.error('Error in error page `getInitialProps`: ', gipErr) - routeInfo.error = err - routeInfo.props = {} - resolve(routeInfo) + resolve( + this.fetchComponent('/_error').then(Component => { + const routeInfo: RouteInfo = { Component, err } + const ctx = { err, pathname, query } + return new Promise(resolve => { + this.getInitialProps(Component, ctx).then( + props => { + routeInfo.props = props + routeInfo.error = err + resolve(routeInfo) + }, + gipErr => { + console.error( + 'Error in error page `getInitialProps`: ', + gipErr + ) + routeInfo.error = err + routeInfo.props = {} + resolve(routeInfo) + } + ) + }) as Promise<RouteInfo> }) - }) as Promise<RouteInfo>) - })) - }) as Promise<RouteInfo>) - }) + ) + }) as Promise<RouteInfo> + }) } - set(route: string, pathname: string, query: any, as: string, data: RouteInfo): void { + set( + route: string, + pathname: string, + query: any, + as: string, + data: RouteInfo + ): void { this.route = route this.pathname = pathname this.query = query @@ -388,11 +456,11 @@ export default class Router implements BaseRouter { onlyAHashChange(as: string): boolean { if (!this.asPath) return false - const [ oldUrlNoHash, oldHash ] = this.asPath.split('#') - const [ newUrlNoHash, newHash ] = as.split('#') + const [oldUrlNoHash, oldHash] = this.asPath.split('#') + const [newUrlNoHash, newHash] = as.split('#') // Makes sure we scroll to the provided hash if the url/hash are the same - if (newHash && (oldUrlNoHash === newUrlNoHash) && (oldHash === newHash)) { + if (newHash && oldUrlNoHash === newUrlNoHash && oldHash === newHash) { return true } @@ -409,7 +477,7 @@ export default class Router implements BaseRouter { } scrollToHash(as: string): void { - const [ , hash ] = as.split('#') + const [, hash] = as.split('#') // Scroll to top if the hash is just `#` with no value if (hash === '') { window.scrollTo(0, 0) @@ -442,7 +510,11 @@ export default class Router implements BaseRouter { prefetch(url: string): Promise<void> { return new Promise((resolve, reject) => { // Prefetch is not supported in development mode because it would trigger on-demand-entries - if (process.env.NODE_ENV !== 'production' || process.env.__NEXT_EXPERIMENTAL_DEBUG) return + if ( + process.env.NODE_ENV !== 'production' || + process.env.__NEXT_EXPERIMENTAL_DEBUG + ) + return const { pathname } = parse(url) // @ts-ignore pathname is always defined @@ -453,14 +525,16 @@ export default class Router implements BaseRouter { async fetchComponent(route: string): Promise<ComponentType> { let cancelled = false - const cancel = this.componentLoadCancel = () => { + const cancel = (this.componentLoadCancel = () => { cancelled = true - } + }) const Component = await this.pageLoader.loadPage(route) if (cancelled) { - const error: any = new Error(`Abort fetching component for route: "${route}"`) + const error: any = new Error( + `Abort fetching component for route: "${route}"` + ) error.cancelled = true throw error } @@ -472,13 +546,22 @@ export default class Router implements BaseRouter { return Component } - async getInitialProps(Component: ComponentType, ctx: NextPageContext): Promise<any> { + async getInitialProps( + Component: ComponentType, + ctx: NextPageContext + ): Promise<any> { let cancelled = false - const cancel = () => { cancelled = true } + const cancel = () => { + cancelled = true + } this.componentLoadCancel = cancel const { Component: App } = this.components['/_app'] - const props = await loadGetInitialProps<AppContextType<Router>>(App, { Component, router: this, ctx }) + const props = await loadGetInitialProps<AppContextType<Router>>(App, { + Component, + router: this, + ctx, + }) if (cancel === this.componentLoadCancel) { this.componentLoadCancel = null @@ -503,7 +586,7 @@ export default class Router implements BaseRouter { notify(data: RouteInfo): void { const { Component: App } = this.components['/_app'] - this.subscriptions.forEach((fn) => fn({ ...data, App })) + this.subscriptions.forEach(fn => fn({ ...data, App })) } subscribe(fn: Subscription): () => void { diff --git a/packages/next-server/lib/router/utils.ts b/packages/next-server/lib/router/utils.ts index e1920fd4883f3..f91190b8c345e 100644 --- a/packages/next-server/lib/router/utils.ts +++ b/packages/next-server/lib/router/utils.ts @@ -1,9 +1,9 @@ export function getRouteRegex( - route: string, + route: string ): { re: RegExp; groups: { [groupName: string]: number } } { const escapedRoute = (route.replace(/\/$/, '') || '/').replace( /[|\\{}()[\]^$+*?.-]/g, - '\\$&', + '\\$&' ) const groups: { [groupName: string]: number } = {} @@ -16,7 +16,7 @@ export function getRouteRegex( $1.replace(/\\\$$/, '').replace(/\\([|\\{}()[\]^$+*?.-])/g, '$1') ] = groupIndex++), $1.lastIndexOf('$') === $1.length - 1 ? '(?:/([^/]+?))?' : '/([^/]+?)' - ), + ) ) return { diff --git a/packages/next-server/lib/utils.ts b/packages/next-server/lib/utils.ts index d7ac463e79c1f..cde63e20c4fb9 100644 --- a/packages/next-server/lib/utils.ts +++ b/packages/next-server/lib/utils.ts @@ -13,7 +13,7 @@ export type NextComponentType< IP = {}, P = {} > = ComponentType<P> & { - getInitialProps?(context: C): Promise<IP>, + getInitialProps?(context: C): Promise<IP> } export type DocumentType = NextComponentType< @@ -33,23 +33,23 @@ export type Enhancer<C> = (Component: C) => C export type ComponentsEnhancer = | { enhanceApp?: Enhancer<AppType> - enhanceComponent?: Enhancer<NextComponentType>, + enhanceComponent?: Enhancer<NextComponentType> } | Enhancer<NextComponentType> export type RenderPageResult = { html: string head?: Array<JSX.Element | null> - dataOnly?: true, + dataOnly?: true } export type RenderPage = ( - options?: ComponentsEnhancer, + options?: ComponentsEnhancer ) => RenderPageResult | Promise<RenderPageResult> export type BaseContext = { res?: ServerResponse - [k: string]: any, + [k: string]: any } export type NEXT_DATA = { @@ -63,7 +63,7 @@ export type NEXT_DATA = { runtimeConfig?: { [key: string]: any } nextExport?: boolean dynamicIds?: string[] - err?: Error & { statusCode?: number }, + err?: Error & { statusCode?: number } } /** @@ -100,11 +100,11 @@ export interface NextPageContext { export type AppContextType<R extends BaseRouter = BaseRouter> = { Component: NextComponentType<NextPageContext> router: R - ctx: NextPageContext, + ctx: NextPageContext } export type AppInitialProps = { - pageProps: any, + pageProps: any } export type AppPropsType< @@ -112,15 +112,15 @@ export type AppPropsType< P = {} > = AppInitialProps & { Component: NextComponentType<NextPageContext, any, P> - router: R, + router: R } export type DocumentContext = NextPageContext & { - renderPage: RenderPage, + renderPage: RenderPage } export type DocumentInitialProps = RenderPageResult & { - styles?: React.ReactElement[], + styles?: React.ReactElement[] } export type DocumentProps = DocumentInitialProps & { @@ -133,8 +133,8 @@ export type DocumentProps = DocumentInitialProps & { devFiles: string[] files: string[] dynamicImports: ManifestItem[] - assetPrefix?: string, - canonicalBase: string, + assetPrefix?: string + canonicalBase: string } /** @@ -180,7 +180,7 @@ export async function loadGetInitialProps< if (process.env.NODE_ENV !== 'production') { if (Component.prototype && Component.prototype.getInitialProps) { const message = `"${getDisplayName( - Component, + 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) } @@ -201,20 +201,18 @@ export async function loadGetInitialProps< // if page component doesn't have getInitialProps // set cache-control header to stale-while-revalidate if (ctx.Component && !ctx.Component.getInitialProps) { - const customAppGetInitialProps = (Component as any).origGetInitialProps && ( + const customAppGetInitialProps = + (Component as any).origGetInitialProps && (Component as any).origGetInitialProps !== Component.getInitialProps - ) if (!customAppGetInitialProps && res && res.setHeader) { - res.setHeader( - 'Cache-Control', 's-maxage=86400, stale-while-revalidate', - ) + res.setHeader('Cache-Control', 's-maxage=86400, stale-while-revalidate') } } if (!props) { const message = `"${getDisplayName( - Component, + Component )}.getInitialProps()" should resolve to an object. But found "${props}" instead.` throw new Error(message) } @@ -239,14 +237,14 @@ export const urlObjectKeys = [ export function formatWithValidation( url: UrlObject, - options?: URLFormatOptions, + options?: URLFormatOptions ) { if (process.env.NODE_ENV === 'development') { if (url !== null && typeof url === 'object') { - Object.keys(url).forEach((key) => { + Object.keys(url).forEach(key => { if (urlObjectKeys.indexOf(key) === -1) { console.warn( - `Unknown key passed via urlObject into url.format: ${key}`, + `Unknown key passed via urlObject into url.format: ${key}` ) } }) diff --git a/packages/next-server/server/config.ts b/packages/next-server/server/config.ts index 4c646044e0a21..687e2b0064a36 100644 --- a/packages/next-server/server/config.ts +++ b/packages/next-server/server/config.ts @@ -4,7 +4,7 @@ import { CONFIG_FILE } from '../lib/constants' const targets = ['server', 'serverless'] -const defaultConfig: {[key: string]: any} = { +const defaultConfig: { [key: string]: any } = { env: [], webpack: null, webpackDevMiddleware: null, @@ -28,7 +28,7 @@ const defaultConfig: {[key: string]: any} = { cpus: Math.max( 1, (Number(process.env.CIRCLE_NODE_TOTAL) || - (os.cpus() || { length: 1 }).length) - 1, + (os.cpus() || { length: 1 }).length) - 1 ), dynamicRouting: false, autoExport: false, @@ -41,10 +41,10 @@ const defaultConfig: {[key: string]: any} = { }, } -function assignDefaults(userConfig: {[key: string]: any}) { +function assignDefaults(userConfig: { [key: string]: any }) { Object.keys(userConfig).forEach((key: string) => { const maybeObject = userConfig[key] - if ((!!maybeObject) && (maybeObject.constructor === Object)) { + if (!!maybeObject && maybeObject.constructor === Object) { userConfig[key] = { ...(defaultConfig[key] || {}), ...userConfig[key], @@ -61,14 +61,18 @@ function normalizeConfig(phase: string, config: any) { if (typeof config.then === 'function') { throw new Error( - '> Promise returned in next config. https://err.sh/zeit/next.js/promise-in-next-config.md', + '> Promise returned in next config. https://err.sh/zeit/next.js/promise-in-next-config.md' ) } } return config } -export default function loadConfig(phase: string, dir: string, customConfig: any) { +export default function loadConfig( + phase: string, + dir: string, + customConfig: any +) { if (customConfig) { return assignDefaults({ configOrigin: 'server', ...customConfig }) } @@ -79,16 +83,25 @@ export default function loadConfig(phase: string, dir: string, customConfig: any // If config file was found if (path && path.length) { const userConfigModule = require(path) - const userConfig = normalizeConfig(phase, userConfigModule.default || userConfigModule) + const userConfig = normalizeConfig( + phase, + userConfigModule.default || userConfigModule + ) if (userConfig.target && !targets.includes(userConfig.target)) { - throw new Error(`Specified target is invalid. Provided: "${userConfig.target}" should be one of ${targets.join(', ')}`) + throw new Error( + `Specified target is invalid. Provided: "${ + userConfig.target + }" should be one of ${targets.join(', ')}` + ) } if (userConfig.amp && userConfig.amp.canonicalBase) { - const { canonicalBase } = userConfig.amp || {} as any + const { canonicalBase } = userConfig.amp || ({} as any) userConfig.amp = userConfig.amp || {} - userConfig.amp.canonicalBase = (canonicalBase.endsWith('/') - ? canonicalBase.slice(0, -1) : canonicalBase) || '' + userConfig.amp.canonicalBase = + (canonicalBase.endsWith('/') + ? canonicalBase.slice(0, -1) + : canonicalBase) || '' } return assignDefaults({ configOrigin: CONFIG_FILE, ...userConfig }) diff --git a/packages/next-server/server/get-dynamic-import-bundles.ts b/packages/next-server/server/get-dynamic-import-bundles.ts index 12df48fe07c47..5612cb779b9c7 100644 --- a/packages/next-server/server/get-dynamic-import-bundles.ts +++ b/packages/next-server/server/get-dynamic-import-bundles.ts @@ -1,22 +1,28 @@ export type ManifestItem = { - id: number|string, - name: string, - file: string, - publicPath: string, + id: number | string + name: string + file: string + publicPath: string } -export type Manifest = {[moduleId: string]: ManifestItem[]} +export type Manifest = { [moduleId: string]: ManifestItem[] } type DynamicImportBundles = Set<ManifestItem> // Based on https://github.com/jamiebuilds/react-loadable/pull/132 -export function getDynamicImportBundles(manifest: Manifest, moduleIds: string[]): DynamicImportBundles { - return moduleIds.reduce((bundles: DynamicImportBundles, moduleId: string): DynamicImportBundles => { - if (typeof manifest[moduleId] === 'undefined') { - return bundles - } +export function getDynamicImportBundles( + manifest: Manifest, + moduleIds: string[] +): DynamicImportBundles { + return moduleIds.reduce( + (bundles: DynamicImportBundles, moduleId: string): DynamicImportBundles => { + if (typeof manifest[moduleId] === 'undefined') { + return bundles + } - manifest[moduleId].map((item) => bundles.add(item)) - return bundles - }, new Set()) + manifest[moduleId].map(item => bundles.add(item)) + return bundles + }, + new Set() + ) } diff --git a/packages/next-server/server/get-page-files.ts b/packages/next-server/server/get-page-files.ts index de1670f3ef16e..9d79e60d32b66 100644 --- a/packages/next-server/server/get-page-files.ts +++ b/packages/next-server/server/get-page-files.ts @@ -1,13 +1,16 @@ import { normalizePagePath } from './normalize-page-path' export type BuildManifest = { - devFiles: string[], + devFiles: string[] 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) let files = buildManifest.pages[normalizedPage] @@ -17,7 +20,9 @@ export function getPageFiles(buildManifest: BuildManifest, page: string): string 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 [] } diff --git a/packages/next-server/server/lib/path-match.ts b/packages/next-server/server/lib/path-match.ts index 3c71e4ac06ff3..c452810e14ac3 100644 --- a/packages/next-server/server/lib/path-match.ts +++ b/packages/next-server/server/lib/path-match.ts @@ -9,7 +9,7 @@ export default () => { const keys: any[] = [] const re = pathToRegexp(path, keys, {}) - return (pathname: string|undefined, params?: any) => { + return (pathname: string | undefined, params?: any) => { const m = re.exec(pathname) if (!m) return false diff --git a/packages/next-server/server/lib/recursive-readdir-sync.ts b/packages/next-server/server/lib/recursive-readdir-sync.ts index f5f755d1a797a..9ef1367269e82 100644 --- a/packages/next-server/server/lib/recursive-readdir-sync.ts +++ b/packages/next-server/server/lib/recursive-readdir-sync.ts @@ -7,7 +7,11 @@ import { join } from 'path' * @param {string=dir`} rootDir Used to replace the initial path, only the relative path is left, it's faster than path.relative. * @returns Array holding all relative paths */ -export function recursiveReadDirSync(dir: string, arr: string[] = [], rootDir = dir): string[] { +export function recursiveReadDirSync( + dir: string, + arr: string[] = [], + rootDir = dir +): string[] { const result = fs.readdirSync(dir) result.forEach((part: string) => { diff --git a/packages/next-server/server/load-components.ts b/packages/next-server/server/load-components.ts index 80789d983bed4..ac69bbfb5b42e 100644 --- a/packages/next-server/server/load-components.ts +++ b/packages/next-server/server/load-components.ts @@ -18,14 +18,14 @@ export type LoadComponentsReturnType = { reactLoadableManifest?: any Document?: any DocumentMiddleware?: any - App?: any, + App?: any } export async function loadComponents( distDir: string, buildId: string, pathname: string, - serverless: boolean, + serverless: boolean ): Promise<LoadComponentsReturnType> { if (serverless) { const Component = await requirePage(pathname, distDir, serverless) @@ -37,7 +37,7 @@ export async function loadComponents( CLIENT_STATIC_FILES_PATH, buildId, 'pages', - '_document', + '_document' ) const appPath = join( distDir, @@ -45,7 +45,7 @@ export async function loadComponents( CLIENT_STATIC_FILES_PATH, buildId, 'pages', - '_app', + '_app' ) const DocumentMod = require(documentPath) diff --git a/packages/next-server/server/next-server.ts b/packages/next-server/server/next-server.ts index b650ddde48b4f..8afd4b34f2ab1 100644 --- a/packages/next-server/server/next-server.ts +++ b/packages/next-server/server/next-server.ts @@ -37,7 +37,7 @@ export type ServerConstructor = { dir?: string staticMarkup?: boolean quiet?: boolean - conf?: NextConfig, + conf?: NextConfig } export default class Server { @@ -55,10 +55,10 @@ export default class Server { buildId: string generateEtags: boolean runtimeConfig?: { [key: string]: any } - assetPrefix?: string, - canonicalBase: string, + assetPrefix?: string + canonicalBase: string autoExport: boolean - dev?: boolean, + dev?: boolean } router: Router private dynamicRoutes?: Array<{ page: string; match: RouteMatch }> @@ -130,7 +130,7 @@ export default class Server { private handleRequest( req: IncomingMessage, res: ServerResponse, - parsedUrl?: UrlWithParsedQuery, + parsedUrl?: UrlWithParsedQuery ): Promise<void> { // Parse url if parsedUrl not provided if (!parsedUrl || typeof parsedUrl !== 'object') { @@ -144,7 +144,7 @@ export default class Server { } res.statusCode = 200 - return this.run(req, res, parsedUrl).catch((err) => { + return this.run(req, res, parsedUrl).catch(err => { this.logError(err) res.statusCode = 500 res.end('Internal Server Error') @@ -187,7 +187,7 @@ export default class Server { const p = join( this.distDir, CLIENT_STATIC_FILES_PATH, - ...(params.path || []), + ...(params.path || []) ) await this.serveStatic(req, res, p, parsedUrl) }, @@ -257,7 +257,7 @@ export default class Server { private async handleApiRequest( req: IncomingMessage, res: ServerResponse, - pathname: string, + pathname: string ) { const resolverFunction = await this.resolveApiRequest(pathname) if (resolverFunction === null) { @@ -278,7 +278,7 @@ export default class Server { return getPagePath( pathname, this.distDir, - this.nextConfig.target === 'serverless', + this.nextConfig.target === 'serverless' ) } @@ -288,7 +288,7 @@ export default class Server { const serverBuildPath = join(this.distDir, SERVER_DIRECTORY) const pagesManifest = require(join(serverBuildPath, PAGES_MANIFEST)) - publicFiles.forEach((path) => { + publicFiles.forEach(path => { const unixPath = path.replace(/\\/g, '/') // Only include public files that will not replace a page path if (!pagesManifest[unixPath]) { @@ -307,23 +307,23 @@ export default class Server { private getDynamicRoutes() { const manifest = require(this.buildManifest) - const dynamicRoutedPages = Object.keys(manifest.pages).filter((p) => - p.includes('/$'), + const dynamicRoutedPages = Object.keys(manifest.pages).filter(p => + p.includes('/$') ) return dynamicRoutedPages - .map((page) => ({ + .map(page => ({ page, match: getRouteMatch(page), })) .sort((a, b) => - Math.sign(a.page.match(/\/\$/g)!.length - b.page.match(/\/\$/g)!.length), + Math.sign(a.page.match(/\/\$/g)!.length - b.page.match(/\/\$/g)!.length) ) } private async run( req: IncomingMessage, res: ServerResponse, - parsedUrl: UrlWithParsedQuery, + parsedUrl: UrlWithParsedQuery ) { try { const fn = this.router.match(req, res, parsedUrl) @@ -350,7 +350,7 @@ export default class Server { private async sendHTML( req: IncomingMessage, res: ServerResponse, - html: string, + html: string ) { const { generateEtags, poweredByHeader } = this.renderOpts return sendHTML(req, res, html, { generateEtags, poweredByHeader }) @@ -361,7 +361,7 @@ export default class Server { res: ServerResponse, pathname: string, query: ParsedUrlQuery = {}, - parsedUrl?: UrlWithParsedQuery, + parsedUrl?: UrlWithParsedQuery ): Promise<void> { const url: any = req.url if (isInternalUrl(url)) { @@ -389,7 +389,7 @@ export default class Server { private async findPageComponents( pathname: string, - query: ParsedUrlQuery = {}, + query: ParsedUrlQuery = {} ) { const serverless = !this.renderOpts.dev && this.nextConfig.target === 'serverless' @@ -400,7 +400,7 @@ export default class Server { this.distDir, this.buildId, (pathname === '/' ? '/index' : pathname) + '.amp', - serverless, + serverless ) } catch (err) { if (err.code !== 'ENOENT') throw err @@ -410,7 +410,7 @@ export default class Server { this.distDir, this.buildId, pathname, - serverless, + serverless ) } @@ -420,7 +420,7 @@ export default class Server { pathname: string, query: ParsedUrlQuery = {}, result: LoadComponentsReturnType, - opts: any, + opts: any ) { // handle static page if (typeof result.Component === 'string') { @@ -450,22 +450,22 @@ export default class Server { }: { amphtml?: boolean hasAmp?: boolean - dataOnly?: boolean, - } = {}, + dataOnly?: boolean + } = {} ): Promise<string | null> { return this.findPageComponents(pathname, query) .then( - (result) => { + result => { return this.renderToHTMLWithComponents( req, res, pathname, query, result, - { ...this.renderOpts, amphtml, hasAmp, dataOnly }, + { ...this.renderOpts, amphtml, hasAmp, dataOnly } ) }, - (err) => { + err => { if (err.code !== 'ENOENT' || !this.dynamicRoutes) { return Promise.reject(err) } @@ -477,22 +477,22 @@ export default class Server { } return this.findPageComponents(dynamicRoute.page, query).then( - (result) => + result => this.renderToHTMLWithComponents( req, res, dynamicRoute.page, { ...query, ...params }, result, - { ...this.renderOpts, amphtml, hasAmp, dataOnly }, - ), + { ...this.renderOpts, amphtml, hasAmp, dataOnly } + ) ) } return Promise.reject(err) - }, + } ) - .catch((err) => { + .catch(err => { if (err && err.code === 'ENOENT') { res.statusCode = 404 return this.renderErrorToHTML(null, req, res, pathname, query) @@ -509,11 +509,11 @@ export default class Server { req: IncomingMessage, res: ServerResponse, pathname: string, - query: ParsedUrlQuery = {}, + query: ParsedUrlQuery = {} ): Promise<void> { res.setHeader( 'Cache-Control', - 'no-cache, no-store, max-age=0, must-revalidate', + 'no-cache, no-store, max-age=0, must-revalidate' ) const html = await this.renderErrorToHTML(err, req, res, pathname, query) if (html === null) { @@ -527,7 +527,7 @@ export default class Server { req: IncomingMessage, res: ServerResponse, _pathname: string, - query: ParsedUrlQuery = {}, + query: ParsedUrlQuery = {} ) { const result = await this.findPageComponents('/_error', query) return this.renderToHTMLWithComponents(req, res, '/_error', query, result, { @@ -539,7 +539,7 @@ export default class Server { public async render404( req: IncomingMessage, res: ServerResponse, - parsedUrl?: UrlWithParsedQuery, + parsedUrl?: UrlWithParsedQuery ): Promise<void> { const url: any = req.url const { pathname, query } = parsedUrl ? parsedUrl : parseUrl(url, true) @@ -554,7 +554,7 @@ export default class Server { req: IncomingMessage, res: ServerResponse, path: string, - parsedUrl?: UrlWithParsedQuery, + parsedUrl?: UrlWithParsedQuery ): Promise<void> { if (!this.isServeableUrl(path)) { return this.render404(req, res, parsedUrl) @@ -594,7 +594,7 @@ export default class Server { throw new Error( `Could not find a valid build in the '${ this.distDir - }' directory! Try building your app with 'next build' before starting the server.`, + }' directory! Try building your app with 'next build' before starting the server.` ) } diff --git a/packages/next-server/server/optimize-amp.ts b/packages/next-server/server/optimize-amp.ts index 86676943c59df..6457e5d617480 100644 --- a/packages/next-server/server/optimize-amp.ts +++ b/packages/next-server/server/optimize-amp.ts @@ -1,9 +1,9 @@ -import { ParsedUrlQuery } from "querystring" +import { ParsedUrlQuery } from 'querystring' interface IOptimizerConfig { - transforms?: string[], - validAmp?: boolean, - verbose?: boolean, + transforms?: string[] + validAmp?: boolean + verbose?: boolean } interface IOptimizer { @@ -16,7 +16,10 @@ interface IOptimizeOptions { query?: ParsedUrlQuery } -export default async function optimize(html: string, { amphtml, query }: IOptimizeOptions): Promise<string> { +export default async function optimize( + html: string, + { amphtml, query }: IOptimizeOptions +): Promise<string> { let ampOptimizer: IOptimizer try { ampOptimizer = require('amp-toolbox-optimizer') diff --git a/packages/next-server/server/require.ts b/packages/next-server/server/require.ts index 3db2aab76004d..f8bc3fc787ef3 100644 --- a/packages/next-server/server/require.ts +++ b/packages/next-server/server/require.ts @@ -1,7 +1,11 @@ import fs from 'fs' -import {join} from 'path' -import {promisify} from 'util' -import {PAGES_MANIFEST, SERVER_DIRECTORY, SERVERLESS_DIRECTORY} from '../lib/constants' +import { join } from 'path' +import { promisify } from 'util' +import { + PAGES_MANIFEST, + SERVER_DIRECTORY, + SERVERLESS_DIRECTORY, +} from '../lib/constants' import { normalizePagePath } from './normalize-page-path' const readFile = promisify(fs.readFile) @@ -12,8 +16,15 @@ export function pageNotFoundError(page: string): Error { return err } -export function getPagePath(page: string, distDir: string, serverless: boolean): string { - const serverBuildPath = join(distDir, serverless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY) +export function getPagePath( + page: string, + distDir: string, + serverless: boolean +): string { + const serverBuildPath = join( + distDir, + serverless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY + ) const pagesManifest = require(join(serverBuildPath, PAGES_MANIFEST)) try { @@ -36,7 +47,11 @@ export function getPagePath(page: string, distDir: string, serverless: boolean): return join(serverBuildPath, pagesManifest[page]) } -export function requirePage(page: string, distDir: string, serverless: boolean): any { +export function requirePage( + page: string, + distDir: string, + serverless: boolean +): any { const pagePath = getPagePath(page, distDir, serverless) if (pagePath.endsWith('.html')) { return readFile(pagePath, 'utf8') diff --git a/packages/next-server/server/router.ts b/packages/next-server/server/router.ts index 087c02b5752cc..446c48592bfc7 100644 --- a/packages/next-server/server/router.ts +++ b/packages/next-server/server/router.ts @@ -14,8 +14,8 @@ export type Route = { req: IncomingMessage, res: ServerResponse, params: Params, - parsedUrl: UrlWithParsedQuery, - ) => void, + parsedUrl: UrlWithParsedQuery + ) => void } export default class Router { @@ -31,7 +31,7 @@ export default class Router { match( req: IncomingMessage, res: ServerResponse, - parsedUrl: UrlWithParsedQuery, + parsedUrl: UrlWithParsedQuery ) { const { pathname } = parsedUrl for (const route of this.routes) { diff --git a/packages/next-server/server/send-html.ts b/packages/next-server/server/send-html.ts index 6fb5e955f70b4..a344a1c0d0c15 100644 --- a/packages/next-server/server/send-html.ts +++ b/packages/next-server/server/send-html.ts @@ -1,9 +1,17 @@ -import {IncomingMessage, ServerResponse} from 'http' +import { IncomingMessage, ServerResponse } from 'http' import generateETag from 'etag' import fresh from 'fresh' import { isResSent } from '../lib/utils' -export function sendHTML(req: IncomingMessage, res: ServerResponse, html: string, { generateEtags, poweredByHeader }: {generateEtags: boolean, poweredByHeader: boolean}) { +export function sendHTML( + req: IncomingMessage, + res: ServerResponse, + html: string, + { + generateEtags, + poweredByHeader, + }: { generateEtags: boolean; poweredByHeader: boolean } +) { if (isResSent(res)) return const etag = generateEtags ? generateETag(html) : undefined diff --git a/packages/next-server/server/serve-static.ts b/packages/next-server/server/serve-static.ts index e96c593b32cfc..823cb1dfeef76 100644 --- a/packages/next-server/server/serve-static.ts +++ b/packages/next-server/server/serve-static.ts @@ -1,14 +1,18 @@ -import {IncomingMessage, ServerResponse} from 'http' +import { IncomingMessage, ServerResponse } from 'http' import send from 'send' // since send doesn't support wasm yet 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) => { send(req, path) .on('directory', () => { - // We don't allow directories to be read. + // We don't allow directories to be read. const err: any = new Error('No directory access') err.code = 'ENOENT' reject(err) diff --git a/packages/next-server/server/utils.ts b/packages/next-server/server/utils.ts index 94ff61d09d4ec..5e1a6be70d7e5 100644 --- a/packages/next-server/server/utils.ts +++ b/packages/next-server/server/utils.ts @@ -1,9 +1,6 @@ import { BLOCKED_PAGES } from '../lib/constants' -const internalPrefixes = [ - /^\/_next\//, - /^\/static\//, -] +const internalPrefixes = [/^\/_next\//, /^\/static\//] export function isInternalUrl(url: string): boolean { for (const prefix of internalPrefixes) { @@ -16,7 +13,7 @@ export function isInternalUrl(url: string): boolean { } export function isBlockedPage(pathname: string): boolean { - return (BLOCKED_PAGES.indexOf(pathname) !== -1) + return BLOCKED_PAGES.indexOf(pathname) !== -1 } export function cleanAmpPath(pathname: string): string { diff --git a/packages/next-server/taskfile-typescript.js b/packages/next-server/taskfile-typescript.js index 87945a728359c..5f5c633d83aae 100644 --- a/packages/next-server/taskfile-typescript.js +++ b/packages/next-server/taskfile-typescript.js @@ -39,7 +39,13 @@ try { } // update file's data - file.data = Buffer.from(result.outputText.replace(/process\.env\.__NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8') + file.data = Buffer.from( + result.outputText.replace( + /process\.env\.__NEXT_VERSION/, + `"${require('./package.json').version}"` + ), + 'utf8' + ) }) } } catch (err) { diff --git a/packages/next-server/taskfile.js b/packages/next-server/taskfile.js index 1c7593ff0f418..bc24e77c9e874 100644 --- a/packages/next-server/taskfile.js +++ b/packages/next-server/taskfile.js @@ -1,12 +1,18 @@ const notifier = require('node-notifier') export async function lib (task, opts) { - await task.source(opts.src || 'lib/**/*.+(js|ts|tsx)').typescript({ module: 'commonjs' }).target('dist/lib') + await task + .source(opts.src || 'lib/**/*.+(js|ts|tsx)') + .typescript({ module: 'commonjs' }) + .target('dist/lib') notify('Compiled lib files') } export async function server (task, opts) { - await task.source(opts.src || 'server/**/*.+(js|ts|tsx)').typescript({ module: 'commonjs' }).target('dist/server') + await task + .source(opts.src || 'server/**/*.+(js|ts|tsx)') + .typescript({ module: 'commonjs' }) + .target('dist/server') notify('Compiled server files') } diff --git a/packages/next-server/tsconfig.json b/packages/next-server/tsconfig.json index 681bfa21fefc2..f033b0dad1fa0 100644 --- a/packages/next-server/tsconfig.json +++ b/packages/next-server/tsconfig.json @@ -7,9 +7,5 @@ "moduleResolution": "node", "jsx": "react" }, - "exclude": [ - "./dist/**", - "./*.d.ts", - "./constants.d.ts" - ] + "exclude": ["./dist/**", "./*.d.ts", "./constants.d.ts"] } diff --git a/packages/next-server/types/index.d.ts b/packages/next-server/types/index.d.ts index c2848292bd9d5..56b4e1541cb8c 100644 --- a/packages/next-server/types/index.d.ts +++ b/packages/next-server/types/index.d.ts @@ -1 +1 @@ -declare module 'react-ssr-prepass' \ No newline at end of file +declare module 'react-ssr-prepass' diff --git a/packages/next/README.md b/packages/next/README.md index 630e69c39e8b8..2a0d73eed09ac 100644 --- a/packages/next/README.md +++ b/packages/next/README.md @@ -135,7 +135,6 @@ So far, we get: - Server rendering and indexing of `./pages` - Static file serving. `./static/` is mapped to `/static/` (given you [create a `./static/` directory](#static-file-serving-eg-images) inside your project) - ### Automatic code splitting Every `import` you declare gets bundled and served with each page. That means pages never load unnecessary code! @@ -161,7 +160,6 @@ export default CowsayHi </ul> </details> - We bundle [styled-jsx](https://github.com/zeit/styled-jsx) to provide support for isolated scoped CSS. The aim is to support "shadow CSS" similar to Web Components, which unfortunately [do not support server-rendering and are JS-only](https://github.com/w3c/webcomponents/issues/71). ```jsx @@ -213,7 +211,6 @@ Please see the [styled-jsx documentation](https://www.npmjs.com/package/styled-j </ul> </details> - It's possible to use any existing CSS-in-JS solution. The simplest one is inline styles: ```jsx @@ -268,7 +265,6 @@ _Note: Don't name the `static` or `public` directory anything else. The names ca </ul> </details> - We expose a built-in component for appending elements to the `<head>` of the page. ```jsx @@ -335,7 +331,6 @@ _Note: `<title>` and `<meta>` elements need to be contained as **direct** childr </ul> </details> - When you need state, lifecycle hooks or **initial data population** you can export a `React.Component` (instead of a stateless function, like shown above): ```jsx @@ -408,7 +403,6 @@ Next.js does not ship a routes manifest with every possible route in the applica </ul> </details> - Client-side transitions between routes can be enabled via a `<Link>` component. **Basic Example** @@ -502,7 +496,6 @@ To inject the `pathname`, `query` or `asPath` in your component, you can use [wi </ul> </details> - The component `<Link>` can also receive a URL object and it will automatically format it to create the URL string. ```jsx @@ -611,7 +604,6 @@ The default behaviour of `<Link>` is to scroll to the top of the page. When ther </ul> </details> - You can also do client-side page transitions using the `next/router` ```jsx @@ -675,7 +667,7 @@ import Router from 'next/router' const handler = () => { Router.push({ pathname: '/about', - query: { name: 'Zeit' } + query: { name: 'Zeit' }, }) } @@ -741,7 +733,6 @@ Router.events.on('routeChangeError', (err, url) => { </ul> </details> - Shallow routing allows you to change the URL without running `getInitialProps`. You'll receive the updated `pathname` and the `query` via the `router` prop (injected using [`withRouter`](#using-a-higher-order-component)), without losing state. You can do this by invoking either `Router.push` or `Router.replace` with the `shallow: true` option. Here's an example: @@ -786,7 +777,6 @@ componentDidUpdate(prevProps) { </ul> </details> - If you want to access the `router` object inside any component in your app, you can use the `withRouter` Higher-Order Component. Here's how to use it: ```jsx @@ -795,7 +785,7 @@ import { withRouter } from 'next/router' function ActiveLink({ children, router, href }) { const style = { marginRight: 10, - color: router.pathname === href ? 'red' : 'black' + color: router.pathname === href ? 'red' : 'black', } const handleClick = e => { @@ -826,7 +816,6 @@ The above `router` object comes with an API similar to [`next/router`](#imperati </ul> </details> - Next.js has an API which allows you to prefetch pages. Since Next.js server-renders your pages, this allows all the future interaction paths of your app to be instant. Effectively Next.js gives you the great initial download performance of a _website_, with the ahead-of-time download capabilities of an _app_. [Read more](https://zeit.co/blog/next#anticipation-is-the-key-to-performance). @@ -933,7 +922,6 @@ export default withRouter(MyLink) </ul> </details> - Typically you start your next server with `next start`. It's possible, however, to start a server 100% programmatically in order to customize routes, use route patterns, etc. When using a custom server with a server file, for example called `server.js`, make sure you update the scripts key in `package.json` to: @@ -1007,7 +995,7 @@ To disable this behavior & prevent routing based on files in `/pages`, simply se ```js // next.config.js module.exports = { - useFileSystemPublicRoutes: false + useFileSystemPublicRoutes: false, } ``` @@ -1064,7 +1052,6 @@ app.prepare().then(() => { </ul> </details> - Next.js supports TC39 [dynamic import proposal](https://github.com/tc39/proposal-dynamic-import) for JavaScript. With that, you could import JavaScript modules (inc. React Components) dynamically and work with them. @@ -1130,7 +1117,7 @@ import dynamic from 'next/dynamic' const DynamicComponentWithCustomLoading = dynamic( () => import('../components/hello2'), { - loading: () => <p>...</p> + loading: () => <p>...</p>, } ) @@ -1155,7 +1142,7 @@ import dynamic from 'next/dynamic' const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { - ssr: false + ssr: false, } ) @@ -1181,7 +1168,7 @@ const HelloBundle = dynamic({ modules: () => { const components = { Hello1: () => import('../components/hello1'), - Hello2: () => import('../components/hello2') + Hello2: () => import('../components/hello2'), } return components @@ -1192,7 +1179,7 @@ const HelloBundle = dynamic({ <Hello1 /> <Hello2 /> </div> - ) + ), }) function DynamicBundle() { @@ -1212,7 +1199,6 @@ export default DynamicBundle </ul> </details> - Next.js uses the `App` component to initialize pages. You can override it and control the page initialization. Which allows you to do amazing things like: - Persisting layout between page changes @@ -1261,7 +1247,6 @@ export default MyApp </ul> </details> - - Is rendered on the server side - Is used to change the initial server side rendered document markup - Commonly used to implement server side rendering for css-in-js libraries like [styled-components](/examples/with-styled-components) or [emotion](/examples/with-emotion). [styled-jsx](https://github.com/zeit/styled-jsx) is included with Next.js by default. @@ -1326,7 +1311,7 @@ class MyDocument extends Document { // useful for wrapping the whole react tree enhanceApp: App => App, // useful for wrapping in a per-page basis - enhanceComponent: Component => Component + enhanceComponent: Component => Component, }) // Run the parent `getInitialProps` using `ctx` that now includes our custom `renderPage` @@ -1450,7 +1435,7 @@ You can specify a name to use for a custom build directory. For example, the fol ```js // next.config.js module.exports = { - distDir: 'build' + distDir: 'build', } ``` @@ -1461,7 +1446,7 @@ You can disable etag generation for HTML pages depending on your cache strategy. ```js // next.config.js module.exports = { - generateEtags: false + generateEtags: false, } ``` @@ -1475,8 +1460,8 @@ module.exports = { // period (in ms) where the server will keep pages in the buffer maxInactiveAge: 25 * 1000, // number of pages that should be kept simultaneously without being disposed - pagesBufferLength: 2 - } + pagesBufferLength: 2, + }, } ``` @@ -1489,7 +1474,7 @@ Aimed at modules like [`@next/mdx`](https://github.com/zeit/next.js/tree/canary/ ```js // next.config.js module.exports = { - pageExtensions: ['mdx', 'jsx', 'js'] + pageExtensions: ['mdx', 'jsx', 'js'], } ``` @@ -1503,7 +1488,7 @@ module.exports = { generateBuildId: async () => { // For example get the latest git commit hash here return 'my-build-id' - } + }, } ``` @@ -1518,7 +1503,7 @@ module.exports = { } return null - } + }, } ``` @@ -1541,7 +1526,6 @@ NODE_OPTIONS="--inspect" next </ul> </details> - Some commonly asked for features are available as modules: - [@zeit/next-css](https://github.com/zeit/next-plugins/tree/master/packages/next-css) @@ -1563,7 +1547,7 @@ module.exports = withMDX( webpack(config, options) { // Further custom configuration here return config - } + }, }) ) ``` @@ -1580,16 +1564,14 @@ module.exports = { // Important: return the modified config // Example using webpack option - config.plugins.push( - new webpack.IgnorePlugin(/\/__tests__\//), - ) + config.plugins.push(new webpack.IgnorePlugin(/\/__tests__\//)) return config }, webpackDevMiddleware: config => { // Perform customizations to webpack dev middleware config // Important: return the modified config return config - } + }, } ``` @@ -1616,13 +1598,13 @@ module.exports = { options.defaultLoaders.babel, { loader: '@mdx-js/loader', - options: pluginOptions.options - } - ] + options: pluginOptions.options, + }, + ], }) return config - } + }, } ``` @@ -1635,7 +1617,6 @@ module.exports = { </ul> </details> - In order to extend our usage of `babel`, you can simply define a `.babelrc` file at the root of your app. This file is optional. If found, we're going to consider it the _source of truth_, therefore it needs to define what next needs as well, which is the `next/babel` preset. @@ -1700,8 +1681,8 @@ You can add the `env` key in `next.config.js`: // next.config.js module.exports = { env: { - customKey: 'value' - } + customKey: 'value', + }, } ``` @@ -1715,24 +1696,24 @@ function Index() { export default Index ``` + > **Warning:** Note that it is not possible to destructure process.env variables due to the webpack `DefinePlugin` replacing process.env.XXXX inline at build time ```js // Will not work -const { CUSTOM_KEY, CUSTOM_SECRET } = process.env; -AuthMethod({ key: CUSTOM_KEY, secret: CUSTOM_SECRET }); +const { CUSTOM_KEY, CUSTOM_SECRET } = process.env +AuthMethod({ key: CUSTOM_KEY, secret: CUSTOM_SECRET }) // Will work as replaced inline -AuthMethod({ key: process.env.CUSTOM_KEY, secret: process.env.CUSTOM_SECRET }); +AuthMethod({ key: process.env.CUSTOM_KEY, secret: process.env.CUSTOM_SECRET }) ``` - #### Runtime configuration > **Warning:** Note that this option is not available when using `target: 'serverless'` > **Warning:** Generally you want to use build-time configuration to provide your configuration. -The reason for this is that runtime configuration adds a small rendering / initialization overhead. +> The reason for this is that runtime configuration adds a small rendering / initialization overhead. The `next/config` module gives your app access to the `publicRuntimeConfig` and `serverRuntimeConfig` stored in your `next.config.js`. @@ -1746,12 +1727,12 @@ module.exports = { serverRuntimeConfig: { // Will only be available on the server side mySecret: 'secret', - secondSecret: process.env.SECOND_SECRET // Pass through env variables + secondSecret: process.env.SECOND_SECRET, // Pass through env variables }, publicRuntimeConfig: { // Will be available on both server and client - staticFolder: '/static' - } + staticFolder: '/static', + }, } ``` @@ -1787,7 +1768,7 @@ To set up a CDN, you can set up the `assetPrefix` setting and configure your CDN const isProd = process.env.NODE_ENV === 'production' module.exports = { // You may only need to add assetPrefix in the production. - assetPrefix: isProd ? 'https://cdn.mydomain.com' : '' + assetPrefix: isProd ? 'https://cdn.mydomain.com' : '', } ``` @@ -1798,7 +1779,7 @@ If your CDN is on a separate domain and you would like assets to be requested us ```js // next.config.js module.exports = { - crossOrigin: 'anonymous' + crossOrigin: 'anonymous', } ``` @@ -1839,7 +1820,7 @@ To enable **serverless mode** in Next.js, add the `serverless` build `target` in ```js // next.config.js module.exports = { - target: 'serverless' + target: 'serverless', } ``` @@ -1956,45 +1937,43 @@ export default Page To enable AMP support for a page, first enable experimental AMP support in your `next.config.js` and then import `withAmp` from `next/amp` and wrap your page's component in it. ### AMP First Page + ```js // pages/about.js import { withAmp } from 'next/amp' export default withAmp(function AboutPage(props) { - return ( - <h3>My AMP About Page!</h3> - ) + return <h3>My AMP About Page!</h3> }) ``` ### Hybrid AMP Page + ```js // pages/hybrid-about.js import { withAmp, useAmp } from 'next/amp' -export default withAmp(function AboutPage(props) { - return ( - <div> - <h3>My AMP Page</h3> - {useAmp() ? ( - <amp-img - width='300' - height='300' - src='/my-img.jpg' - alt='a cool image' - layout='responsive' - /> - ) : ( - <img - width='300' - height='300' - src='/my-img.jpg' - alt='a cool image' - /> - )} - </div> - ) -}, { hybrid: true }) +export default withAmp( + function AboutPage(props) { + return ( + <div> + <h3>My AMP Page</h3> + {useAmp() ? ( + <amp-img + width="300" + height="300" + src="/my-img.jpg" + alt="a cool image" + layout="responsive" + /> + ) : ( + <img width="300" height="300" src="/my-img.jpg" alt="a cool image" /> + )} + </div> + ) + }, + { hybrid: true } +) ``` ### AMP Page Modes @@ -2002,15 +1981,15 @@ export default withAmp(function AboutPage(props) { AMP pages can specify two modes: - AMP-only (default) - - Pages have no Next.js or React client-side runtime - - Pages are automatically optimized with [AMP Optimizer](https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer), an optimizer that applies the same transformations as AMP caches (improves performance by up to 42%) - - Pages have a user-accessible (optimized) version of the page and a search-engine indexable (unoptimized) version of the page - - Opt-in via `withAmp(Component)` + - Pages have no Next.js or React client-side runtime + - Pages are automatically optimized with [AMP Optimizer](https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer), an optimizer that applies the same transformations as AMP caches (improves performance by up to 42%) + - Pages have a user-accessible (optimized) version of the page and a search-engine indexable (unoptimized) version of the page + - Opt-in via `withAmp(Component)` - Hybrid - - Pages are able to be rendered as traditional HTML (default) and AMP HTML (by adding `?amp=1` to the URL) - - The AMP version of the page only has valid optimizations applied with AMP Optimizer so that it is indexable by search-engines - - Opt-in via `withAmp(Component, { hybrid: true })` - - Able to differentiate between modes using `useAmp` from `next/amp` + - Pages are able to be rendered as traditional HTML (default) and AMP HTML (by adding `?amp=1` to the URL) + - The AMP version of the page only has valid optimizations applied with AMP Optimizer so that it is indexable by search-engines + - Opt-in via `withAmp(Component, { hybrid: true })` + - Able to differentiate between modes using `useAmp` from `next/amp` Both of these page modes provide a consistently fast experience for users accessing pages through search engines. @@ -2081,7 +2060,6 @@ Any AMP errors will cause `next export` to exit with status code `1` because the </ul> </details> - `next export` is a way to run your Next.js app as a standalone static app without the need for a Node.js server. The exported app supports almost every feature of Next.js, including dynamic urls, prefetching, preloading and dynamic imports. @@ -2116,9 +2094,9 @@ module.exports = { '/readme.md': { page: '/readme' }, '/p/hello-nextjs': { page: '/post', query: { title: 'hello-nextjs' } }, '/p/learn-nextjs': { page: '/post', query: { title: 'learn-nextjs' } }, - '/p/deploy-nextjs': { page: '/post', query: { title: 'deploy-nextjs' } } + '/p/deploy-nextjs': { page: '/post', query: { title: 'deploy-nextjs' } }, } - } + }, } ``` @@ -2189,7 +2167,7 @@ module.exports = { // This will copy robots.txt from your project root into the out directory await copyFile(join(dir, 'robots.txt'), join(outDir, 'robots.txt')) return defaultPathMap - } + }, } ``` @@ -2210,7 +2188,6 @@ The `req` and `res` fields of the `context` object passed to `getInitialProps` a </ul> </details> - A zone is a single deployment of a Next.js app. Just like that, you can have multiple zones. Then you can merge them as a single app. For an example, you can have two zones like this: @@ -2267,7 +2244,6 @@ We’re ecstatic about both the developer experience and end-user performance, s </details> - <details> <summary>How big is it?</summary> @@ -2276,7 +2252,6 @@ A small Next main bundle is around 65kb gzipped. </details> - <details> <summary>Is this like `create-react-app`?</summary> @@ -2298,7 +2273,6 @@ If you want to create re-usable React components that you can embed in your Next </details> - <details> <summary>How do I use CSS-in-JS solutions?</summary> @@ -2306,7 +2280,6 @@ Next.js bundles [styled-jsx](https://github.com/zeit/styled-jsx) supporting scop </details> - <details> <summary>What syntactic features are transpiled? How do I change them?</summary> @@ -2316,7 +2289,6 @@ See the documentation about [customizing the babel config](#customizing-babel-co </details> - <details> <summary>Why a new Router?</summary> @@ -2333,7 +2305,6 @@ As a result, we were able to introduce a very simple approach to routing that co </details> - <details> <summary>How do I define a custom fancy route?</summary> @@ -2343,7 +2314,6 @@ On the client side, we have a parameter call `as` on `<Link>` that _decorates_ t </details> - <details> <summary>How do I fetch data?</summary> @@ -2351,7 +2321,6 @@ It’s up to you. `getInitialProps` is an `async` function (or a regular functio </details> - <details> <summary>Can I use it with GraphQL?</summary> @@ -2359,7 +2328,6 @@ Yes! Here's an example with [Apollo](/examples/with-apollo). </details> - <details> <summary>Can I use it with Redux and thunk?</summary> @@ -2367,7 +2335,6 @@ Yes! Here's an [example](/examples/with-redux-thunk) </details> - <details> <summary>Can I use it with Redux?</summary> @@ -2375,7 +2342,6 @@ Yes! Here's an [example](/examples/with-redux) </details> - <details> <summary>Can I use Next with my favorite Javascript library or toolkit?</summary> @@ -2383,7 +2349,6 @@ Since our first release we've had **many** example contributions, you can check </details> - <details> <summary>What is this inspired by?</summary> @@ -2397,7 +2362,6 @@ As we were researching options for server-rendering React that didn’t involve </details> - ## Contributing Please see our [contributing.md](/contributing.md) diff --git a/packages/next/amp.d.ts b/packages/next/amp.d.ts index 1f1fc80dc7d7e..f552bb199fbc2 100644 --- a/packages/next/amp.d.ts +++ b/packages/next/amp.d.ts @@ -1,2 +1,2 @@ export * from 'next-server/amp' -export {default} from 'next-server/amp' +export { default } from 'next-server/amp' diff --git a/packages/next/app.d.ts b/packages/next/app.d.ts index 27f2dc312f6e0..644150b3ba529 100644 --- a/packages/next/app.d.ts +++ b/packages/next/app.d.ts @@ -1,2 +1,2 @@ export * from './dist/pages/_app' -export {default} from './dist/pages/_app' +export { default } from './dist/pages/_app' diff --git a/packages/next/babel.d.ts b/packages/next/babel.d.ts index cc01b15681bb4..c13c965147b8b 100644 --- a/packages/next/babel.d.ts +++ b/packages/next/babel.d.ts @@ -1,2 +1,2 @@ export * from './dist/build/babel/preset' -export {default} from './dist/build/babel/preset' +export { default } from './dist/build/babel/preset' diff --git a/packages/next/bin/next.ts b/packages/next/bin/next.ts index f5fa1896ff453..db0bc1f91335f 100755 --- a/packages/next/bin/next.ts +++ b/packages/next/bin/next.ts @@ -1,37 +1,42 @@ #!/usr/bin/env node import arg from 'next/dist/compiled/arg/index.js' - -['react', 'react-dom'].forEach((dependency) => { +;['react', 'react-dom'].forEach(dependency => { try { // When 'npm link' is used it checks the clone location. Not the project. require.resolve(dependency) } 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}'` + ) } }) const defaultCommand = 'dev' export type cliCommand = (argv?: string[]) => void -const commands: {[command: string]: () => Promise<cliCommand>} = { - build: async () => await import('../cli/next-build').then((i) => i.nextBuild), - start: async () => await import('../cli/next-start').then((i) => i.nextStart), - export: async () => await import('../cli/next-export').then((i) => i.nextExport), - dev: async () => await import('../cli/next-dev').then((i) => i.nextDev), +const commands: { [command: string]: () => Promise<cliCommand> } = { + build: async () => await import('../cli/next-build').then(i => i.nextBuild), + start: async () => await import('../cli/next-start').then(i => i.nextStart), + export: async () => + await import('../cli/next-export').then(i => i.nextExport), + dev: async () => await import('../cli/next-dev').then(i => i.nextDev), } -const args = arg({ - // Types - '--version': Boolean, - '--help': Boolean, - '--inspect': Boolean, - - // Aliases - '-v': '--version', - '-h': '--help', -}, { - permissive: true, -}) +const args = arg( + { + // Types + '--version': Boolean, + '--help': Boolean, + '--inspect': Boolean, + + // Aliases + '-v': '--version', + '-h': '--help', + }, + { + permissive: true, + } +) // Version is inlined into the file using taskr build pipeline if (args['--version']) { @@ -68,7 +73,10 @@ if (!foundCommand && args['--help']) { const command = foundCommand ? args._[0] : defaultCommand const forwardedArgs = foundCommand ? args._.slice(1) : args._ -if (args['--inspect']) throw new Error(`Use env variable NODE_OPTIONS instead: NODE_OPTIONS="--inspect" next ${command}`) +if (args['--inspect']) + throw new Error( + `Use env variable NODE_OPTIONS instead: NODE_OPTIONS="--inspect" next ${command}` + ) // Make sure the `next <subcommand> --help` case is covered if (args['--help']) { @@ -83,18 +91,22 @@ process.env.NODE_ENV = process.env.NODE_ENV || defaultEnv const React = require('react') if (typeof React.Suspense === 'undefined') { - throw new Error(`The version of React you are using is lower than the minimum required version needed for Next.js. Please upgrade "react" and "react-dom": "npm install --save react react-dom" https://err.sh/zeit/next.js/invalid-react-version`) + throw new Error( + `The version of React you are using is lower than the minimum required version needed for Next.js. Please upgrade "react" and "react-dom": "npm install --save react react-dom" https://err.sh/zeit/next.js/invalid-react-version` + ) } -commands[command]().then((exec) => exec(forwardedArgs)) +commands[command]().then(exec => exec(forwardedArgs)) if (command === 'dev') { - const {CONFIG_FILE} = require('next-server/constants') - const {watchFile} = require('fs') + const { CONFIG_FILE } = require('next-server/constants') + const { watchFile } = require('fs') watchFile(`${process.cwd()}/${CONFIG_FILE}`, (cur: any, prev: any) => { if (cur.size > 0 || prev.size > 0) { // tslint:disable-next-line - console.log(`\n> Found a change in ${CONFIG_FILE}. Restart the server to see the changes in effect.`) + console.log( + `\n> Found a change in ${CONFIG_FILE}. Restart the server to see the changes in effect.` + ) } }) } diff --git a/packages/next/build/babel/plugins/commonjs.ts b/packages/next/build/babel/plugins/commonjs.ts index b8ba8226e4864..aee72c2ea9f19 100644 --- a/packages/next/build/babel/plugins/commonjs.ts +++ b/packages/next/build/babel/plugins/commonjs.ts @@ -1,23 +1,21 @@ -import {PluginObj} from '@babel/core' -import {NodePath} from '@babel/traverse' -import {Program} from '@babel/types' +import { PluginObj } from '@babel/core' +import { NodePath } from '@babel/traverse' +import { Program } from '@babel/types' import commonjsPlugin from '@babel/plugin-transform-modules-commonjs' // Rewrite imports using next/<something> to next-server/<something> -export default function NextToNextServer (...args: any): PluginObj { +export default function NextToNextServer(...args: any): PluginObj { const commonjs = commonjsPlugin(...args) return { visitor: { Program: { - exit (path: NodePath<Program>, state) { + exit(path: NodePath<Program>, state) { let foundModuleExports = false path.traverse({ - MemberExpression ( - path: any - ) { + MemberExpression(path: any) { if (path.node.object.name !== 'module') return if (path.node.property.name !== 'exports') return foundModuleExports = true - } + }, }) if (!foundModuleExports) { @@ -25,8 +23,8 @@ export default function NextToNextServer (...args: any): PluginObj { } commonjs.visitor.Program.exit.call(this, path, state) - } - } - } + }, + }, + }, } } diff --git a/packages/next/build/babel/plugins/react-loadable-plugin.ts b/packages/next/build/babel/plugins/react-loadable-plugin.ts index b9312adcdc872..dbad510056613 100644 --- a/packages/next/build/babel/plugins/react-loadable-plugin.ts +++ b/packages/next/build/babel/plugins/react-loadable-plugin.ts @@ -23,14 +23,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWAR // Modified to put `webpack` and `modules` under `loadableGenerated` to be backwards compatible with next/dynamic which has a `modules` key // Modified to support `dynamic(import('something'))` and `dynamic(import('something'), options) -import {PluginObj} from '@babel/core' -import {NodePath} from '@babel/traverse' +import { PluginObj } from '@babel/core' +import { NodePath } from '@babel/traverse' import * as BabelTypes from '@babel/types' -export default function ({ types: t }: {types: typeof BabelTypes}): PluginObj { +export default function({ types: t }: { types: typeof BabelTypes }): PluginObj { return { visitor: { - ImportDeclaration (path: NodePath<BabelTypes.ImportDeclaration>) { + ImportDeclaration(path: NodePath<BabelTypes.ImportDeclaration>) { let source = path.node.source.value if (source !== 'next/dynamic') return @@ -55,7 +55,10 @@ export default function ({ types: t }: {types: typeof BabelTypes}): PluginObj { callExpression.node.computed === false ) { const property = callExpression.get('property') - if (!Array.isArray(property) && property.isIdentifier({ name: 'Map' })) { + if ( + !Array.isArray(property) && + property.isIdentifier({ name: 'Map' }) + ) { callExpression = callExpression.parentPath } } @@ -64,7 +67,9 @@ export default function ({ types: t }: {types: typeof BabelTypes}): PluginObj { let args = callExpression.get('arguments') if (args.length > 2) { - throw callExpression.buildCodeFrameError('next/dynamic only accepts 2 arguments') + throw callExpression.buildCodeFrameError( + 'next/dynamic only accepts 2 arguments' + ) } if (!args[0]) { @@ -91,7 +96,13 @@ export default function ({ types: t }: {types: typeof BabelTypes}): PluginObj { if (!options.isObjectExpression()) return let properties = options.get('properties') - let propertiesMap: {[key: string]: NodePath<BabelTypes.ObjectProperty | BabelTypes.ObjectMethod | BabelTypes.SpreadProperty>} = {} + let propertiesMap: { + [key: string]: NodePath< + | BabelTypes.ObjectProperty + | BabelTypes.ObjectMethod + | BabelTypes.SpreadProperty + > + } = {} properties.forEach(property => { const key: any = property.get('key') @@ -116,44 +127,44 @@ export default function ({ types: t }: {types: typeof BabelTypes}): PluginObj { const dynamicImports: BabelTypes.StringLiteral[] = [] loader.traverse({ - Import (path) { + Import(path) { const args = path.parentPath.get('arguments') if (!Array.isArray(args)) return const node: any = args[0].node dynamicImports.push(node) - } + }, }) if (!dynamicImports.length) return - options.node.properties.push(t.objectProperty( - t.identifier('loadableGenerated'), - t.objectExpression([ - t.objectProperty( - t.identifier('webpack'), - t.arrowFunctionExpression( - [], - t.arrayExpression( - dynamicImports.map(dynamicImport => { - return t.callExpression( - t.memberExpression( - t.identifier('require'), - t.identifier('resolveWeak') - ), - [dynamicImport] - ) - }) + options.node.properties.push( + t.objectProperty( + t.identifier('loadableGenerated'), + t.objectExpression([ + t.objectProperty( + t.identifier('webpack'), + t.arrowFunctionExpression( + [], + t.arrayExpression( + dynamicImports.map(dynamicImport => { + return t.callExpression( + t.memberExpression( + t.identifier('require'), + t.identifier('resolveWeak') + ), + [dynamicImport] + ) + }) + ) ) - ) - ), - t.objectProperty( - t.identifier('modules'), - t.arrayExpression( - dynamicImports - ) - ) - ]) - )) + ), + t.objectProperty( + t.identifier('modules'), + t.arrayExpression(dynamicImports) + ), + ]) + ) + ) // Turns `dynamic(import('something'))` into `dynamic(() => import('something'))` for backwards compat. // This is the replicate the behavior in versions below Next.js 7 where we magically handled not executing the `import()` too. @@ -163,7 +174,7 @@ export default function ({ types: t }: {types: typeof BabelTypes}): PluginObj { loader.replaceWith(arrowFunction) } }) - } - } + }, + }, } } diff --git a/packages/next/build/babel/preset.ts b/packages/next/build/babel/preset.ts index 133e5917e0b3e..c2ebf25e5e5da 100644 --- a/packages/next/build/babel/preset.ts +++ b/packages/next/build/babel/preset.ts @@ -1,16 +1,18 @@ -import {PluginItem} from '@babel/core' +import { PluginItem } from '@babel/core' const env = process.env.NODE_ENV const isProduction = env === 'production' const isDevelopment = env === 'development' const isTest = env === 'test' type StyledJsxPlugin = [string, any] | string -type StyledJsxBabelOptions = { - plugins?: StyledJsxPlugin[] -} | undefined +type StyledJsxBabelOptions = + | { + plugins?: StyledJsxPlugin[] + } + | undefined // Resolve styled-jsx plugins -function styledJsxOptions (options: StyledJsxBabelOptions) { +function styledJsxOptions(options: StyledJsxBabelOptions) { if (!options) { return {} } @@ -19,80 +21,97 @@ function styledJsxOptions (options: StyledJsxBabelOptions) { return options } - options.plugins = options.plugins.map((plugin: StyledJsxPlugin): StyledJsxPlugin => { - if (Array.isArray(plugin)) { - const [name, options] = plugin - return [ - require.resolve(name), - options - ] - } + options.plugins = options.plugins.map( + (plugin: StyledJsxPlugin): StyledJsxPlugin => { + if (Array.isArray(plugin)) { + const [name, options] = plugin + return [require.resolve(name), options] + } - return require.resolve(plugin) - }) + return require.resolve(plugin) + } + ) return options } type NextBabelPresetOptions = { - 'preset-env'?: any, - 'preset-react'?: any, - 'class-properties'?: any, - 'transform-runtime'?: any, + 'preset-env'?: any + 'preset-react'?: any + 'class-properties'?: any + 'transform-runtime'?: any 'styled-jsx'?: StyledJsxBabelOptions } type BabelPreset = { - presets?: PluginItem[] | null, - plugins?: PluginItem[] | null, + presets?: PluginItem[] | null + plugins?: PluginItem[] | null overrides?: any[] } // Taken from https://github.com/babel/babel/commit/d60c5e1736543a6eac4b549553e107a9ba967051#diff-b4beead8ad9195361b4537601cc22532R158 function supportsStaticESM(caller: any) { - return !!(caller && caller.supportsStaticESM); + return !!(caller && caller.supportsStaticESM) } -module.exports = (api: any, options: NextBabelPresetOptions = {}): BabelPreset => { +module.exports = ( + api: any, + options: NextBabelPresetOptions = {} +): BabelPreset => { const supportsESM = api.caller(supportsStaticESM) const presetEnvConfig = { // In the test environment `modules` is often needed to be set to true, babel figures that out by itself using the `'auto'` option // In production/development this option is set to `false` so that webpack can handle import/export with tree-shaking modules: 'auto', exclude: ['transform-typeof-symbol'], - ...options['preset-env'] + ...options['preset-env'], } return { presets: [ [require('@babel/preset-env').default, presetEnvConfig], - [require('@babel/preset-react'), { - // This adds @babel/plugin-transform-react-jsx-source and - // @babel/plugin-transform-react-jsx-self automatically in development - development: isDevelopment || isTest, - ...options['preset-react'] - }], - require('@babel/preset-typescript') + [ + require('@babel/preset-react'), + { + // This adds @babel/plugin-transform-react-jsx-source and + // @babel/plugin-transform-react-jsx-self automatically in development + development: isDevelopment || isTest, + ...options['preset-react'], + }, + ], + require('@babel/preset-typescript'), ], plugins: [ require('babel-plugin-react-require'), require('@babel/plugin-syntax-dynamic-import'), require('./plugins/react-loadable-plugin'), - [require('@babel/plugin-proposal-class-properties'), options['class-properties'] || {}], - [require('@babel/plugin-proposal-object-rest-spread'), { - useBuiltIns: true - }], - [require('@babel/plugin-transform-runtime'), { - corejs: 2, - helpers: true, - regenerator: true, - useESModules: supportsESM && presetEnvConfig.modules !== 'commonjs', - ...options['transform-runtime'] - }], + [ + require('@babel/plugin-proposal-class-properties'), + options['class-properties'] || {}, + ], + [ + require('@babel/plugin-proposal-object-rest-spread'), + { + useBuiltIns: true, + }, + ], + [ + require('@babel/plugin-transform-runtime'), + { + corejs: 2, + helpers: true, + regenerator: true, + useESModules: supportsESM && presetEnvConfig.modules !== 'commonjs', + ...options['transform-runtime'], + }, + ], [require('styled-jsx/babel'), styledJsxOptions(options['styled-jsx'])], require('./plugins/amp-attributes'), - isProduction && [require('babel-plugin-transform-react-remove-prop-types'), { - removeImport: true - }] - ].filter(Boolean) + isProduction && [ + require('babel-plugin-transform-react-remove-prop-types'), + { + removeImport: true, + }, + ], + ].filter(Boolean), } } diff --git a/packages/next/build/compiler.ts b/packages/next/build/compiler.ts index 7de87d5d71993..6070bc57f5a84 100644 --- a/packages/next/build/compiler.ts +++ b/packages/next/build/compiler.ts @@ -1,4 +1,4 @@ -import webpack, {Stats} from 'webpack' +import webpack, { Stats } from 'webpack' export type CompilerResult = { errors: Error[] @@ -33,7 +33,7 @@ export function runCompiler( return reject(err) } - if(statsOrMultiStats.stats) { + if (statsOrMultiStats.stats) { const result: CompilerResult = statsOrMultiStats.stats.reduce( generateStats, { errors: [], warnings: [] } @@ -41,7 +41,10 @@ export function runCompiler( return resolve(result) } - const result = generateStats({ errors: [], warnings: [] }, statsOrMultiStats) + const result = generateStats( + { errors: [], warnings: [] }, + statsOrMultiStats + ) return resolve(result) }) }) diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index 116f1f256adfa..5bc03a014518f 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -1,20 +1,31 @@ -import {join} from 'path' -import {stringify} from 'querystring' -import {PAGES_DIR_ALIAS, DOT_NEXT_ALIAS} from '../lib/constants' -import {ServerlessLoaderQuery} from './webpack/loaders/next-serverless-loader' +import { join } from 'path' +import { stringify } from 'querystring' +import { PAGES_DIR_ALIAS, DOT_NEXT_ALIAS } from '../lib/constants' +import { ServerlessLoaderQuery } from './webpack/loaders/next-serverless-loader' type PagesMapping = { [page: string]: string } -export function createPagesMapping(pagePaths: string[], extensions: string[]): PagesMapping { - const pages: PagesMapping = pagePaths.reduce((result: PagesMapping, pagePath): PagesMapping => { - let page = `${pagePath.replace(new RegExp(`\\.+(${extensions.join('|')})$`), '').replace(/\\/g, '/')}`.replace(/\/index$/, '') - page = page === '/index' ? '/' : page +export function createPagesMapping( + pagePaths: string[], + extensions: string[] +): PagesMapping { + const pages: PagesMapping = pagePaths.reduce( + (result: PagesMapping, pagePath): PagesMapping => { + let page = `${pagePath + .replace(new RegExp(`\\.+(${extensions.join('|')})$`), '') + .replace(/\\/g, '/')}`.replace(/\/index$/, '') + page = page === '/index' ? '/' : page - result[page === '' ? '/' : page] = join(PAGES_DIR_ALIAS, pagePath).replace(/\\/g, '/') - return result - }, {}) + result[page === '' ? '/' : page] = join( + PAGES_DIR_ALIAS, + pagePath + ).replace(/\\/g, '/') + return result + }, + {} + ) pages['/_app'] = pages['/_app'] || 'next/dist/pages/_app' pages['/_error'] = pages['/_error'] || 'next/dist/pages/_error' @@ -24,7 +35,7 @@ export function createPagesMapping(pagePaths: string[], extensions: string[]): P } export type WebpackEntrypoints = { - [bundle: string]: string|string[] + [bundle: string]: string | string[] } type Entrypoints = { @@ -32,7 +43,13 @@ type Entrypoints = { server: WebpackEntrypoints } -export function createEntrypoints(pages: PagesMapping, target: 'server'|'serverless', buildId: string, dynamicBuildId: boolean, config: any): Entrypoints { +export function createEntrypoints( + pages: PagesMapping, + target: 'server' | 'serverless', + buildId: string, + dynamicBuildId: boolean, + config: any +): Entrypoints { const client: WebpackEntrypoints = {} const server: WebpackEntrypoints = {} @@ -48,30 +65,43 @@ export function createEntrypoints(pages: PagesMapping, target: 'server'|'serverl dynamicBuildId, } - Object.keys(pages).forEach((page) => { + Object.keys(pages).forEach(page => { const absolutePagePath = pages[page] const bundleFile = page === '/' ? '/index.js' : `${page}.js` const isApiRoute = bundleFile.startsWith('/api') const bundlePath = join('static', buildId, 'pages', bundleFile) - if(isApiRoute || target === 'server') { + if (isApiRoute || target === 'server') { server[bundlePath] = [absolutePagePath] - } else if(target === 'serverless' && page !== '/_app' && page !== '/_document') { - const serverlessLoaderOptions: ServerlessLoaderQuery = {page, absolutePagePath, ...defaultServerlessOptions} - server[join('pages', bundleFile)] = `next-serverless-loader?${stringify(serverlessLoaderOptions)}!` + } else if ( + target === 'serverless' && + page !== '/_app' && + page !== '/_document' + ) { + const serverlessLoaderOptions: ServerlessLoaderQuery = { + page, + absolutePagePath, + ...defaultServerlessOptions, + } + server[join('pages', bundleFile)] = `next-serverless-loader?${stringify( + serverlessLoaderOptions + )}!` } if (page === '/_document') { return } - if(!isApiRoute) { - client[bundlePath] = `next-client-pages-loader?${stringify({page, absolutePagePath})}!` + if (!isApiRoute) { + client[bundlePath] = `next-client-pages-loader?${stringify({ + page, + absolutePagePath, + })}!` } }) return { client, - server + server, } } diff --git a/packages/next/build/generate-build-id.ts b/packages/next/build/generate-build-id.ts index 53e9f7f4128e3..54996c93bdea8 100644 --- a/packages/next/build/generate-build-id.ts +++ b/packages/next/build/generate-build-id.ts @@ -1,8 +1,11 @@ -export async function generateBuildId (generate: () => string|null, fallback: () => string): Promise<string> { +export async function generateBuildId( + generate: () => string | null, + fallback: () => string +): Promise<string> { let buildId = await generate() // If there's no buildId defined we'll fall back if (buildId === null) { - // We also create a new buildId if it contains the word `ad` to avoid false + // We also create a new buildId if it contains the word `ad` to avoid false // positives with ad blockers while (!buildId || /ad/i.test(buildId)) { buildId = fallback() @@ -10,7 +13,9 @@ export async function generateBuildId (generate: () => string|null, fallback: () } if (typeof buildId !== 'string') { - throw new Error('generateBuildId did not return a string. https://err.sh/zeit/next.js/generatebuildid-not-a-string') + throw new Error( + 'generateBuildId did not return a string. https://err.sh/zeit/next.js/generatebuildid-not-a-string' + ) } return buildId.trim() diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index a86c23d0f658a..a57edc27af8d9 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -36,7 +36,7 @@ import { getPageChunks, } from './webpack/plugins/chunk-graph-plugin' import { writeBuildId } from './write-build-id' -import { recursiveReadDir } from '../lib/recursive-readdir'; +import { recursiveReadDir } from '../lib/recursive-readdir' import mkdirpOrig from 'mkdirp' const fsUnlink = promisify(fs.unlink) @@ -134,12 +134,10 @@ export default async function build(dir: string, conf = null): Promise<void> { allPageInfos = await flyingShuttle.getPageInfos() const _unchangedPages = new Set(await flyingShuttle.getUnchangedPages()) for (const unchangedPage of _unchangedPages) { - const info = allPageInfos.get(unchangedPage) || {} as PageInfo + const info = allPageInfos.get(unchangedPage) || ({} as PageInfo) if (info.static) allStaticPages.add(unchangedPage) - const recalled = await flyingShuttle.restorePage( - unchangedPage, info - ) + const recalled = await flyingShuttle.restorePage(unchangedPage, info) if (recalled) { continue } @@ -150,7 +148,7 @@ export default async function build(dir: string, conf = null): Promise<void> { [..._unchangedPages].map(async page => { if ( page.endsWith('.amp') && - (allPageInfos.get(page.split('.amp')[0]) || {} as PageInfo).isAmp + (allPageInfos.get(page.split('.amp')[0]) || ({} as PageInfo)).isAmp ) { return '' } @@ -169,8 +167,8 @@ export default async function build(dir: string, conf = null): Promise<void> { `Did pageExtensions change? We can't recover from this yet.` ) ) - })) - ).filter(Boolean) + }) + )).filter(Boolean) const pageSet = new Set(pagePaths) for (const unchangedPage of unchangedPages) { @@ -274,8 +272,11 @@ export default async function build(dir: string, conf = null): Promise<void> { const distPath = path.join(dir, config.distDir) const pageKeys = Object.keys(mappedPages) - const manifestPath = path.join(distDir, target === 'serverless' - ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY, PAGES_MANIFEST) + const manifestPath = path.join( + distDir, + target === 'serverless' ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY, + PAGES_MANIFEST + ) const { autoExport } = config.experimental const staticPages = new Set<string>() @@ -295,9 +296,7 @@ export default async function build(dir: string, conf = null): Promise<void> { const actualPage = page === '/' ? '/index' : page const size = await getPageSizeInKb(actualPage, distPath, buildId) const bundleRelative = path.join( - target === 'serverless' - ? 'pages' - : `static/${buildId}/pages`, + target === 'serverless' ? 'pages' : `static/${buildId}/pages`, actualPage + '.js' ) const serverBundle = path.join( @@ -311,7 +310,7 @@ export default async function build(dir: string, conf = null): Promise<void> { const runtimeEnvConfig = { publicRuntimeConfig: config.publicRuntimeConfig, - serverRuntimeConfig: config.serverRuntimeConfig + serverRuntimeConfig: config.serverRuntimeConfig, } const nonReservedPage = !page.match(/^\/(_app|_error|_document|api)/) @@ -319,12 +318,18 @@ export default async function build(dir: string, conf = null): Promise<void> { customAppGetInitialProps = hasCustomAppGetInitialProps( target === 'serverless' ? serverBundle - : path.join(distPath, SERVER_DIRECTORY, `/static/${buildId}/pages/_app.js`), + : path.join( + distPath, + SERVER_DIRECTORY, + `/static/${buildId}/pages/_app.js` + ), runtimeEnvConfig ) if (customAppGetInitialProps) { - console.warn('Opting out of automatic exporting due to custom `getInitialProps` in `pages/_app`\n') + console.warn( + 'Opting out of automatic exporting due to custom `getInitialProps` in `pages/_app`\n' + ) } } @@ -368,7 +373,7 @@ export default async function build(dir: string, conf = null): Promise<void> { experimental: { ...config.experimental, exportTrailingSlash: false, - } + }, } await exportApp(dir, exportOptions, exportConfig) const toMove = await recursiveReadDir(exportOptions.outdir, /.*\.html$/) diff --git a/packages/next/build/is-writeable.ts b/packages/next/build/is-writeable.ts index 546f6dba20a6d..2943d8705c4b6 100644 --- a/packages/next/build/is-writeable.ts +++ b/packages/next/build/is-writeable.ts @@ -1,9 +1,9 @@ import fs from 'fs' -import {promisify} from 'util' +import { promisify } from 'util' const access = promisify(fs.access) -export async function isWriteable (directory: string): Promise<boolean> { +export async function isWriteable(directory: string): Promise<boolean> { try { await access(directory, (fs.constants || fs).W_OK) return true diff --git a/packages/next/build/output/store.ts b/packages/next/build/output/store.ts index 92a6f188330a3..f543cff715b53 100644 --- a/packages/next/build/output/store.ts +++ b/packages/next/build/output/store.ts @@ -11,7 +11,8 @@ export type OutputState = loading: false errors: string[] | null warnings: string[] | null - })) + } + )) export const store = createStore<OutputState>({ appUrl: null, bootstrap: true }) diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index 1c147b3d8da57..ff85f97d62d71 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -227,7 +227,7 @@ export async function getPageSizeInKb( export function isPageStatic( serverBundle: string, - runtimeEnvConfig: any, + runtimeEnvConfig: any ): boolean { try { nextEnvConfig.setConfig(runtimeEnvConfig) @@ -250,7 +250,7 @@ export function isPageStatic( export function hasCustomAppGetInitialProps( _appBundle: string, - runtimeEnvConfig: any, + runtimeEnvConfig: any ): boolean { nextEnvConfig.setConfig(runtimeEnvConfig) let mod = require(_appBundle) diff --git a/packages/next/build/webpack/loaders/emit-file-loader.js b/packages/next/build/webpack/loaders/emit-file-loader.js index ffbbb93ca51b5..93b3f68069dea 100644 --- a/packages/next/build/webpack/loaders/emit-file-loader.js +++ b/packages/next/build/webpack/loaders/emit-file-loader.js @@ -21,15 +21,22 @@ module.exports = function (content, sourceMap) { const context = query.context || this.rootContext || this.options.context const regExp = query.regExp const opts = { context, content, regExp } - const interpolateName = query.interpolateName || ((name) => name) - const interpolatedName = interpolateName(loaderUtils.interpolateName(this, name, opts), { name, opts }) + const interpolateName = query.interpolateName || (name => name) + const interpolatedName = interpolateName( + loaderUtils.interpolateName(this, name, opts), + { name, opts } + ) const emit = (code, map) => { this.emitFile(interpolatedName, code, map) callback(null, code, map) } if (query.transform) { - const transformed = query.transform({ content, sourceMap, interpolatedName }) + const transformed = query.transform({ + content, + sourceMap, + interpolatedName + }) return emit(transformed.content, transformed.sourceMap) } diff --git a/packages/next/build/webpack/loaders/next-babel-loader.js b/packages/next/build/webpack/loaders/next-babel-loader.js index f87bc5497917d..664254d6f5ff1 100644 --- a/packages/next/build/webpack/loaders/next-babel-loader.js +++ b/packages/next/build/webpack/loaders/next-babel-loader.js @@ -6,9 +6,17 @@ import babelLoader from 'babel-loader' const cacheKey = 'babel-cache-' + 'c' + '-' module.exports = babelLoader.custom(babel => { - const presetItem = babel.createConfigItem(require('../../babel/preset'), { type: 'preset' }) - const applyCommonJs = babel.createConfigItem(require('../../babel/plugins/commonjs'), { type: 'plugin' }) - const commonJsItem = babel.createConfigItem(require('@babel/plugin-transform-modules-commonjs'), { type: 'plugin' }) + const presetItem = babel.createConfigItem(require('../../babel/preset'), { + type: 'preset' + }) + const applyCommonJs = babel.createConfigItem( + require('../../babel/plugins/commonjs'), + { type: 'plugin' } + ) + const commonJsItem = babel.createConfigItem( + require('@babel/plugin-transform-modules-commonjs'), + { type: 'plugin' } + ) const configs = new Set() @@ -19,19 +27,26 @@ module.exports = babelLoader.custom(babel => { asyncToPromises: opts.asyncToPromises } const filename = join(opts.cwd, 'noop.js') - const loader = Object.assign(opts.cache ? { - cacheCompression: false, - cacheDirectory: join(opts.distDir, 'cache', 'next-babel-loader'), - cacheIdentifier: cacheKey + JSON.stringify( - babel.loadPartialConfig({ - filename, - cwd: opts.cwd, - sourceFileName: filename - }).options - ) - } : { - cacheDirectory: false - }, opts) + const loader = Object.assign( + opts.cache + ? { + cacheCompression: false, + cacheDirectory: join(opts.distDir, 'cache', 'next-babel-loader'), + cacheIdentifier: + cacheKey + + JSON.stringify( + babel.loadPartialConfig({ + filename, + cwd: opts.cwd, + sourceFileName: filename + }).options + ) + } + : { + cacheDirectory: false + }, + opts + ) delete loader.isServer delete loader.asyncToPromises @@ -39,7 +54,13 @@ module.exports = babelLoader.custom(babel => { delete loader.distDir return { loader, custom } }, - config (cfg, { source, customOptions: { isServer, asyncToPromises } }) { + config ( + cfg, + { + source, + customOptions: { isServer, asyncToPromises } + } + ) { const filename = this.resourcePath const options = Object.assign({}, cfg.options) if (cfg.hasFilesystemConfig()) { @@ -57,21 +78,36 @@ module.exports = babelLoader.custom(babel => { } if (!isServer && source.indexOf('next/amp')) { - const dropClientPlugin = babel.createConfigItem([require('../../babel/plugins/next-drop-client-page'), {}], { type: 'plugin' }) + const dropClientPlugin = babel.createConfigItem( + [require('../../babel/plugins/next-drop-client-page'), {}], + { type: 'plugin' } + ) options.plugins = options.plugins || [] options.plugins.push(dropClientPlugin) } if (isServer && source.indexOf('next/data') !== -1) { - const nextDataPlugin = babel.createConfigItem([require('../../babel/plugins/next-data'), { key: basename(filename) + '-' + hash(filename) }], { type: 'plugin' }) + const nextDataPlugin = babel.createConfigItem( + [ + require('../../babel/plugins/next-data'), + { key: basename(filename) + '-' + hash(filename) } + ], + { type: 'plugin' } + ) options.plugins = options.plugins || [] options.plugins.push(nextDataPlugin) } if (asyncToPromises) { - const asyncToPromisesPlugin = babel.createConfigItem(['babel-plugin-transform-async-to-promises', { - inlineHelpers: true - }], { type: 'plugin' }) + const asyncToPromisesPlugin = babel.createConfigItem( + [ + 'babel-plugin-transform-async-to-promises', + { + inlineHelpers: true + } + ], + { type: 'plugin' } + ) options.plugins = options.plugins || [] options.plugins.push(asyncToPromisesPlugin) @@ -86,11 +122,12 @@ module.exports = babelLoader.custom(babel => { return preset[0] === require('@babel/preset-env').default }) if (babelPresetEnv) { - babelPresetEnv[1].exclude = (options.presets[0][1].exclude || []).concat([ - 'transform-typeof-symbol', - 'transform-regenerator', - 'transform-async-to-generator' - ]) + babelPresetEnv[1].exclude = (options.presets[0][1].exclude || []) + .concat([ + 'transform-typeof-symbol', + 'transform-regenerator', + 'transform-async-to-generator' + ]) .filter('transform-typeof-symbol') } } @@ -111,9 +148,7 @@ module.exports = babelLoader.custom(babel => { /next[\\/]dist[\\/]client/, /next[\\/]dist[\\/]pages/ ], - plugins: [ - commonJsItem - ] + plugins: [commonJsItem] } ] diff --git a/packages/next/build/webpack/loaders/next-client-pages-loader.ts b/packages/next/build/webpack/loaders/next-client-pages-loader.ts index d084ec6abf394..5352b6924a0c3 100644 --- a/packages/next/build/webpack/loaders/next-client-pages-loader.ts +++ b/packages/next/build/webpack/loaders/next-client-pages-loader.ts @@ -1,13 +1,13 @@ -import {loader} from 'webpack' +import { loader } from 'webpack' import loaderUtils from 'loader-utils' export type ClientPagesLoaderOptions = { - absolutePagePath: string, + absolutePagePath: string page: string } -const nextClientPagesLoader: loader.Loader = function () { - const {absolutePagePath, page}: any = loaderUtils.getOptions(this) +const nextClientPagesLoader: loader.Loader = function() { + const { absolutePagePath, page }: any = loaderUtils.getOptions(this) const stringifiedAbsolutePagePath = JSON.stringify(absolutePagePath) const stringifiedPage = JSON.stringify(page) diff --git a/packages/next/build/webpack/loaders/next-data-loader.ts b/packages/next/build/webpack/loaders/next-data-loader.ts index a1ec9851800f8..03879892bae28 100644 --- a/packages/next/build/webpack/loaders/next-data-loader.ts +++ b/packages/next/build/webpack/loaders/next-data-loader.ts @@ -1,12 +1,14 @@ -import {loader} from 'webpack' +import { loader } from 'webpack' import hash from 'string-hash' -import {basename} from 'path' -const nextDataLoader: loader.Loader = function (source) { +import { basename } from 'path' +const nextDataLoader: loader.Loader = function(source) { const filename = this.resourcePath return ` import {createHook} from 'next/data' - export default createHook(undefined, {key: ${JSON.stringify(basename(filename) + '-' + hash(filename))}}) + export default createHook(undefined, {key: ${JSON.stringify( + basename(filename) + '-' + hash(filename) + )}}) ` } diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index 6840724d87e0c..91228f46a265d 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -1,23 +1,23 @@ -import {loader} from 'webpack' -import {join} from 'path' -import {parse} from 'querystring' +import { loader } from 'webpack' +import { join } from 'path' +import { parse } from 'querystring' import { BUILD_MANIFEST, REACT_LOADABLE_MANIFEST } from 'next-server/constants' export type ServerlessLoaderQuery = { - page: string, - distDir: string, - absolutePagePath: string, - absoluteAppPath: string, - absoluteDocumentPath: string, - absoluteErrorPath: string, - assetPrefix: string, - ampBindInitData: boolean | string, + page: string + distDir: string + absolutePagePath: string + absoluteAppPath: string + absoluteDocumentPath: string + absoluteErrorPath: string + assetPrefix: string + ampBindInitData: boolean | string generateEtags: string - dynamicBuildId?: string | boolean, + dynamicBuildId?: string | boolean canonicalBase: string } -const nextServerlessLoader: loader.Loader = function () { +const nextServerlessLoader: loader.Loader = function() { const { distDir, absolutePagePath, @@ -29,10 +29,14 @@ const nextServerlessLoader: loader.Loader = function () { absoluteDocumentPath, absoluteErrorPath, generateEtags, - dynamicBuildId - }: ServerlessLoaderQuery = typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query + dynamicBuildId, + }: ServerlessLoaderQuery = + typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query const buildManifest = join(distDir, BUILD_MANIFEST).replace(/\\/g, '/') - const reactLoadableManifest = join(distDir, REACT_LOADABLE_MANIFEST).replace(/\\/g, '/') + const reactLoadableManifest = join(distDir, REACT_LOADABLE_MANIFEST).replace( + /\\/g, + '/' + ) return ` import {parse} from 'url' import {renderToHTML} from 'next-server/dist/server/render'; @@ -60,7 +64,8 @@ const nextServerlessLoader: loader.Loader = function () { buildId: "__NEXT_REPLACE__BUILD_ID__", dynamicBuildId: ${dynamicBuildId === true || dynamicBuildId === 'true'}, assetPrefix: "${assetPrefix}", - ampBindInitData: ${ampBindInitData === true || ampBindInitData === 'true'} + ampBindInitData: ${ampBindInitData === true || + ampBindInitData === 'true'} } const parsedUrl = parse(req.url, true) const renderOpts = Object.assign( diff --git a/packages/next/build/webpack/loaders/noop-loader.ts b/packages/next/build/webpack/loaders/noop-loader.ts index c8dde089f1ad0..b44453b0c2614 100644 --- a/packages/next/build/webpack/loaders/noop-loader.ts +++ b/packages/next/build/webpack/loaders/noop-loader.ts @@ -1,4 +1,4 @@ import { loader } from 'webpack' -const NoopLoader: loader.Loader = (source) => source +const NoopLoader: loader.Loader = source => source export default NoopLoader diff --git a/packages/next/build/webpack/plugins/build-manifest-plugin.ts b/packages/next/build/webpack/plugins/build-manifest-plugin.ts index 752b93cf1bc24..87350a4b21f93 100644 --- a/packages/next/build/webpack/plugins/build-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/build-manifest-plugin.ts @@ -4,18 +4,21 @@ import { BUILD_MANIFEST, ROUTE_NAME_REGEX, IS_BUNDLED_PAGE_REGEX, - CLIENT_STATIC_FILES_RUNTIME_MAIN + CLIENT_STATIC_FILES_RUNTIME_MAIN, } from 'next-server/constants' // This plugin creates a build-manifest.json for all assets that are being output // It has a mapping of "entry" filename to real filename. Because the real filename can be hashed in production export default class BuildManifestPlugin { - apply (compiler: Compiler) { + apply(compiler: Compiler) { compiler.hooks.emit.tapAsync( 'NextJsBuildManifest', (compilation, callback) => { const { chunks } = compilation - const assetMap: { devFiles: string[], pages: { [page: string]: string[] } } = { devFiles: [], pages: {} } + const assetMap: { + devFiles: string[] + pages: { [page: string]: string[] } + } = { devFiles: [], pages: {} } const mainJsChunk = chunks.find( c => c.name === CLIENT_STATIC_FILES_RUNTIME_MAIN @@ -73,7 +76,7 @@ export default class BuildManifestPlugin { assetMap.pages[`/${pagePath.replace(/\\/g, '/')}`] = [ ...filesForEntry, - ...mainJsFiles + ...mainJsFiles, ] } diff --git a/packages/next/build/webpack/plugins/chunk-names-plugin.ts b/packages/next/build/webpack/plugins/chunk-names-plugin.ts index 23c6c04a69d54..8d12acd9d17f5 100644 --- a/packages/next/build/webpack/plugins/chunk-names-plugin.ts +++ b/packages/next/build/webpack/plugins/chunk-names-plugin.ts @@ -3,31 +3,34 @@ import { Compiler } from 'webpack' // This fixes https://github.com/webpack/webpack/issues/6598 // This plugin is based on https://github.com/researchgate/webpack/commit/2f28947fa0c63ccbb18f39c0098bd791a2c37090 export default class ChunkNamesPlugin { - apply (compiler: Compiler) { - compiler.hooks.compilation.tap('NextJsChunkNamesPlugin', (compilation: any) => { - compilation.chunkTemplate.hooks.renderManifest.intercept({ - register (tapInfo: any) { - if (tapInfo.name === 'JavascriptModulesPlugin') { - const originalMethod = tapInfo.fn - tapInfo.fn = (result: any, options: any) => { - let filenameTemplate - const chunk = options.chunk - const outputOptions = options.outputOptions - if (chunk.filenameTemplate) { - filenameTemplate = chunk.filenameTemplate - } else if (chunk.hasEntryModule()) { - filenameTemplate = outputOptions.filename - } else { - filenameTemplate = outputOptions.chunkFilename - } + apply(compiler: Compiler) { + compiler.hooks.compilation.tap( + 'NextJsChunkNamesPlugin', + (compilation: any) => { + compilation.chunkTemplate.hooks.renderManifest.intercept({ + register(tapInfo: any) { + if (tapInfo.name === 'JavascriptModulesPlugin') { + const originalMethod = tapInfo.fn + tapInfo.fn = (result: any, options: any) => { + let filenameTemplate + const chunk = options.chunk + const outputOptions = options.outputOptions + if (chunk.filenameTemplate) { + filenameTemplate = chunk.filenameTemplate + } else if (chunk.hasEntryModule()) { + filenameTemplate = outputOptions.filename + } else { + filenameTemplate = outputOptions.chunkFilename + } - options.chunk.filenameTemplate = filenameTemplate - return originalMethod(result, options) + options.chunk.filenameTemplate = filenameTemplate + return originalMethod(result, options) + } } - } - return tapInfo - } - }) - }) + return tapInfo + }, + }) + } + ) } } diff --git a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts index f9a2825565550..b3d5aca34bd4a 100644 --- a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts +++ b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts @@ -3,14 +3,18 @@ import { extname } from 'path' // Prevents outputting client pages when they are not needed export class DropClientPage implements Plugin { - ampPages = new Set(); + ampPages = new Set() apply(compiler: Compiler) { compiler.hooks.emit.tap('DropClientPage', compilation => { Object.keys(compilation.assets).forEach(assetKey => { const asset = compilation.assets[assetKey] - if (asset && asset._value && asset._value.includes('__NEXT_DROP_CLIENT_FILE__')) { + if ( + asset && + asset._value && + asset._value.includes('__NEXT_DROP_CLIENT_FILE__') + ) { const cleanAssetKey = assetKey.replace(/\\/g, '/') const page = '/' + cleanAssetKey.split('pages/')[1] const pageNoExt = page.split(extname(page))[0] diff --git a/packages/next/build/webpack/plugins/nextjs-require-cache-hot-reloader.ts b/packages/next/build/webpack/plugins/nextjs-require-cache-hot-reloader.ts index e1e09c781cbdf..05de22e2a4419 100644 --- a/packages/next/build/webpack/plugins/nextjs-require-cache-hot-reloader.ts +++ b/packages/next/build/webpack/plugins/nextjs-require-cache-hot-reloader.ts @@ -1,10 +1,10 @@ import { Compiler, Plugin } from 'webpack' import { realpathSync } from 'fs' -function deleteCache (path: string) { +function deleteCache(path: string) { try { delete require.cache[realpathSync(path)] - } catch(e) { + } catch (e) { if (e.code !== 'ENOENT') throw e } finally { delete require.cache[path] @@ -15,23 +15,26 @@ function deleteCache (path: string) { export class NextJsRequireCacheHotReloader implements Plugin { prevAssets: any = null - apply (compiler: Compiler) { - compiler.hooks.afterEmit.tapAsync('NextJsRequireCacheHotReloader', (compilation, callback) => { - const { assets } = compilation + apply(compiler: Compiler) { + compiler.hooks.afterEmit.tapAsync( + 'NextJsRequireCacheHotReloader', + (compilation, callback) => { + const { assets } = compilation - if (this.prevAssets) { - for (const f of Object.keys(assets)) { - deleteCache(assets[f].existsAt) - } - for (const f of Object.keys(this.prevAssets)) { - if (!assets[f]) { - deleteCache(this.prevAssets[f].existsAt) + if (this.prevAssets) { + for (const f of Object.keys(assets)) { + deleteCache(assets[f].existsAt) + } + for (const f of Object.keys(this.prevAssets)) { + if (!assets[f]) { + deleteCache(this.prevAssets[f].existsAt) + } } } - } - this.prevAssets = assets + this.prevAssets = assets - callback() - }) + callback() + } + ) } } diff --git a/packages/next/build/webpack/plugins/nextjs-ssr-import.ts b/packages/next/build/webpack/plugins/nextjs-ssr-import.ts index 61ca8ae4530fa..a5aa5e81a97bf 100644 --- a/packages/next/build/webpack/plugins/nextjs-ssr-import.ts +++ b/packages/next/build/webpack/plugins/nextjs-ssr-import.ts @@ -4,18 +4,32 @@ import { Compiler } from 'webpack' // This plugin modifies the require-ensure code generated by Webpack // to work with Next.js SSR export default class NextJsSsrImportPlugin { - apply (compiler: Compiler) { + apply(compiler: Compiler) { compiler.hooks.compilation.tap('NextJsSSRImport', (compilation: any) => { - compilation.mainTemplate.hooks.requireEnsure.tap('NextJsSSRImport', (code: string, chunk: any) => { - // Update to load chunks from our custom chunks directory - const outputPath = resolve('/') - const pagePath = join('/', dirname(chunk.name)) - const relativePathToBaseDir = relative(pagePath, outputPath) - // Make sure even in windows, the path looks like in unix - // Node.js require system will convert it accordingly - const relativePathToBaseDirNormalized = relativePathToBaseDir.replace(/\\/g, '/') - return code.replace('require("./"', `require("${relativePathToBaseDirNormalized}/"`).replace('readFile(join(__dirname', `readFile(join(__dirname, "${relativePathToBaseDirNormalized}"`) - }) + compilation.mainTemplate.hooks.requireEnsure.tap( + 'NextJsSSRImport', + (code: string, chunk: any) => { + // Update to load chunks from our custom chunks directory + const outputPath = resolve('/') + const pagePath = join('/', dirname(chunk.name)) + const relativePathToBaseDir = relative(pagePath, outputPath) + // Make sure even in windows, the path looks like in unix + // Node.js require system will convert it accordingly + const relativePathToBaseDirNormalized = relativePathToBaseDir.replace( + /\\/g, + '/' + ) + return code + .replace( + 'require("./"', + `require("${relativePathToBaseDirNormalized}/"` + ) + .replace( + 'readFile(join(__dirname', + `readFile(join(__dirname, "${relativePathToBaseDirNormalized}"` + ) + } + ) }) } } diff --git a/packages/next/build/webpack/plugins/nextjs-ssr-module-cache.ts b/packages/next/build/webpack/plugins/nextjs-ssr-module-cache.ts index 2c7e0e2326291..8214af77e903b 100644 --- a/packages/next/build/webpack/plugins/nextjs-ssr-module-cache.ts +++ b/packages/next/build/webpack/plugins/nextjs-ssr-module-cache.ts @@ -18,46 +18,58 @@ const SSR_MODULE_CACHE_FILENAME = 'ssr-module-cache.js' export default class NextJsSsrImportPlugin { private options: { outputPath: string } - constructor (options: { outputPath: string }) { + constructor(options: { outputPath: string }) { this.options = options } - apply (compiler: webpack.Compiler) { + apply(compiler: webpack.Compiler) { const { outputPath } = this.options - compiler.hooks.emit.tapAsync('NextJsSSRModuleCache', (compilation, callback) => { - compilation.assets[SSR_MODULE_CACHE_FILENAME] = new RawSource(` + compiler.hooks.emit.tapAsync( + 'NextJsSSRModuleCache', + (compilation, callback) => { + compilation.assets[SSR_MODULE_CACHE_FILENAME] = new RawSource(` /* This cache is used by webpack for instantiated modules */ module.exports = {} `) - callback() - }) - compiler.hooks.compilation.tap('NextJsSSRModuleCache', (compilation: any) => { - compilation.mainTemplate.hooks.localVars.intercept({ - register (tapInfo: any) { - if (tapInfo.name === 'MainTemplate') { - const originalFn = tapInfo.fn - tapInfo.fn = (source: any, chunk: any) => { - // 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)) { - return originalFn(source, chunk) - } - const pagePath = join(outputPath, dirname(chunk.name)) - let relativePathToBaseDir = relative(pagePath, join(outputPath, SSR_MODULE_CACHE_FILENAME)) + callback() + } + ) + compiler.hooks.compilation.tap( + 'NextJsSSRModuleCache', + (compilation: any) => { + compilation.mainTemplate.hooks.localVars.intercept({ + register(tapInfo: any) { + if (tapInfo.name === 'MainTemplate') { + const originalFn = tapInfo.fn + tapInfo.fn = (source: any, chunk: any) => { + // 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)) { + return originalFn(source, chunk) + } + const pagePath = join(outputPath, dirname(chunk.name)) + let relativePathToBaseDir = relative( + pagePath, + join(outputPath, SSR_MODULE_CACHE_FILENAME) + ) - // Make sure even in windows, the path looks like in unix - // Node.js require system will convert it accordingly - const relativePathToBaseDirNormalized = relativePathToBaseDir.replace(/\\/g, '/') - return (webpack as any).Template.asString([ - source, - '// The module cache', - `var installedModules = require('${relativePathToBaseDirNormalized}');` - ]) + // Make sure even in windows, the path looks like in unix + // Node.js require system will convert it accordingly + const relativePathToBaseDirNormalized = relativePathToBaseDir.replace( + /\\/g, + '/' + ) + return (webpack as any).Template.asString([ + source, + '// The module cache', + `var installedModules = require('${relativePathToBaseDirNormalized}');`, + ]) + } } - } - return tapInfo - } - }) - }) + return tapInfo + }, + }) + } + ) } } diff --git a/packages/next/build/webpack/plugins/pages-manifest-plugin.ts b/packages/next/build/webpack/plugins/pages-manifest-plugin.ts index 30700691ac033..d8f34fd5f73ce 100644 --- a/packages/next/build/webpack/plugins/pages-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/pages-manifest-plugin.ts @@ -1,6 +1,10 @@ -import {Compiler, Plugin} from 'webpack' +import { Compiler, Plugin } from 'webpack' import { RawSource } from 'webpack-sources' -import { PAGES_MANIFEST, ROUTE_NAME_REGEX, SERVERLESS_ROUTE_NAME_REGEX } from 'next-server/constants' +import { + PAGES_MANIFEST, + ROUTE_NAME_REGEX, + SERVERLESS_ROUTE_NAME_REGEX, +} from 'next-server/constants' // This plugin creates a pages-manifest.json from page entrypoints. // This is used for mapping paths like `/` to `.next/server/static/<buildid>/pages/index.js` when doing SSR @@ -8,18 +12,20 @@ import { PAGES_MANIFEST, ROUTE_NAME_REGEX, SERVERLESS_ROUTE_NAME_REGEX } from 'n export default class PagesManifestPlugin implements Plugin { serverless: boolean - constructor (serverless: boolean) { + constructor(serverless: boolean) { this.serverless = serverless } - apply (compiler: Compiler): void { - compiler.hooks.emit.tap('NextJsPagesManifest', (compilation) => { + apply(compiler: Compiler): void { + compiler.hooks.emit.tap('NextJsPagesManifest', compilation => { const { chunks } = compilation - const pages: {[page: string]: string} = {} + const pages: { [page: string]: string } = {} for (const chunk of chunks) { const result = (this.serverless - ? SERVERLESS_ROUTE_NAME_REGEX : ROUTE_NAME_REGEX).exec(chunk.name) + ? SERVERLESS_ROUTE_NAME_REGEX + : ROUTE_NAME_REGEX + ).exec(chunk.name) if (!result) { continue @@ -32,7 +38,10 @@ export default class PagesManifestPlugin implements Plugin { } // Write filename, replace any backslashes in path (on windows) with forwardslashes for cross-platform consistency. - pages[`/${pagePath.replace(/\\/g, '/')}`] = chunk.name.replace(/\\/g, '/') + pages[`/${pagePath.replace(/\\/g, '/')}`] = chunk.name.replace( + /\\/g, + '/' + ) } if (typeof pages['/index'] !== 'undefined') { diff --git a/packages/next/build/webpack/plugins/react-loadable-plugin.ts b/packages/next/build/webpack/plugins/react-loadable-plugin.ts index b2dc74a883590..c2dcbd4459249 100644 --- a/packages/next/build/webpack/plugins/react-loadable-plugin.ts +++ b/packages/next/build/webpack/plugins/react-loadable-plugin.ts @@ -24,7 +24,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWAR import url from 'url' import { Compiler, compilation } from 'webpack' -function buildManifest (compiler: Compiler, compilation: compilation.Compilation) { +function buildManifest( + compiler: Compiler, + compilation: compilation.Compilation +) { let context = compiler.options.context let manifest: { [k: string]: any[] } = {} @@ -67,7 +70,7 @@ function buildManifest (compiler: Compiler, compilation: compilation.Compilation id, name, file, - publicPath + publicPath, }) } }) @@ -85,23 +88,23 @@ function buildManifest (compiler: Compiler, compilation: compilation.Compilation export class ReactLoadablePlugin { private filename: string - constructor (opts: { filename: string }) { + constructor(opts: { filename: string }) { this.filename = opts.filename } - apply (compiler: Compiler) { + apply(compiler: Compiler) { compiler.hooks.emit.tapAsync( 'ReactLoadableManifest', (compilation, callback) => { const manifest = buildManifest(compiler, compilation) var json = JSON.stringify(manifest, null, 2) compilation.assets[this.filename] = { - source () { + source() { return json }, - size () { + size() { return json.length - } + }, } callback() } diff --git a/packages/next/build/webpack/plugins/serverless-plugin.ts b/packages/next/build/webpack/plugins/serverless-plugin.ts index 4f94362f52465..5eec0eaaacd07 100644 --- a/packages/next/build/webpack/plugins/serverless-plugin.ts +++ b/packages/next/build/webpack/plugins/serverless-plugin.ts @@ -66,22 +66,25 @@ export class ServerlessPlugin { replaceInBuffer(content, NEXT_REPLACE_BUILD_ID, this.buildId) ) - compiler.hooks.compilation.tap('ServerlessPlugin', compilation => { - compilation.hooks.optimizeChunksBasic.tap('ServerlessPlugin', chunks => { - chunks.forEach(chunk => { - // If chunk is not an entry point skip them - if (chunk.hasEntryModule()) { - const dynamicChunks = chunk.getAllAsyncChunks() - if (dynamicChunks.size !== 0) { - for (const dynamicChunk of dynamicChunks) { - for (const module of dynamicChunk.modulesIterable) { - connectChunkAndModule(chunk, module) + compiler.hooks.compilation.tap('ServerlessPlugin', compilation => { + compilation.hooks.optimizeChunksBasic.tap( + 'ServerlessPlugin', + chunks => { + chunks.forEach(chunk => { + // If chunk is not an entry point skip them + if (chunk.hasEntryModule()) { + const dynamicChunks = chunk.getAllAsyncChunks() + if (dynamicChunks.size !== 0) { + for (const dynamicChunk of dynamicChunks) { + for (const module of dynamicChunk.modulesIterable) { + connectChunkAndModule(chunk, module) + } + } } } - } + }) } - }) - }) + ) }) } else { compiler.hooks.emit.tap('ServerlessPlugin', compilation => { diff --git a/packages/next/build/webpack/plugins/terser-webpack-plugin/src/index.d.ts b/packages/next/build/webpack/plugins/terser-webpack-plugin/src/index.d.ts index 61c6d48fa0bc7..018e07f7300f2 100644 --- a/packages/next/build/webpack/plugins/terser-webpack-plugin/src/index.d.ts +++ b/packages/next/build/webpack/plugins/terser-webpack-plugin/src/index.d.ts @@ -7,8 +7,19 @@ export class TerserPlugin { static isSourceMap(input: any): any static buildSourceMap(inputSourceMap: any): any - static buildError(err: any, file: any, sourceMap: any, requestShortener?: any): any - static buildWarning(warning: any, file: any, sourceMap: any, requestShortener?: any, warningsFilter?: any): any + static buildError( + err: any, + file: any, + sourceMap: any, + requestShortener?: any + ): any + static buildWarning( + warning: any, + file: any, + sourceMap: any, + requestShortener?: any, + warningsFilter?: any + ): any apply(compiler: any): void } diff --git a/packages/next/build/webpack/plugins/terser-webpack-plugin/src/index.js b/packages/next/build/webpack/plugins/terser-webpack-plugin/src/index.js index 31a6a15af7d48..a93329ae66edf 100644 --- a/packages/next/build/webpack/plugins/terser-webpack-plugin/src/index.js +++ b/packages/next/build/webpack/plugins/terser-webpack-plugin/src/index.js @@ -4,7 +4,7 @@ import stringHash from 'string-hash' import { SourceMapConsumer } from 'source-map' import { SourceMapSource, RawSource } from 'webpack-sources' -import { RequestShortener } from 'webpack'; +import { RequestShortener } from 'webpack' import TaskRunner from './TaskRunner' const warningRegex = /\[.+:([0-9]+),([0-9]+)\]/ diff --git a/packages/next/build/webpack/plugins/terser-webpack-plugin/src/minify.ts b/packages/next/build/webpack/plugins/terser-webpack-plugin/src/minify.ts index df6fdd98ede8d..0ca68c1ddcc5d 100644 --- a/packages/next/build/webpack/plugins/terser-webpack-plugin/src/minify.ts +++ b/packages/next/build/webpack/plugins/terser-webpack-plugin/src/minify.ts @@ -1,7 +1,7 @@ /* eslint-disable arrow-body-style */ -import { minify as terser, MinifyOptions } from 'terser'; +import { minify as terser, MinifyOptions } from 'terser' const buildTerserOptions = ({ ecma, @@ -43,31 +43,32 @@ const buildTerserOptions = ({ keep_classnames, keep_fnames, safari10, -}); +}) -const minify = (options: { file: string, input: string, inputSourceMap?: string, terserOptions?: MinifyOptions }) => { - const { - file, - input, - inputSourceMap - } = options; +const minify = (options: { + file: string + input: string + inputSourceMap?: string + terserOptions?: MinifyOptions +}) => { + const { file, input, inputSourceMap } = options // Copy terser options - const terserOptions = buildTerserOptions(options.terserOptions) as any; + const terserOptions = buildTerserOptions(options.terserOptions) as any // Add source map data if (inputSourceMap) { terserOptions.sourceMap = { content: inputSourceMap, - }; + } } const { error, map, code, warnings } = terser( { [file]: input }, terserOptions - ); + ) - return { error, map, code, warnings }; -}; + return { error, map, code, warnings } +} -export default minify; +export default minify diff --git a/packages/next/build/webpack/plugins/terser-webpack-plugin/src/worker.js b/packages/next/build/webpack/plugins/terser-webpack-plugin/src/worker.js index 1d8b7aa8733c2..8f0e6af9a304d 100644 --- a/packages/next/build/webpack/plugins/terser-webpack-plugin/src/worker.js +++ b/packages/next/build/webpack/plugins/terser-webpack-plugin/src/worker.js @@ -1,4 +1,4 @@ -import minify from './minify'; +import minify from './minify' module.exports = (options, callback) => { try { @@ -12,10 +12,10 @@ module.exports = (options, callback) => { '__filename', '__dirname', `'use strict'\nreturn ${options}` - )(exports, require, module, __filename, __dirname); + )(exports, require, module, __filename, __dirname) - callback(null, minify(options)); + callback(null, minify(options)) } catch (errors) { - callback(errors); + callback(errors) } -}; +} diff --git a/packages/next/build/webpack/plugins/unlink-removed-pages-plugin.ts b/packages/next/build/webpack/plugins/unlink-removed-pages-plugin.ts index 73c4d1bb58361..8549bf5b5ef99 100644 --- a/packages/next/build/webpack/plugins/unlink-removed-pages-plugin.ts +++ b/packages/next/build/webpack/plugins/unlink-removed-pages-plugin.ts @@ -2,34 +2,39 @@ import { join } from 'path' import { promisify } from 'util' import fs from 'fs' import { IS_BUNDLED_PAGE_REGEX } from 'next-server/constants' -import {Compiler} from 'webpack' +import { Compiler } from 'webpack' const unlink = promisify(fs.unlink) // Makes sure removed pages are removed from `.next` in development export class UnlinkRemovedPagesPlugin { prevAssets: any - constructor () { + constructor() { this.prevAssets = {} } - apply (compiler: Compiler) { - compiler.hooks.afterEmit.tapAsync('NextJsUnlinkRemovedPages', (compilation, callback) => { - const removed = Object.keys(this.prevAssets) - .filter((a) => IS_BUNDLED_PAGE_REGEX.test(a) && !compilation.assets[a]) + apply(compiler: Compiler) { + compiler.hooks.afterEmit.tapAsync( + 'NextJsUnlinkRemovedPages', + (compilation, callback) => { + const removed = Object.keys(this.prevAssets).filter( + a => IS_BUNDLED_PAGE_REGEX.test(a) && !compilation.assets[a] + ) - this.prevAssets = compilation.assets + this.prevAssets = compilation.assets - Promise.all(removed.map(async (f) => { - const path = join((compiler as any).outputPath, f) - try { - await unlink(path) - } catch (err) { - if (err.code === 'ENOENT') return - throw err - } - })) - .then(() => callback(), callback) - }) + Promise.all( + removed.map(async f => { + const path = join((compiler as any).outputPath, f) + try { + await unlink(path) + } catch (err) { + if (err.code === 'ENOENT') return + throw err + } + }) + ).then(() => callback(), callback) + } + ) } } diff --git a/packages/next/cli/next-build.ts b/packages/next/cli/next-build.ts index a8a316fc21aef..1576dd401a4dd 100755 --- a/packages/next/cli/next-build.ts +++ b/packages/next/cli/next-build.ts @@ -6,7 +6,7 @@ import build from '../build' import { printAndExit } from '../server/lib/utils' import { cliCommand } from '../bin/next' -const nextBuild: cliCommand = (argv) => { +const nextBuild: cliCommand = argv => { const args = arg( { // Types @@ -14,7 +14,7 @@ const nextBuild: cliCommand = (argv) => { // Aliases '-h': '--help', }, - { argv }, + { argv } ) if (args['--help']) { @@ -30,7 +30,7 @@ const nextBuild: cliCommand = (argv) => { If no directory is provided, the dist folder will be created in the current directory. You can set a custom folder in config https://github.com/zeit/next.js#custom-configuration, otherwise it will be created inside '.next' `, - 0, + 0 ) } @@ -46,16 +46,16 @@ const nextBuild: cliCommand = (argv) => { // Check one level down the tree to see if the pages directory might be there if (existsSync(join(dir, '..', 'pages'))) { printAndExit( - '> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?', + '> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?' ) } printAndExit( - "> Couldn't find a `pages` directory. Please create one under the project root", + "> Couldn't find a `pages` directory. Please create one under the project root" ) } - build(dir).catch((err) => { + build(dir).catch(err => { // tslint:disable-next-line console.error('> Build error occurred') printAndExit(err) diff --git a/packages/next/cli/next-dev.ts b/packages/next/cli/next-dev.ts index 08673d56ed7a0..3810a6aa99105 100755 --- a/packages/next/cli/next-dev.ts +++ b/packages/next/cli/next-dev.ts @@ -7,18 +7,21 @@ import { printAndExit } from '../server/lib/utils' import { startedDevelopmentServer } from '../build/output' import { cliCommand } from '../bin/next' -const nextDev: cliCommand = (argv) => { - const args = arg({ - // Types - '--help': Boolean, - '--port': Number, - '--hostname': String, +const nextDev: cliCommand = argv => { + const args = arg( + { + // Types + '--help': Boolean, + '--port': Number, + '--hostname': String, - // Aliases - '-h': '--help', - '-p': '--port', - '-H': '--hostname', - }, { argv }) + // Aliases + '-h': '--help', + '-p': '--port', + '-H': '--hostname', + }, + { argv } + ) if (args['--help']) { // tslint:disable-next-line @@ -51,10 +54,14 @@ const nextDev: cliCommand = (argv) => { if (!existsSync(join(dir, 'pages'))) { if (existsSync(join(dir, '..', 'pages'))) { - printAndExit('> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?') + printAndExit( + '> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?' + ) } - printAndExit('> Couldn\'t find a `pages` directory. Please create one under the project root') + printAndExit( + "> Couldn't find a `pages` directory. Please create one under the project root" + ) } const port = args['--port'] || 3000 @@ -62,11 +69,11 @@ const nextDev: cliCommand = (argv) => { startedDevelopmentServer(appUrl) - startServer({dir, dev: true}, port, args['--hostname']) - .then(async (app) => { + startServer({ dir, dev: true }, port, args['--hostname']) + .then(async app => { await app.prepare() }) - .catch((err) => { + .catch(err => { if (err.code === 'EADDRINUSE') { let errorMessage = `Port ${port} is already in use.` const pkgAppPath = require('find-up').sync('package.json', { @@ -74,9 +81,13 @@ const nextDev: cliCommand = (argv) => { }) const appPackage = require(pkgAppPath) 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) { - errorMessage += `\nUse \`npm run ${nextScript[0]} -- -p <some other port>\`.` + errorMessage += `\nUse \`npm run ${ + nextScript[0] + } -- -p <some other port>\`.` } } // tslint:disable-next-line diff --git a/packages/next/cli/next-export.ts b/packages/next/cli/next-export.ts index 7465e12b74bc3..2f8a4a88cf617 100755 --- a/packages/next/cli/next-export.ts +++ b/packages/next/cli/next-export.ts @@ -6,20 +6,23 @@ import exportApp from '../export' import { printAndExit } from '../server/lib/utils' import { cliCommand } from '../bin/next' -const nextExport: cliCommand = (argv) => { - const args = arg({ - // Types - '--help': Boolean, - '--silent': Boolean, - '--outdir': String, - '--threads': Number, - '--concurrency': Number, +const nextExport: cliCommand = argv => { + const args = arg( + { + // Types + '--help': Boolean, + '--silent': Boolean, + '--outdir': String, + '--threads': Number, + '--concurrency': Number, - // Aliases - '-h': '--help', - '-s': '--silent', - '-o': '--outdir', - }, { argv }) + // Aliases + '-h': '--help', + '-s': '--silent', + '-o': '--outdir', + }, + { argv } + ) if (args['--help']) { // tslint:disable-next-line @@ -50,10 +53,14 @@ const nextExport: cliCommand = (argv) => { if (!existsSync(join(dir, 'pages'))) { if (existsSync(join(dir, '..', 'pages'))) { - printAndExit('> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?') + printAndExit( + '> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?' + ) } - printAndExit('> Couldn\'t find a `pages` directory. Please create one under the project root') + printAndExit( + "> Couldn't find a `pages` directory. Please create one under the project root" + ) } const options = { @@ -67,7 +74,7 @@ const nextExport: cliCommand = (argv) => { .then(() => { printAndExit('Export successful', 0) }) - .catch((err) => { + .catch(err => { printAndExit(err) }) } diff --git a/packages/next/cli/next-start.ts b/packages/next/cli/next-start.ts index 49b73e13891bd..ce48d4e2bb2e2 100755 --- a/packages/next/cli/next-start.ts +++ b/packages/next/cli/next-start.ts @@ -5,18 +5,21 @@ import arg from 'next/dist/compiled/arg/index.js' import startServer from '../server/lib/start-server' import { cliCommand } from '../bin/next' -const nextStart: cliCommand = (argv) => { - const args = arg({ - // Types - '--help': Boolean, - '--port': Number, - '--hostname': String, - - // Aliases - '-h': '--help', - '-p': '--port', - '-H': '--hostname', - }, { argv }) +const nextStart: cliCommand = argv => { + const args = arg( + { + // Types + '--help': Boolean, + '--port': Number, + '--hostname': String, + + // Aliases + '-h': '--help', + '-p': '--port', + '-H': '--hostname', + }, + { argv } + ) if (args['--help']) { // tslint:disable-next-line @@ -43,13 +46,15 @@ const nextStart: cliCommand = (argv) => { const dir = resolve(args._[0] || '.') const port = args['--port'] || 3000 - startServer({dir}, port, args['--hostname']) - .then(async (app) => { + startServer({ dir }, port, args['--hostname']) + .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() }) - .catch((err) => { + .catch(err => { // tslint:disable-next-line console.error(err) process.exit(1) diff --git a/packages/next/client.d.ts b/packages/next/client.d.ts index 01cb06caeaaba..515d08c98d28b 100644 --- a/packages/next/client.d.ts +++ b/packages/next/client.d.ts @@ -1,2 +1,2 @@ export * from './dist/client/index' -export {default} from './dist/client/index' +export { default } from './dist/client/index' diff --git a/packages/next/client/amp-dev.js b/packages/next/client/amp-dev.js index 5c9feb500b9f2..fde6320349a35 100644 --- a/packages/next/client/amp-dev.js +++ b/packages/next/client/amp-dev.js @@ -14,7 +14,8 @@ assetPrefix = assetPrefix || '' let mostRecentHash = null /* eslint-disable-next-line */ let curHash = __webpack_hash__ -const hotUpdatePath = assetPrefix + (assetPrefix.endsWith('/') ? '' : '/') + '_next/static/webpack/' +const hotUpdatePath = + assetPrefix + (assetPrefix.endsWith('/') ? '' : '/') + '_next/static/webpack/' // Is there a newer version of this code available? function isUpdateAvailable () { @@ -39,13 +40,18 @@ async function tryApplyUpdates () { const res = await fetch(`${hotUpdatePath}${curHash}.hot-update.json`) const data = await res.json() const curPage = page === '/' ? 'index' : page - const pageUpdated = Object.keys(data.c) - .some(mod => { - return ( - mod.indexOf(`pages${curPage.substr(0, 1) === '/' ? curPage : `/${curPage}`}`) !== -1 || - mod.indexOf(`pages${curPage.substr(0, 1) === '/' ? curPage : `/${curPage}`}`.replace(/\//g, '\\')) !== -1 - ) - }) + const pageUpdated = Object.keys(data.c).some(mod => { + return ( + mod.indexOf( + `pages${curPage.substr(0, 1) === '/' ? curPage : `/${curPage}`}` + ) !== -1 || + mod.indexOf( + `pages${ + curPage.substr(0, 1) === '/' ? curPage : `/${curPage}` + }`.replace(/\//g, '\\') + ) !== -1 + ) + }) if (pageUpdated) { document.location.reload(true) diff --git a/packages/next/client/dev-build-watcher.js b/packages/next/client/dev-build-watcher.js index 046c62f861c9a..b3f8a5fe04c1e 100644 --- a/packages/next/client/dev-build-watcher.js +++ b/packages/next/client/dev-build-watcher.js @@ -38,7 +38,7 @@ export default function initializeBuildWatcher () { // Handle events const evtSource = getEventSourceWrapper({ path: '/_next/webpack-hmr' }) - evtSource.addMessageListener((event) => { + evtSource.addMessageListener(event => { // This is the heartbeat event if (event.data === '\uD83D\uDC93') { return @@ -46,7 +46,7 @@ export default function initializeBuildWatcher () { try { handleMessage(event) - } catch { } + } catch {} }) function handleMessage (event) { diff --git a/packages/next/client/dev-error-overlay/eventsource.js b/packages/next/client/dev-error-overlay/eventsource.js index 3d6500dc09a70..63e6701f83af4 100644 --- a/packages/next/client/dev-error-overlay/eventsource.js +++ b/packages/next/client/dev-error-overlay/eventsource.js @@ -11,7 +11,7 @@ function EventSourceWrapper (options) { init() var timer = setInterval(function () { - if ((new Date() - lastActivity) > options.timeout) { + if (new Date() - lastActivity > options.timeout) { handleDisconnect() } }, options.timeout / 2) diff --git a/packages/next/client/dev-error-overlay/format-webpack-messages.d.ts b/packages/next/client/dev-error-overlay/format-webpack-messages.d.ts index 007398fa41491..a91396030a211 100644 --- a/packages/next/client/dev-error-overlay/format-webpack-messages.d.ts +++ b/packages/next/client/dev-error-overlay/format-webpack-messages.d.ts @@ -1 +1 @@ -export default function formatWebpackMessages(json: any): any; +export default function formatWebpackMessages(json: any): any diff --git a/packages/next/client/dev-error-overlay/hot-dev-client.js b/packages/next/client/dev-error-overlay/hot-dev-client.js index cada5ac876875..b983104f45c42 100644 --- a/packages/next/client/dev-error-overlay/hot-dev-client.js +++ b/packages/next/client/dev-error-overlay/hot-dev-client.js @@ -50,7 +50,11 @@ let hadRuntimeError = false let customHmrEventHandler export default function connect (options) { // Open stack traces in an editor. - ErrorOverlay.setEditorHandler(function editorHandler ({ fileName, lineNumber, colNumber }) { + ErrorOverlay.setEditorHandler(function editorHandler ({ + fileName, + lineNumber, + colNumber + }) { // Resolve invalid paths coming from react-error-overlay const resolvedFilename = fileName.replace(/^webpack:\/\//, '') fetch( @@ -80,7 +84,7 @@ export default function connect (options) { }) } - getEventSourceWrapper(options).addMessageListener((event) => { + getEventSourceWrapper(options).addMessageListener(event => { // This is the heartbeat event if (event.data === '\uD83D\uDC93') { return @@ -204,8 +208,7 @@ function processMessage (e) { switch (obj.action) { case 'building': { console.log( - '[HMR] bundle ' + (obj.name ? "'" + obj.name + "' " : '') + - 'rebuilding' + '[HMR] bundle ' + (obj.name ? "'" + obj.name + "' " : '') + 'rebuilding' ) break } @@ -295,9 +298,11 @@ async function tryApplyUpdates (onHotUpdateSuccess) { // https://webpack.github.io/docs/hot-module-replacement.html#check try { - const updatedModules = await module.hot.check(/* autoApply */ { - ignoreUnaccepted: true - }) + const updatedModules = await module.hot.check( + /* autoApply */ { + ignoreUnaccepted: true + } + ) if (updatedModules) { handleApplyUpdates(null, updatedModules) } diff --git a/packages/next/client/error-boundary.ts b/packages/next/client/error-boundary.ts index 30eb5e34c4656..6ab0772c33396 100644 --- a/packages/next/client/error-boundary.ts +++ b/packages/next/client/error-boundary.ts @@ -1,6 +1,8 @@ -import React, {ErrorInfo} from 'react' +import React, { ErrorInfo } from 'react' -export class ErrorBoundary extends React.Component<{fn: (err: Error, info: ErrorInfo) => void}> { +export class ErrorBoundary extends React.Component<{ + fn: (err: Error, info: ErrorInfo) => void +}> { componentDidCatch(err: Error, info: ErrorInfo) { this.props.fn(err, info) } diff --git a/packages/next/client/event-source-polyfill.js b/packages/next/client/event-source-polyfill.js index b7fa0f9862679..ac556236c8154 100644 --- a/packages/next/client/event-source-polyfill.js +++ b/packages/next/client/event-source-polyfill.js @@ -11,32 +11,34 @@ var TextEncoder = window.TextEncoder var AbortController = window.AbortController if (AbortController == undefined) { - AbortController = function () { + AbortController = function() { this.signal = null - this.abort = function () { - } + this.abort = function() {} } } -function TextDecoderPolyfill () { +function TextDecoderPolyfill() { this.bitsNeeded = 0 this.codePoint = 0 } -TextDecoderPolyfill.prototype.decode = function (octets) { - function valid (codePoint, shift, octetsCount) { +TextDecoderPolyfill.prototype.decode = function(octets) { + function valid(codePoint, shift, octetsCount) { if (octetsCount === 1) { - return codePoint >= 0x0080 >> shift && codePoint << shift <= 0x07FF + return codePoint >= 0x0080 >> shift && codePoint << shift <= 0x07ff } if (octetsCount === 2) { - return codePoint >= 0x0800 >> shift && codePoint << shift <= 0xD7FF || codePoint >= 0xE000 >> shift && codePoint << shift <= 0xFFFF + return ( + (codePoint >= 0x0800 >> shift && codePoint << shift <= 0xd7ff) || + (codePoint >= 0xe000 >> shift && codePoint << shift <= 0xffff) + ) } if (octetsCount === 3) { - return codePoint >= 0x010000 >> shift && codePoint << shift <= 0x10FFFF + return codePoint >= 0x010000 >> shift && codePoint << shift <= 0x10ffff } throw new Error() } - function octetsCount (bitsNeeded, codePoint) { + function octetsCount(bitsNeeded, codePoint) { if (bitsNeeded === 6 * 1) { return codePoint >> 6 > 15 ? 3 : codePoint > 31 ? 2 : 1 } @@ -48,14 +50,22 @@ TextDecoderPolyfill.prototype.decode = function (octets) { } throw new Error() } - var REPLACER = 0xFFFD + var REPLACER = 0xfffd var string = '' var bitsNeeded = this.bitsNeeded var codePoint = this.codePoint for (var i = 0; i < octets.length; i += 1) { var octet = octets[i] if (bitsNeeded !== 0) { - if (octet < 128 || octet > 191 || !valid(codePoint << 6 | octet & 63, bitsNeeded - 6, octetsCount(bitsNeeded, codePoint))) { + if ( + octet < 128 || + octet > 191 || + !valid( + (codePoint << 6) | (octet & 63), + bitsNeeded - 6, + octetsCount(bitsNeeded, codePoint) + ) + ) { bitsNeeded = 0 codePoint = REPLACER string += String.fromCharCode(codePoint) @@ -78,20 +88,25 @@ TextDecoderPolyfill.prototype.decode = function (octets) { bitsNeeded = 0 codePoint = REPLACER } - if (bitsNeeded !== 0 && !valid(codePoint, bitsNeeded, octetsCount(bitsNeeded, codePoint))) { + if ( + bitsNeeded !== 0 && + !valid(codePoint, bitsNeeded, octetsCount(bitsNeeded, codePoint)) + ) { bitsNeeded = 0 codePoint = REPLACER } } else { bitsNeeded -= 6 - codePoint = codePoint << 6 | octet & 63 + codePoint = (codePoint << 6) | (octet & 63) } if (bitsNeeded === 0) { - if (codePoint <= 0xFFFF) { + if (codePoint <= 0xffff) { string += String.fromCharCode(codePoint) } else { - string += String.fromCharCode(0xD800 + (codePoint - 0xFFFF - 1 >> 10)) - string += String.fromCharCode(0xDC00 + (codePoint - 0xFFFF - 1 & 0x3FF)) + string += String.fromCharCode(0xd800 + ((codePoint - 0xffff - 1) >> 10)) + string += String.fromCharCode( + 0xdc00 + ((codePoint - 0xffff - 1) & 0x3ff) + ) } } } @@ -101,9 +116,13 @@ TextDecoderPolyfill.prototype.decode = function (octets) { } // Firefox < 38 throws an error with stream option -var supportsStreamOption = function () { +var supportsStreamOption = function() { try { - return new TextDecoder().decode(new TextEncoder().encode('test'), { stream: true }) === 'test' + return ( + new TextDecoder().decode(new TextEncoder().encode('test'), { + stream: true, + }) === 'test' + ) } catch (error) { console.log(error) } @@ -111,14 +130,17 @@ var supportsStreamOption = function () { } // IE, Edge -if (TextDecoder == undefined || TextEncoder == undefined || !supportsStreamOption()) { +if ( + TextDecoder == undefined || + TextEncoder == undefined || + !supportsStreamOption() +) { TextDecoder = TextDecoderPolyfill } -var k = function () { -} +var k = function() {} -function XHRWrapper (xhr) { +function XHRWrapper(xhr) { this.withCredentials = false this.responseType = '' this.readyState = 0 @@ -133,7 +155,7 @@ function XHRWrapper (xhr) { this._abort = k } -XHRWrapper.prototype.open = function (method, url) { +XHRWrapper.prototype.open = function(method, url) { this._abort(true) var that = this @@ -141,7 +163,7 @@ XHRWrapper.prototype.open = function (method, url) { var state = 1 var timeout = 0 - this._abort = function (silent) { + this._abort = function(silent) { if (that._sendTimeout !== 0) { clearTimeout(that._sendTimeout) that._sendTimeout = 0 @@ -168,7 +190,7 @@ XHRWrapper.prototype.open = function (method, url) { state = 0 } - var onStart = function () { + var onStart = function() { if (state === 1) { // state = 2; var status = 0 @@ -205,7 +227,7 @@ XHRWrapper.prototype.open = function (method, url) { } } } - var onProgress = function () { + var onProgress = function() { onStart() if (state === 2 || state === 3) { state = 3 @@ -220,7 +242,7 @@ XHRWrapper.prototype.open = function (method, url) { that.onprogress() } } - var onFinish = function () { + var onFinish = function() { // Firefox 52 fires "readystatechange" (xhr.readyState === 4) without final "readystatechange" (xhr.readyState === 3) // IE 8 fires "onload" without "onprogress" onProgress() @@ -234,8 +256,9 @@ XHRWrapper.prototype.open = function (method, url) { that.onreadystatechange() } } - var onReadyStateChange = function () { - if (xhr != undefined) { // Opera 12 + var onReadyStateChange = function() { + if (xhr != undefined) { + // Opera 12 if (xhr.readyState === 4) { onFinish() } else if (xhr.readyState === 3) { @@ -245,8 +268,8 @@ XHRWrapper.prototype.open = function (method, url) { } } } - var onTimeout = function () { - timeout = setTimeout(function () { + var onTimeout = function() { + timeout = setTimeout(function() { onTimeout() }, 500) if (xhr.readyState === 3) { @@ -265,7 +288,10 @@ XHRWrapper.prototype.open = function (method, url) { xhr.onabort = onFinish // https://bugzilla.mozilla.org/show_bug.cgi?id=736723 - if (!('sendAsBinary' in XMLHttpRequest.prototype) && !('mozAnon' in XMLHttpRequest.prototype)) { + if ( + !('sendAsBinary' in XMLHttpRequest.prototype) && + !('mozAnon' in XMLHttpRequest.prototype) + ) { xhr.onprogress = onProgress } @@ -285,34 +311,38 @@ XHRWrapper.prototype.open = function (method, url) { if ('readyState' in xhr) { // workaround for Opera 12 issue with "progress" events // #91 - timeout = setTimeout(function () { + timeout = setTimeout(function() { onTimeout() }, 0) } } -XHRWrapper.prototype.abort = function () { +XHRWrapper.prototype.abort = function() { this._abort(false) } -XHRWrapper.prototype.getResponseHeader = function (name) { +XHRWrapper.prototype.getResponseHeader = function(name) { return this._contentType } -XHRWrapper.prototype.setRequestHeader = function (name, value) { +XHRWrapper.prototype.setRequestHeader = function(name, value) { var xhr = this._xhr if ('setRequestHeader' in xhr) { xhr.setRequestHeader(name, value) } } -XHRWrapper.prototype.getAllResponseHeaders = function () { - return this._xhr.getAllResponseHeaders != undefined ? this._xhr.getAllResponseHeaders() : '' +XHRWrapper.prototype.getAllResponseHeaders = function() { + return this._xhr.getAllResponseHeaders != undefined + ? this._xhr.getAllResponseHeaders() + : '' } -XHRWrapper.prototype.send = function () { +XHRWrapper.prototype.send = function() { // loading indicator in Safari < ? (6), Chrome < 14, Firefox - if (!('ontimeout' in XMLHttpRequest.prototype) && - document != undefined && - document.readyState != undefined && - document.readyState !== 'complete') { + if ( + !('ontimeout' in XMLHttpRequest.prototype) && + document != undefined && + document.readyState != undefined && + document.readyState !== 'complete' + ) { var that = this - that._sendTimeout = setTimeout(function () { + that._sendTimeout = setTimeout(function() { that._sendTimeout = 0 that.send() }, 4) @@ -332,13 +362,13 @@ XHRWrapper.prototype.send = function () { } } -function toLowerCase (name) { - return name.replace(/[A-Z]/g, function (c) { +function toLowerCase(name) { + return name.replace(/[A-Z]/g, function(c) { return String.fromCharCode(c.charCodeAt(0) + 0x20) }) } -function HeadersPolyfill (all) { +function HeadersPolyfill(all) { // Get headers: implemented according to mozilla's example code: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders#Example var map = Object.create(null) var array = all.split('\r\n') @@ -351,31 +381,44 @@ function HeadersPolyfill (all) { } this._map = map } -HeadersPolyfill.prototype.get = function (name) { +HeadersPolyfill.prototype.get = function(name) { return this._map[toLowerCase(name)] } -function XHRTransport () { -} +function XHRTransport() {} -XHRTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) { +XHRTransport.prototype.open = function( + xhr, + onStartCallback, + onProgressCallback, + onFinishCallback, + url, + withCredentials, + headers +) { xhr.open('GET', url) var offset = 0 - xhr.onprogress = function () { + xhr.onprogress = function() { var responseText = xhr.responseText var chunk = responseText.slice(offset) offset += chunk.length onProgressCallback(chunk) } - xhr.onreadystatechange = function () { + xhr.onreadystatechange = function() { if (xhr.readyState === 2) { var status = xhr.status var statusText = xhr.statusText var contentType = xhr.getResponseHeader('Content-Type') var headers = xhr.getAllResponseHeaders() - onStartCallback(status, statusText, contentType, new HeadersPolyfill(headers), function () { - xhr.abort() - }) + onStartCallback( + status, + statusText, + contentType, + new HeadersPolyfill(headers), + function() { + xhr.abort() + } + ) } else if (xhr.readyState === 4) { onFinishCallback() } @@ -390,68 +433,89 @@ XHRTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback xhr.send() } -function HeadersWrapper (headers) { +function HeadersWrapper(headers) { this._headers = headers } -HeadersWrapper.prototype.get = function (name) { +HeadersWrapper.prototype.get = function(name) { return this._headers.get(name) } -function FetchTransport () { -} +function FetchTransport() {} -FetchTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) { +FetchTransport.prototype.open = function( + xhr, + onStartCallback, + onProgressCallback, + onFinishCallback, + url, + withCredentials, + headers +) { var controller = new AbortController() - var signal = controller.signal// see #120 + var signal = controller.signal // see #120 var textDecoder = new TextDecoder() fetch(url, { headers: headers, credentials: withCredentials ? 'include' : 'same-origin', signal: signal, - cache: 'no-store' - }).then(function (response) { - var reader = response.body.getReader() - onStartCallback(response.status, response.statusText, response.headers.get('Content-Type'), new HeadersWrapper(response.headers), function () { - controller.abort() - reader.cancel() + cache: 'no-store', + }) + .then(function(response) { + var reader = response.body.getReader() + onStartCallback( + response.status, + response.statusText, + response.headers.get('Content-Type'), + new HeadersWrapper(response.headers), + function() { + controller.abort() + reader.cancel() + } + ) + return new Promise(function(resolve, reject) { + var readNextChunk = function() { + reader + .read() + .then(function(result) { + if (result.done) { + // Note: bytes in textDecoder are ignored + resolve(undefined) + } else { + var chunk = textDecoder.decode(result.value, { stream: true }) + onProgressCallback(chunk) + readNextChunk() + } + }) + ['catch'](function(error) { + reject(error) + }) + } + readNextChunk() + }) }) - return new Promise(function (resolve, reject) { - var readNextChunk = function () { - reader.read().then(function (result) { - if (result.done) { - // Note: bytes in textDecoder are ignored - resolve(undefined) - } else { - var chunk = textDecoder.decode(result.value, { stream: true }) - onProgressCallback(chunk) - readNextChunk() - } - })['catch'](function (error) { - reject(error) - }) + .then( + function(result) { + onFinishCallback() + return result + }, + function(error) { + onFinishCallback() + return Promise.reject(error) } - readNextChunk() - }) - }).then(function(result) { - onFinishCallback() - return result - }, function(error) { - onFinishCallback() - return Promise.reject(error) - }) + ) } -function EventTarget () { +function EventTarget() { this._listeners = Object.create(null) } -function throwError (e) { - setTimeout(function () { +function throwError(e) { + setTimeout(function() { throw e }, 0) } -EventTarget.prototype.dispatchEvent = function (event) { +EventTarget.prototype.dispatchEvent = function(event) { event.target = this var typeListeners = this._listeners[event.type] if (typeListeners != undefined) { @@ -470,7 +534,7 @@ EventTarget.prototype.dispatchEvent = function (event) { } } } -EventTarget.prototype.addEventListener = function (type, listener) { +EventTarget.prototype.addEventListener = function(type, listener) { type = String(type) var listeners = this._listeners var typeListeners = listeners[type] @@ -488,7 +552,7 @@ EventTarget.prototype.addEventListener = function (type, listener) { typeListeners.push(listener) } } -EventTarget.prototype.removeEventListener = function (type, listener) { +EventTarget.prototype.removeEventListener = function(type, listener) { type = String(type) var listeners = this._listeners var typeListeners = listeners[type] @@ -507,12 +571,12 @@ EventTarget.prototype.removeEventListener = function (type, listener) { } } -function Event (type) { +function Event(type) { this.type = type this.target = undefined } -function MessageEvent (type, options) { +function MessageEvent(type, options) { Event.call(this, type) this.data = options.data this.lastEventId = options.lastEventId @@ -520,7 +584,7 @@ function MessageEvent (type, options) { MessageEvent.prototype = Object.create(Event.prototype) -function ConnectionEvent (type, options) { +function ConnectionEvent(type, options) { Event.call(this, type) this.status = options.status this.statusText = options.statusText @@ -545,18 +609,18 @@ var contentTypeRegExp = /^text\/event\-stream;?(\s*charset\=utf\-8)?$/i var MINIMUM_DURATION = 1000 var MAXIMUM_DURATION = 18000000 -var parseDuration = function (value, def) { +var parseDuration = function(value, def) { var n = parseInt(value, 10) if (n !== n) { n = def } return clampDuration(n) } -var clampDuration = function (n) { +var clampDuration = function(n) { return Math.min(Math.max(n, MINIMUM_DURATION), MAXIMUM_DURATION) } -var fire = function (that, f, event) { +var fire = function(that, f, event) { try { if (typeof f === 'function') { f.call(that, event) @@ -566,7 +630,7 @@ var fire = function (that, f, event) { } } -function EventSourcePolyfill (url, options) { +function EventSourcePolyfill(url, options) { EventTarget.call(this) this.onopen = undefined @@ -582,21 +646,35 @@ function EventSourcePolyfill (url, options) { start(this, url, options) } -var isFetchSupported = fetch != undefined && Response != undefined && 'body' in Response.prototype +var isFetchSupported = + fetch != undefined && Response != undefined && 'body' in Response.prototype -function start (es, url, options) { +function start(es, url, options) { url = String(url) var withCredentials = options != undefined && Boolean(options.withCredentials) var initialRetry = clampDuration(1000) - var heartbeatTimeout = options != undefined && options.heartbeatTimeout != undefined ? parseDuration(options.heartbeatTimeout, 45000) : clampDuration(45000) + var heartbeatTimeout = + options != undefined && options.heartbeatTimeout != undefined + ? parseDuration(options.heartbeatTimeout, 45000) + : clampDuration(45000) var lastEventId = '' var retry = initialRetry var wasActivity = false - var headers = options != undefined && options.headers != undefined ? JSON.parse(JSON.stringify(options.headers)) : undefined - var CurrentTransport = options != undefined && options.Transport != undefined ? options.Transport : XMLHttpRequest - var xhr = isFetchSupported && !(options != undefined && options.Transport != undefined) ? undefined : new XHRWrapper(new CurrentTransport()) + var headers = + options != undefined && options.headers != undefined + ? JSON.parse(JSON.stringify(options.headers)) + : undefined + var CurrentTransport = + options != undefined && options.Transport != undefined + ? options.Transport + : XMLHttpRequest + var xhr = + isFetchSupported && + !(options != undefined && options.Transport != undefined) + ? undefined + : new XHRWrapper(new CurrentTransport()) var transport = xhr == undefined ? new FetchTransport() : new XHRTransport() var cancelFunction = undefined var timeout = 0 @@ -610,10 +688,14 @@ function start (es, url, options) { var fieldStart = 0 var valueStart = 0 - var onStart = function (status, statusText, contentType, headers, cancel) { + var onStart = function(status, statusText, contentType, headers, cancel) { if (currentState === CONNECTING) { cancelFunction = cancel - if (status === 200 && contentType != undefined && contentTypeRegExp.test(contentType)) { + if ( + status === 200 && + contentType != undefined && + contentTypeRegExp.test(contentType) + ) { currentState = OPEN wasActivity = true retry = initialRetry @@ -621,7 +703,7 @@ function start (es, url, options) { var event = new ConnectionEvent('open', { status: status, statusText: statusText, - headers: headers + headers: headers, }) es.dispatchEvent(event) fire(es, es.onopen, event) @@ -631,16 +713,26 @@ function start (es, url, options) { if (statusText) { statusText = statusText.replace(/\s+/g, ' ') } - message = "EventSource's response has a status " + status + ' ' + statusText + ' that is not 200. Aborting the connection.' + message = + "EventSource's response has a status " + + status + + ' ' + + statusText + + ' that is not 200. Aborting the connection.' } else { - message = "EventSource's response has a Content-Type specifying an unsupported type: " + (contentType == undefined ? '-' : contentType.replace(/\s+/g, ' ')) + '. Aborting the connection.' + message = + "EventSource's response has a Content-Type specifying an unsupported type: " + + (contentType == undefined + ? '-' + : contentType.replace(/\s+/g, ' ')) + + '. Aborting the connection.' } throwError(new Error(message)) close() var event = new ConnectionEvent('error', { status: status, statusText: statusText, - headers: headers + headers: headers, }) es.dispatchEvent(event) fire(es, es.onerror, event) @@ -648,7 +740,7 @@ function start (es, url, options) { } } - var onProgress = function (textChunk) { + var onProgress = function(textChunk) { if (currentState === OPEN) { var n = -1 for (var i = 0; i < textChunk.length; i += 1) { @@ -676,7 +768,14 @@ function start (es, url, options) { valueStart = position + 1 } var field = chunk.slice(fieldStart, valueStart - 1) - var value = chunk.slice(valueStart + (valueStart < position && chunk.charCodeAt(valueStart) === ' '.charCodeAt(0) ? 1 : 0), position) + var value = chunk.slice( + valueStart + + (valueStart < position && + chunk.charCodeAt(valueStart) === ' '.charCodeAt(0) + ? 1 + : 0), + position + ) if (field === 'data') { dataBuffer += '\n' dataBuffer += value @@ -691,7 +790,7 @@ function start (es, url, options) { heartbeatTimeout = parseDuration(value, heartbeatTimeout) if (timeout !== 0) { clearTimeout(timeout) - timeout = setTimeout(function () { + timeout = setTimeout(function() { onTimeout() }, heartbeatTimeout) } @@ -705,7 +804,7 @@ function start (es, url, options) { } var event = new MessageEvent(eventTypeBuffer, { data: dataBuffer.slice(1), - lastEventId: lastEventIdBuffer + lastEventId: lastEventIdBuffer, }) es.dispatchEvent(event) if (eventTypeBuffer === 'message') { @@ -738,14 +837,14 @@ function start (es, url, options) { } } - var onFinish = function () { + var onFinish = function() { if (currentState === OPEN || currentState === CONNECTING) { currentState = WAITING if (timeout !== 0) { clearTimeout(timeout) timeout = 0 } - timeout = setTimeout(function () { + timeout = setTimeout(function() { onTimeout() }, retry) retry = clampDuration(Math.min(initialRetry * 16, retry * 2)) @@ -757,7 +856,7 @@ function start (es, url, options) { } } - var close = function () { + var close = function() { currentState = CLOSED if (cancelFunction != undefined) { cancelFunction() @@ -770,17 +869,23 @@ function start (es, url, options) { es.readyState = CLOSED } - var onTimeout = function () { + var onTimeout = function() { timeout = 0 if (currentState !== WAITING) { if (!wasActivity && cancelFunction != undefined) { - throwError(new Error('No activity within ' + heartbeatTimeout + ' milliseconds. Reconnecting.')) + throwError( + new Error( + 'No activity within ' + + heartbeatTimeout + + ' milliseconds. Reconnecting.' + ) + ) cancelFunction() cancelFunction = undefined } else { wasActivity = false - timeout = setTimeout(function () { + timeout = setTimeout(function() { onTimeout() }, heartbeatTimeout) } @@ -788,7 +893,7 @@ function start (es, url, options) { } wasActivity = false - timeout = setTimeout(function () { + timeout = setTimeout(function() { onTimeout() }, heartbeatTimeout) @@ -806,7 +911,10 @@ function start (es, url, options) { var requestURL = url if (url.slice(0, 5) !== 'data:' && url.slice(0, 5) !== 'blob:') { if (lastEventId !== '') { - requestURL += (url.indexOf('?') === -1 ? '?' : '&') + 'lastEventId=' + encodeURIComponent(lastEventId) + requestURL += + (url.indexOf('?') === -1 ? '?' : '&') + + 'lastEventId=' + + encodeURIComponent(lastEventId) } } var requestHeaders = {} @@ -819,7 +927,15 @@ function start (es, url, options) { } } try { - transport.open(xhr, onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders) + transport.open( + xhr, + onStart, + onProgress, + onFinish, + requestURL, + withCredentials, + requestHeaders + ) } catch (error) { close() throw error @@ -838,7 +954,7 @@ EventSourcePolyfill.prototype = Object.create(EventTarget.prototype) EventSourcePolyfill.prototype.CONNECTING = CONNECTING EventSourcePolyfill.prototype.OPEN = OPEN EventSourcePolyfill.prototype.CLOSED = CLOSED -EventSourcePolyfill.prototype.close = function () { +EventSourcePolyfill.prototype.close = function() { this._close() } diff --git a/packages/next/client/head-manager.js b/packages/next/client/head-manager.js index 28fd9cab067cc..48206daa8e86a 100644 --- a/packages/next/client/head-manager.js +++ b/packages/next/client/head-manager.js @@ -10,18 +10,18 @@ export default class HeadManager { this.updatePromise = null } - updateHead = (head) => { - const promise = this.updatePromise = Promise.resolve().then(() => { + updateHead = head => { + const promise = (this.updatePromise = Promise.resolve().then(() => { if (promise !== this.updatePromise) return this.updatePromise = null this.doUpdateHead(head) - }) + })) } doUpdateHead (head) { const tags = {} - head.forEach((h) => { + head.forEach(h => { const components = tags[h.type] || [] components.push(h) tags[h.type] = components @@ -30,7 +30,7 @@ export default class HeadManager { this.updateTitle(tags.title ? tags.title[0] : null) const types = ['meta', 'base', 'link', 'style', 'script'] - types.forEach((type) => { + types.forEach(type => { this.updateElements(type, tags[type] || []) }) } @@ -46,8 +46,10 @@ export default class HeadManager { updateElements (type, components) { const headEl = document.getElementsByTagName('head')[0] - const oldTags = Array.prototype.slice.call(headEl.querySelectorAll(type + '.next-head')) - const newTags = components.map(reactElementToDOM).filter((newTag) => { + const oldTags = Array.prototype.slice.call( + headEl.querySelectorAll(type + '.next-head') + ) + const newTags = components.map(reactElementToDOM).filter(newTag => { for (let i = 0, len = oldTags.length; i < len; i++) { const oldTag = oldTags[i] if (oldTag.isEqualNode(newTag)) { @@ -58,8 +60,8 @@ export default class HeadManager { return true }) - oldTags.forEach((t) => t.parentNode.removeChild(t)) - newTags.forEach((t) => headEl.appendChild(t)) + oldTags.forEach(t => t.parentNode.removeChild(t)) + newTags.forEach(t => headEl.appendChild(t)) } } diff --git a/packages/next/client/index.js b/packages/next/client/index.js index 70e38c6d79aa7..4a02b74e3c72e 100644 --- a/packages/next/client/index.js +++ b/packages/next/client/index.js @@ -73,9 +73,7 @@ let App export const emitter = mitt() -export default async ({ - webpackHMR: passedWebpackHMR -} = {}) => { +export default async ({ webpackHMR: passedWebpackHMR } = {}) => { // This makes sure this specific lines are removed in production if (process.env.NODE_ENV === 'development') { webpackHMR = passedWebpackHMR @@ -90,7 +88,9 @@ export default async ({ if (process.env.NODE_ENV !== 'production') { const { isValidElementType } = require('react-is') if (!isValidElementType(Component)) { - throw new Error(`The default export is not a React Component in page: "${page}"`) + throw new Error( + `The default export is not a React Component in page: "${page}"` + ) } } } catch (error) { @@ -141,9 +141,7 @@ export async function renderError (props) { const { App, err } = props if (process.env.NODE_ENV !== 'production') { - return webpackHMR.reportRuntimeError( - webpackHMR.prepareError(err) - ) + return webpackHMR.reportRuntimeError(webpackHMR.prepareError(err)) } // Make sure we log the error to the console, otherwise users can't track down issues. @@ -156,7 +154,11 @@ export async function renderError (props) { // Otherwise, we need to call `getInitialProps` on `App` before mounting. const initProps = props.props ? props.props - : await loadGetInitialProps(App, { Component: ErrorComponent, router, ctx: { err, pathname: page, query, asPath } }) + : await loadGetInitialProps(App, { + Component: ErrorComponent, + router, + ctx: { err, pathname: page, query, asPath } + }) await doRender({ ...props, err, Component: ErrorComponent, props: initProps }) } @@ -175,11 +177,18 @@ function renderReactElement (reactEl, domEl) { async function doRender ({ App, Component, props, err }) { // Usual getInitialProps fetching is handled in next/router // this is for when ErrorComponent gets replaced by Component by HMR - if (!props && Component && + if ( + !props && + Component && Component !== ErrorComponent && - lastAppProps.Component === ErrorComponent) { + lastAppProps.Component === ErrorComponent + ) { const { pathname, query, asPath } = router - props = await loadGetInitialProps(App, { Component, router, ctx: { err, pathname, query, asPath } }) + props = await loadGetInitialProps(App, { + Component, + router, + ctx: { err, pathname, query, asPath } + }) } Component = Component || lastAppProps.Component @@ -189,11 +198,15 @@ async function doRender ({ App, Component, props, err }) { // lastAppProps has to be set before ReactDom.render to account for ReactDom throwing an error. lastAppProps = appProps - emitter.emit('before-reactdom-render', { Component, ErrorComponent, appProps }) + emitter.emit('before-reactdom-render', { + Component, + ErrorComponent, + appProps + }) // In development runtime errors are caught by react-error-overlay. if (process.env.NODE_ENV === 'development') { - renderReactElement(( + renderReactElement( <Suspense fallback={<div>Loading...</div>}> <RouterContext.Provider value={makePublicRouterInstance(router)}> <DataManagerContext.Provider value={dataManager}> @@ -202,12 +215,19 @@ async function doRender ({ App, Component, props, err }) { </HeadManagerContext.Provider> </DataManagerContext.Provider> </RouterContext.Provider> - </Suspense> - ), appContainer) + </Suspense>, + appContainer + ) } else { // In production we catch runtime errors using componentDidCatch which will trigger renderError. - renderReactElement(( - <ErrorBoundary fn={(error) => renderError({ App, err: error }).catch(err => console.error('Error rendering page: ', err))}> + renderReactElement( + <ErrorBoundary + fn={error => + renderError({ App, err: error }).catch(err => + console.error('Error rendering page: ', err) + ) + } + > <Suspense fallback={<div>Loading...</div>}> <RouterContext.Provider value={makePublicRouterInstance(router)}> <DataManagerContext.Provider value={dataManager}> @@ -217,8 +237,9 @@ async function doRender ({ App, Component, props, err }) { </DataManagerContext.Provider> </RouterContext.Provider> </Suspense> - </ErrorBoundary> - ), appContainer) + </ErrorBoundary>, + appContainer + ) } emitter.emit('after-reactdom-render', { Component, ErrorComponent, appProps }) diff --git a/packages/next/client/next-dev.js b/packages/next/client/next-dev.js index d7bdc9137a5dd..71dce3ba39a44 100644 --- a/packages/next/client/next-dev.js +++ b/packages/next/client/next-dev.js @@ -16,9 +16,7 @@ if (!window.EventSource) { } const { - __NEXT_DATA__: { - assetPrefix - } + __NEXT_DATA__: { assetPrefix } } = window const prefix = assetPrefix || '' @@ -26,7 +24,7 @@ const webpackHMR = initWebpackHMR({ assetPrefix: prefix }) window.next = next initNext({ webpackHMR }) - .then((emitter) => { + .then(emitter => { initOnDemandEntries({ assetPrefix: prefix }) initializeBuildWatcher() @@ -51,6 +49,7 @@ initNext({ webpackHMR }) lastScroll = null } }) - }).catch((err) => { + }) + .catch(err => { console.error('Error was not caught', err) }) diff --git a/packages/next/client/next.js b/packages/next/client/next.js index bd2dfc79e14fb..99c698d9bb14a 100644 --- a/packages/next/client/next.js +++ b/packages/next/client/next.js @@ -2,7 +2,6 @@ import initNext, * as next from './' window.next = next -initNext() - .catch((err) => { - console.error(`${err.message}\n${err.stack}`) - }) +initNext().catch(err => { + console.error(`${err.message}\n${err.stack}`) +}) diff --git a/packages/next/client/page-loader.js b/packages/next/client/page-loader.js index 3abc17e513536..ab81d9343bf75 100644 --- a/packages/next/client/page-loader.js +++ b/packages/next/client/page-loader.js @@ -114,7 +114,9 @@ export default class PageLoader { const scriptRoute = route === '/' ? '/index.js' : `${route}.js` const script = document.createElement('script') - const url = `${this.assetPrefix}/_next/static/${encodeURIComponent(this.buildId)}/pages${scriptRoute}` + const url = `${this.assetPrefix}/_next/static/${encodeURIComponent( + this.buildId + )}/pages${scriptRoute}` script.crossOrigin = process.crossOrigin script.src = url script.onerror = () => { @@ -143,9 +145,11 @@ export default class PageLoader { // Wait for webpack to become idle if it's not. // More info: https://github.com/zeit/next.js/pull/1511 if (module.hot && module.hot.status() !== 'idle') { - console.log(`Waiting for webpack to become "idle" to initialize the page: "${route}"`) + console.log( + `Waiting for webpack to become "idle" to initialize the page: "${route}"` + ) - const check = (status) => { + const check = status => { if (status === 'idle') { module.hot.removeStatusHandler(check) register() @@ -170,7 +174,10 @@ export default class PageLoader { // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE // Don't prefetch if the user is on 2G / Don't prefetch if Save-Data is enabled if ('connection' in navigator) { - if ((navigator.connection.effectiveType || '').indexOf('2g') !== -1 || navigator.connection.saveData) { + if ( + (navigator.connection.effectiveType || '').indexOf('2g') !== -1 || + navigator.connection.saveData + ) { return } } @@ -184,7 +191,9 @@ export default class PageLoader { const link = document.createElement('link') link.rel = 'preload' link.crossOrigin = process.crossOrigin - link.href = `${this.assetPrefix}/_next/static/${encodeURIComponent(this.buildId)}/pages${scriptRoute}` + link.href = `${this.assetPrefix}/_next/static/${encodeURIComponent( + this.buildId + )}/pages${scriptRoute}` link.as = 'script' document.head.appendChild(link) return @@ -193,7 +202,7 @@ export default class PageLoader { if (document.readyState === 'complete') { return this.loadPage(route).catch(() => {}) } else { - return new Promise((resolve) => { + return new Promise(resolve => { window.addEventListener('load', () => { this.loadPage(route).then(() => resolve(), () => resolve()) }) diff --git a/packages/next/client/router.ts b/packages/next/client/router.ts index f4186dd9a56d1..c25600c9ab785 100644 --- a/packages/next/client/router.ts +++ b/packages/next/client/router.ts @@ -4,21 +4,25 @@ import Router, { BaseRouter } from 'next-server/dist/lib/router/router' import { RouterContext } from 'next-server/dist/lib/router-context' import { RequestContext } from 'next-server/dist/lib/request-context' -type ClassArguments<T> = T extends new(...args: infer U) => any ? U : any +type ClassArguments<T> = T extends new (...args: infer U) => any ? U : any type RouterArgs = ClassArguments<typeof Router> type SingletonRouterBase = { router: Router | null readyCallbacks: Array<() => any> - ready(cb: () => any): void, + ready(cb: () => any): void } export { Router } -export type PublicRouterInstance = BaseRouter & Pick<Router, | 'push' | 'replace' | 'reload' | 'back' | 'prefetch' | 'beforePopState'> & { - events: typeof Router['events'], -} +export type PublicRouterInstance = BaseRouter & + Pick< + Router, + 'push' | 'replace' | 'reload' | 'back' | 'prefetch' | 'beforePopState' + > & { + events: typeof Router['events'] + } export type SingletonRouter = SingletonRouterBase & PublicRouterInstance @@ -36,8 +40,22 @@ const singletonRouter: SingletonRouterBase = { // Create public properties and methods of the router in the singletonRouter const urlPropertyFields = ['pathname', 'route', 'query', 'asPath'] const propertyFields = ['components'] -const routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete'] -const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState'] +const routerEvents = [ + 'routeChangeStart', + 'beforeHistoryChange', + 'routeChangeComplete', + 'routeChangeError', + 'hashChangeStart', + 'hashChangeComplete', +] +const coreMethodFields = [ + 'push', + 'replace', + 'reload', + 'back', + 'prefetch', + 'beforePopState', +] // Events is a static property on the router, the router doesn't have to be initialized to use it Object.defineProperty(singletonRouter, 'events', { @@ -46,7 +64,7 @@ Object.defineProperty(singletonRouter, 'events', { }, }) -propertyFields.concat(urlPropertyFields).forEach((field) => { +propertyFields.concat(urlPropertyFields).forEach(field => { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -59,18 +77,20 @@ propertyFields.concat(urlPropertyFields).forEach((field) => { }) }) -coreMethodFields.forEach((field) => { +coreMethodFields.forEach(field => { // We don't really know the types here, so we add them later instead - (singletonRouter as any)[field] = (...args: any[]) => { + ;(singletonRouter as any)[field] = (...args: any[]) => { const router = getRouter() as any return router[field](...args) } }) -routerEvents.forEach((event) => { +routerEvents.forEach(event => { singletonRouter.ready(() => { Router.events.on(event, (...args) => { - const eventField = `on${event.charAt(0).toUpperCase()}${event.substring(1)}` + const eventField = `on${event.charAt(0).toUpperCase()}${event.substring( + 1 + )}` const _singletonRouter = singletonRouter as any if (_singletonRouter[eventField]) { try { @@ -88,7 +108,8 @@ routerEvents.forEach((event) => { function getRouter() { if (!singletonRouter.router) { - const message = 'No router instance found.\n' + + const message = + 'No router instance found.\n' + 'You should only use "next/router" inside the client side of your app.\n' throw new Error(message) } @@ -118,7 +139,7 @@ export function useRequest() { // This should **not** use inside the server. export const createRouter = (...args: RouterArgs) => { singletonRouter.router = new Router(...args) - singletonRouter.readyCallbacks.forEach((cb) => cb()) + singletonRouter.readyCallbacks.forEach(cb => cb()) singletonRouter.readyCallbacks = [] return singletonRouter.router @@ -141,7 +162,7 @@ export function makePublicRouterInstance(router: Router): PublicRouterInstance { // Events is a static property on the router, the router doesn't have to be initialized to use it instance.events = Router.events - propertyFields.forEach((field) => { + propertyFields.forEach(field => { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -153,7 +174,7 @@ export function makePublicRouterInstance(router: Router): PublicRouterInstance { }) }) - coreMethodFields.forEach((field) => { + coreMethodFields.forEach(field => { instance[field] = (...args: any[]) => { return _router[field](...args) } diff --git a/packages/next/client/source-map-support.ts b/packages/next/client/source-map-support.ts index 6a7120b264ec6..0d3b62d535621 100644 --- a/packages/next/client/source-map-support.ts +++ b/packages/next/client/source-map-support.ts @@ -20,7 +20,9 @@ function rewriteTraceLine(trace: string, distDir: string) { return trace } const filename = m[1] - const filenameLink = filename.replace(distDir, '/_next/development').replace(/\\/g, '/') + const filenameLink = filename + .replace(distDir, '/_next/development') + .replace(/\\/g, '/') trace = trace.replace(filename, filenameLink) return trace } diff --git a/packages/next/client/webpack-hot-middleware-client.js b/packages/next/client/webpack-hot-middleware-client.js index 560ddb9621e48..97c7aec094347 100644 --- a/packages/next/client/webpack-hot-middleware-client.js +++ b/packages/next/client/webpack-hot-middleware-client.js @@ -7,7 +7,7 @@ export default ({ assetPrefix }) => { const devClient = connect(options) - devClient.subscribeToHmrEvent((obj) => { + devClient.subscribeToHmrEvent(obj => { if (obj.action === 'reloadPage') { return window.location.reload() } @@ -20,7 +20,10 @@ export default ({ assetPrefix }) => { } if (obj.action === 'addedPage') { const [page] = obj.data - if (page === window.next.router.pathname && typeof window.next.router.components[page] === 'undefined') { + if ( + page === window.next.router.pathname && + typeof window.next.router.components[page] === 'undefined' + ) { return window.location.reload() } return diff --git a/packages/next/config.d.ts b/packages/next/config.d.ts index 16989ba357190..c4cb753c2b1aa 100644 --- a/packages/next/config.d.ts +++ b/packages/next/config.d.ts @@ -1,2 +1,2 @@ export * from 'next-server/config' -export {default} from 'next-server/config' +export { default } from 'next-server/config' diff --git a/packages/next/constants.d.ts b/packages/next/constants.d.ts index e0100a4ae07ba..df2166f2aae99 100644 --- a/packages/next/constants.d.ts +++ b/packages/next/constants.d.ts @@ -1,2 +1,2 @@ export * from 'next-server/constants' -export {default} from 'next-server/constants' +export { default } from 'next-server/constants' diff --git a/packages/next/data.d.ts b/packages/next/data.d.ts index 99d8443366838..6d59eb9b88992 100644 --- a/packages/next/data.d.ts +++ b/packages/next/data.d.ts @@ -1,2 +1,2 @@ export * from './dist/lib/data' -export {default} from './dist/lib/data' +export { default } from './dist/lib/data' diff --git a/packages/next/document.d.ts b/packages/next/document.d.ts index f7e4981195085..97ea219dec9ec 100644 --- a/packages/next/document.d.ts +++ b/packages/next/document.d.ts @@ -1,2 +1,2 @@ export * from './dist/pages/_document' -export {default} from './dist/pages/_document' +export { default } from './dist/pages/_document' diff --git a/packages/next/dynamic.d.ts b/packages/next/dynamic.d.ts index fa446d3d1cb5a..88c45a9152170 100644 --- a/packages/next/dynamic.d.ts +++ b/packages/next/dynamic.d.ts @@ -1,2 +1,2 @@ export * from 'next-server/dynamic' -export {default} from 'next-server/dynamic' +export { default } from 'next-server/dynamic' diff --git a/packages/next/error.d.ts b/packages/next/error.d.ts index fb09a87f506de..0ea4c4f391999 100644 --- a/packages/next/error.d.ts +++ b/packages/next/error.d.ts @@ -1,2 +1,2 @@ export * from './dist/pages/_error' -export {default} from './dist/pages/_error' +export { default } from './dist/pages/_error' diff --git a/packages/next/export/index.d.ts b/packages/next/export/index.d.ts index 9d7c50210c8fd..df123866a2218 100644 --- a/packages/next/export/index.d.ts +++ b/packages/next/export/index.d.ts @@ -1 +1,5 @@ -export default function(dir: string, options: any, configuration?: any): Promise<void> +export default function( + dir: string, + options: any, + configuration?: any +): Promise<void> diff --git a/packages/next/export/index.js b/packages/next/export/index.js index e797b82742436..91447506cb518 100644 --- a/packages/next/export/index.js +++ b/packages/next/export/index.js @@ -5,7 +5,15 @@ import mkdirpModule from 'mkdirp' import { resolve, join } from 'path' import { existsSync, readFileSync } from 'fs' import loadConfig from 'next-server/next-config' -import { PHASE_EXPORT, SERVER_DIRECTORY, PAGES_MANIFEST, CONFIG_FILE, BUILD_ID_FILE, CLIENT_PUBLIC_FILES_PATH, CLIENT_STATIC_FILES_PATH } from 'next-server/constants' +import { + PHASE_EXPORT, + SERVER_DIRECTORY, + PAGES_MANIFEST, + CONFIG_FILE, + BUILD_ID_FILE, + CLIENT_PUBLIC_FILES_PATH, + CLIENT_STATIC_FILES_PATH +} from 'next-server/constants' import createProgress from 'tty-aware-progress' import { promisify } from 'util' import { recursiveDelete } from '../lib/recursive-delete' @@ -26,16 +34,23 @@ export default async function (dir, options, configuration) { const distDir = join(dir, nextConfig.distDir) const subFolders = nextConfig.experimental.exportTrailingSlash - if (!options.buildExport && nextConfig.target !== 'server') throw new Error('Cannot export when target is not server. https://err.sh/zeit/next.js/next-export-serverless') + if (!options.buildExport && nextConfig.target !== 'server') { + throw new Error( + 'Cannot export when target is not server. https://err.sh/zeit/next.js/next-export-serverless' + ) + } log(`> using build directory: ${distDir}`) if (!existsSync(distDir)) { - throw new Error(`Build directory ${distDir} does not exist. Make sure you run "next build" before running "next start" or "next export".`) + throw new Error( + `Build directory ${distDir} does not exist. Make sure you run "next build" before running "next start" or "next export".` + ) } const buildId = readFileSync(join(distDir, BUILD_ID_FILE), 'utf8') - const pagesManifest = !options.pages && require(join(distDir, SERVER_DIRECTORY, PAGES_MANIFEST)) + const pagesManifest = + !options.pages && require(join(distDir, SERVER_DIRECTORY, PAGES_MANIFEST)) const pages = options.pages || Object.keys(pagesManifest) const defaultPathMap = {} @@ -58,11 +73,7 @@ export default async function (dir, options, configuration) { // Copy static directory if (existsSync(join(dir, 'static'))) { log(' copying "static" directory') - await cp( - join(dir, 'static'), - join(outDir, 'static'), - { expand: true } - ) + await cp(join(dir, 'static'), join(outDir, 'static'), { expand: true }) } // Copy .next/static directory @@ -76,8 +87,10 @@ export default async function (dir, options, configuration) { // Get the exportPathMap from the config file if (typeof nextConfig.exportPathMap !== 'function') { - console.log(`> No "exportPathMap" found in "${CONFIG_FILE}". Generating map from "./pages"`) - nextConfig.exportPathMap = async (defaultMap) => { + console.log( + `> No "exportPathMap" found in "${CONFIG_FILE}". Generating map from "./pages"` + ) + nextConfig.exportPathMap = async defaultMap => { return defaultMap } } @@ -106,8 +119,16 @@ export default async function (dir, options, configuration) { nextExport: true } - log(` launching ${threads} threads with concurrency of ${concurrency} per thread`) - const exportPathMap = await nextConfig.exportPathMap(defaultPathMap, { dev: false, dir, outDir, distDir, buildId }) + log( + ` launching ${threads} threads with concurrency of ${concurrency} per thread` + ) + const exportPathMap = await nextConfig.exportPathMap(defaultPathMap, { + dev: false, + dir, + outDir, + distDir, + buildId + }) exportPathMap['/404.html'] = exportPathMap['/404.html'] || { page: '/_error' } const exportPaths = Object.keys(exportPathMap) @@ -130,17 +151,13 @@ export default async function (dir, options, configuration) { // Copy public directory if (existsSync(publicDir)) { log(' copying "public" directory') - await cp( - publicDir, - outDir, - { - expand: true, - filter (path) { - // Exclude paths used by pages - return !exportPathMap['/' + path] - } + await cp(publicDir, outDir, { + expand: true, + filter (path) { + // Exclude paths used by pages + return !exportPathMap['/' + path] } - ) + }) } const workers = new Set() @@ -173,7 +190,8 @@ export default async function (dir, options, configuration) { resolve() } else if (type === 'amp-validation') { ampValidations[payload.page] = payload.result - hadValidationError = hadValidationError || payload.result.errors.length + hadValidationError = + hadValidationError || payload.result.errors.length } }) }) @@ -186,7 +204,9 @@ export default async function (dir, options, configuration) { console.log(formatAmpMessages(ampValidations)) } if (hadValidationError) { - throw new Error(`AMP Validation caused the export to fail. https://err.sh/zeit/next.js/amp-export-validation`) + throw new Error( + `AMP Validation caused the export to fail. https://err.sh/zeit/next.js/amp-export-validation` + ) } // Add an empty line to the console for the better readability. diff --git a/packages/next/head.d.ts b/packages/next/head.d.ts index 8b9f82fc37696..27cf7da261a64 100644 --- a/packages/next/head.d.ts +++ b/packages/next/head.d.ts @@ -1,2 +1,2 @@ export * from 'next-server/head' -export {default} from 'next-server/head' +export { default } from 'next-server/head' diff --git a/packages/next/lib/constants.ts b/packages/next/lib/constants.ts index 57caa76bd0a2a..e28385c627065 100644 --- a/packages/next/lib/constants.ts +++ b/packages/next/lib/constants.ts @@ -1,10 +1,19 @@ import { join } from 'path' 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 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') +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' +) // Because on Windows absolute paths in the generated code can break because of numbers, eg 1 in the path, // we have to use a private alias diff --git a/packages/next/lib/data.ts b/packages/next/lib/data.ts index 458d891a8629b..5add3369fdc13 100644 --- a/packages/next/lib/data.ts +++ b/packages/next/lib/data.ts @@ -1,10 +1,10 @@ -import {useContext} from 'react' +import { useContext } from 'react' import { DataManagerContext } from 'next-server/dist/lib/data-manager-context' import { RouterContext } from 'next-server/dist/lib/router-context' import fetch from 'unfetch' -import {stringify} from 'querystring' +import { stringify } from 'querystring' -type Args = string|number|Array<string|number> +type Args = string | number | Array<string | number> function generateArgsKey(args: Args[]) { return args.reduce((a: string, b: Args): string => { @@ -18,13 +18,20 @@ function generateArgsKey(args: Args[]) { }, '') } -export function createHook(fetcher: (...args: Args[]) => Promise<any>, options: {key: string}) { +export function createHook( + fetcher: (...args: Args[]) => Promise<any>, + options: { key: string } +) { if (!options.key) { throw new Error('key not provided to createHook options.') } - return function useData(...args: Array<string|number>) { - const router: import('next-server/lib/router/router').default = useContext(RouterContext) - const dataManager: import('next-server/lib/data-manager').DataManager = useContext(DataManagerContext) + return function useData(...args: Array<string | number>) { + const router: import('next-server/lib/router/router').default = useContext( + RouterContext + ) + const dataManager: import('next-server/lib/data-manager').DataManager = useContext( + DataManagerContext + ) const key = `${options.key}${generateArgsKey(args)}` const existing = dataManager.get(key) @@ -33,7 +40,9 @@ export function createHook(fetcher: (...args: Args[]) => Promise<any>, options: return existing.result } if (existing === 'mismatched-key') { - throw new Error('matching key was missing from returned data. make sure arguments match between the client and server') + throw new Error( + 'matching key was missing from returned data. make sure arguments match between the client and server' + ) } } @@ -43,16 +52,18 @@ export function createHook(fetcher: (...args: Args[]) => Promise<any>, options: headers: { accept: 'application/amp.bind+json', }, - }).then((res: any) => res.json()).then((result: any) => { - const hasKey = result.some((pair: [string, any]) => pair[0] === key) - if (!hasKey) { - result = [[key, 'mismatched-key']] - } - dataManager.overwrite(result) }) + .then((res: any) => res.json()) + .then((result: any) => { + const hasKey = result.some((pair: [string, any]) => pair[0] === key) + if (!hasKey) { + result = [[key, 'mismatched-key']] + } + dataManager.overwrite(result) + }) throw res } else { - const res = fetcher(...args).then((result) => { + const res = fetcher(...args).then(result => { dataManager.set(key, { status: 'resolved', result, diff --git a/packages/next/lib/pretty-bytes.ts b/packages/next/lib/pretty-bytes.ts index 85aa11f17058f..c34a90c40caf3 100644 --- a/packages/next/lib/pretty-bytes.ts +++ b/packages/next/lib/pretty-bytes.ts @@ -10,17 +10,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const UNITS = [ - 'B', - 'kB', - 'MB', - 'GB', - 'TB', - 'PB', - 'EB', - 'ZB', - 'YB', -]; +const UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] /* Formats the given number using `Number#toLocaleString`. @@ -29,45 +19,50 @@ Formats the given number using `Number#toLocaleString`. - If no value for locale is specified, the number is returned unmodified. */ const toLocaleString = (number: number, locale: any) => { - let result: any = number; + let result: any = number if (typeof locale === 'string') { - result = number.toLocaleString(locale); + result = number.toLocaleString(locale) } else if (locale === true) { - result = number.toLocaleString(); + result = number.toLocaleString() } - return result; -}; + return result +} export default function prettyBytes(number: number, options?: any): string { if (!Number.isFinite(number)) { - throw new TypeError(`Expected a finite number, got ${typeof number}: ${number}`); + throw new TypeError( + `Expected a finite number, got ${typeof number}: ${number}` + ) } - options = Object.assign({}, options); + options = Object.assign({}, options) if (options.signed && number === 0) { - return ' 0 B'; + return ' 0 B' } - const isNegative = number < 0; - const prefix = isNegative ? '-' : (options.signed ? '+' : ''); + const isNegative = number < 0 + const prefix = isNegative ? '-' : options.signed ? '+' : '' if (isNegative) { - number = -number; + number = -number } if (number < 1) { - const numberString = toLocaleString(number, options.locale); - return prefix + numberString + ' B'; + const numberString = toLocaleString(number, options.locale) + return prefix + numberString + ' B' } - const exponent = Math.min(Math.floor(Math.log10(number) / 3), UNITS.length - 1); + const exponent = Math.min( + Math.floor(Math.log10(number) / 3), + UNITS.length - 1 + ) - number = Number((number / Math.pow(1000, exponent)).toPrecision(3)); - const numberString = toLocaleString(number, options.locale); + number = Number((number / Math.pow(1000, exponent)).toPrecision(3)) + const numberString = toLocaleString(number, options.locale) - const unit = UNITS[exponent]; + const unit = UNITS[exponent] - return prefix + numberString + ' ' + unit; -}; + return prefix + numberString + ' ' + unit +} diff --git a/packages/next/lib/recursive-delete.ts b/packages/next/lib/recursive-delete.ts index bda70e061365b..01a5a2d68aee3 100644 --- a/packages/next/lib/recursive-delete.ts +++ b/packages/next/lib/recursive-delete.ts @@ -43,7 +43,7 @@ export async function recursiveDelete( dir: string, filter?: RegExp, previousPath: string = '', - ensure?: boolean, + ensure?: boolean ): Promise<void> { let result try { @@ -58,7 +58,7 @@ export async function recursiveDelete( await Promise.all( result.map(async (part: string) => { const absolutePath = join(dir, part) - const pathStat = await stat(absolutePath).catch((e) => { + const pathStat = await stat(absolutePath).catch(e => { if (e.code !== 'ENOENT') throw e }) if (!pathStat) { @@ -78,6 +78,6 @@ export async function recursiveDelete( if (!filter || filter.test(join(previousPath, part))) { return unlinkFile(absolutePath) } - }), + }) ) } diff --git a/packages/next/lib/recursive-readdir.ts b/packages/next/lib/recursive-readdir.ts index c84b6fb463096..497dc81f42ee0 100644 --- a/packages/next/lib/recursive-readdir.ts +++ b/packages/next/lib/recursive-readdir.ts @@ -13,26 +13,34 @@ const stat = promisify(fs.stat) * @param {string=dir`} rootDir Used to replace the initial path, only the relative path is left, it's faster than path.relative. * @returns Promise array holding all relative paths */ -export async function recursiveReadDir(dir: string, filter: RegExp, ignore?: RegExp, arr: string[] = [], rootDir: string = dir): Promise<string[]> { +export async function recursiveReadDir( + dir: string, + filter: RegExp, + ignore?: RegExp, + arr: string[] = [], + rootDir: string = dir +): Promise<string[]> { const result = await readdir(dir) - await Promise.all(result.map(async (part: string) => { - const absolutePath = join(dir, part) - if (ignore && ignore.test(part)) return + await Promise.all( + result.map(async (part: string) => { + const absolutePath = join(dir, part) + if (ignore && ignore.test(part)) return - const pathStat = await stat(absolutePath) + const pathStat = await stat(absolutePath) - if (pathStat.isDirectory()) { - await recursiveReadDir(absolutePath, filter, ignore, arr, rootDir) - return - } + if (pathStat.isDirectory()) { + await recursiveReadDir(absolutePath, filter, ignore, arr, rootDir) + return + } - if (!filter.test(part)) { - return - } + if (!filter.test(part)) { + return + } - arr.push(absolutePath.replace(rootDir, '')) - })) + arr.push(absolutePath.replace(rootDir, '')) + }) + ) return arr } diff --git a/packages/next/lib/verifyTypeScriptSetup.ts b/packages/next/lib/verifyTypeScriptSetup.ts index 988a314150201..cc0b32de17aaa 100644 --- a/packages/next/lib/verifyTypeScriptSetup.ts +++ b/packages/next/lib/verifyTypeScriptSetup.ts @@ -21,7 +21,7 @@ const resolveP = (req: string, opts: any): Promise<string> => { function writeJson(fileName: string, object: object): Promise<void> { return writeFile( fileName, - JSON.stringify(object, null, 2).replace(/\n/g, os.EOL) + os.EOL, + JSON.stringify(object, null, 2).replace(/\n/g, os.EOL) + os.EOL ) } @@ -29,16 +29,16 @@ async function verifyNoTypeScript(dir: string) { const typescriptFiles = await recursiveReadDir( dir, /.*\.(ts|tsx)$/, - /(node_modules|.*\.d\.ts)/, + /(node_modules|.*\.d\.ts)/ ) if (typescriptFiles.length > 0) { console.warn( chalk.yellow( `We detected TypeScript in your project (${chalk.bold( - `.${typescriptFiles[0]}`, - )}) and created a ${chalk.bold('tsconfig.json')} file for you.`, - ), + `.${typescriptFiles[0]}` + )}) and created a ${chalk.bold('tsconfig.json')} file for you.` + ) ) console.warn() return false @@ -80,9 +80,9 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> { console.error( chalk.bold.red( `It looks like you're trying to use TypeScript but do not have ${chalk.bold( - toInstallStr, - )} installed.`, - ), + toInstallStr + )} installed.` + ) ) console.error( chalk.bold( @@ -92,16 +92,16 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> { chalk.cyan.bold( (isYarn ? 'yarn add --dev' : 'npm install --save-dev') + ' ' + - toInstallStr, - ) + '.', - ), + toInstallStr + ) + '.' + ) ) console.error( chalk.bold( 'If you are not trying to use TypeScript, please remove the ' + chalk.cyan('tsconfig.json') + - ' file from your package root (and any TypeScript files).', - ), + ' file from your package root (and any TypeScript files).' + ) ) console.error() process.exit(1) @@ -160,7 +160,7 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> { try { const { config: readTsConfig, error } = ts.readConfigFile( tsConfigPath, - ts.sys.readFile, + ts.sys.readFile ) if (error) { @@ -176,12 +176,12 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> { const result = ts.parseJsonConfigFileContent( parsedTsConfig, ts.sys, - path.dirname(tsConfigPath), + path.dirname(tsConfigPath) ) if (result.errors && result.errors.length) { throw new Error( - ts.formatDiagnostic(result.errors[0], formatDiagnosticHost), + ts.formatDiagnostic(result.errors[0], formatDiagnosticHost) ) } @@ -192,8 +192,8 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> { chalk.red.bold( 'Could not parse', chalk.cyan('tsconfig.json') + '.', - 'Please make sure it contains syntactically correct JSON.', - ), + 'Please make sure it contains syntactically correct JSON.' + ) ) } @@ -218,17 +218,17 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> { appTsConfig.compilerOptions[option] = suggested messages.push( `${coloredOption} to be ${chalk.bold( - 'suggested', - )} value: ${chalk.cyan.bold(suggested)} (this can be changed)`, + 'suggested' + )} value: ${chalk.cyan.bold(suggested)} (this can be changed)` ) } } else if (parsedCompilerOptions[option] !== valueToCheck) { appTsConfig.compilerOptions[option] = value messages.push( `${coloredOption} ${chalk.bold( - valueToCheck == null ? 'must not' : 'must', + valueToCheck == null ? 'must not' : 'must' )} be ${valueToCheck == null ? 'set' : chalk.cyan.bold(value)}` + - (reason != null ? ` (${reason})` : ''), + (reason != null ? ` (${reason})` : '') ) } } @@ -248,8 +248,8 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> { chalk.bold( 'Your', chalk.cyan('tsconfig.json'), - 'has been populated with default values.', - ), + 'has been populated with default values.' + ) ) console.info() } else { @@ -257,10 +257,10 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> { chalk.bold( 'The following changes are being made to your', chalk.cyan('tsconfig.json'), - 'file:', - ), + 'file:' + ) ) - messages.forEach((message) => { + messages.forEach(message => { console.warn(' - ' + message) }) console.warn() @@ -277,8 +277,8 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> { toInstall.length === 1 ? 'it' : 'them' } with ${ isYarn ? 'yarn add --dev' : 'npm install --save-dev' - } ${toInstall.join(' ')}\n`, - ), + } ${toInstall.join(' ')}\n` + ) ) } } diff --git a/packages/next/link.d.ts b/packages/next/link.d.ts index 4a80d644db997..ea90a38b839c8 100644 --- a/packages/next/link.d.ts +++ b/packages/next/link.d.ts @@ -1,2 +1,2 @@ export * from './dist/client/link' -export {default} from './dist/client/link' +export { default } from './dist/client/link' diff --git a/packages/next/router.d.ts b/packages/next/router.d.ts index c0062ac69dd07..afad55a90add6 100644 --- a/packages/next/router.d.ts +++ b/packages/next/router.d.ts @@ -1,2 +1,2 @@ export * from './dist/client/router' -export {default} from './dist/client/router' +export { default } from './dist/client/router' diff --git a/packages/next/server/error-debug.js b/packages/next/server/error-debug.js index 1bf9194793268..ba09a7877d819 100644 --- a/packages/next/server/error-debug.js +++ b/packages/next/server/error-debug.js @@ -16,12 +16,8 @@ export default function ErrorDebug ({ error, info }) { const StackTrace = ({ error: { name, message, stack }, info }) => ( <div> <div style={styles.heading}>{message || name}</div> - <pre style={styles.stack}> - {stack} - </pre> - {info && <pre style={styles.stack}> - {info.componentStack} - </pre>} + <pre style={styles.stack}>{stack}</pre> + {info && <pre style={styles.stack}>{info.componentStack}</pre>} </div> ) @@ -41,7 +37,8 @@ export const styles = { }, stack: { - fontFamily: '"SF Mono", "Roboto Mono", "Fira Mono", consolas, menlo-regular, monospace', + fontFamily: + '"SF Mono", "Roboto Mono", "Fira Mono", consolas, menlo-regular, monospace', fontSize: '13px', lineHeight: '18px', color: '#777', @@ -52,7 +49,8 @@ export const styles = { }, heading: { - fontFamily: '-apple-system, system-ui, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif', + fontFamily: + '-apple-system, system-ui, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif', fontSize: '20px', fontWeight: '400', lineHeight: '28px', diff --git a/packages/next/server/hot-reloader.js b/packages/next/server/hot-reloader.js index 0b8af1fa04979..8f674a008634d 100644 --- a/packages/next/server/hot-reloader.js +++ b/packages/next/server/hot-reloader.js @@ -5,7 +5,12 @@ import errorOverlayMiddleware from './lib/error-overlay-middleware' import onDemandEntryHandler, { normalizePage } from './on-demand-entry-handler' import webpack from 'webpack' import getBaseWebpackConfig from '../build/webpack-config' -import { IS_BUNDLED_PAGE_REGEX, ROUTE_NAME_REGEX, BLOCKED_PAGES, CLIENT_STATIC_FILES_RUNTIME_AMP } from 'next-server/constants' +import { + IS_BUNDLED_PAGE_REGEX, + ROUTE_NAME_REGEX, + BLOCKED_PAGES, + CLIENT_STATIC_FILES_RUNTIME_AMP +} from 'next-server/constants' import { NEXT_PROJECT_ROOT_DIST_CLIENT } from '../lib/constants' import { route } from 'next-server/dist/server/router' import { createPagesMapping, createEntrypoints } from '../build/entries' @@ -23,7 +28,10 @@ const fileExists = promisify(fs.exists) export async function renderScriptError (res, error) { // Asks CDNs and others to not to cache the errored page - 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' + ) if (error.code === 'ENOENT' || error.message === 'INVALID_BUILD_ID') { res.statusCode = 404 @@ -45,7 +53,10 @@ function addCorsSupport (req, res) { res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET') // Based on https://github.com/primus/access-control/blob/4cf1bc0e54b086c91e6aa44fb14966fa5ef7549c/index.js#L158 if (req.headers['access-control-request-headers']) { - res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers']) + res.setHeader( + 'Access-Control-Allow-Headers', + req.headers['access-control-request-headers'] + ) } if (req.method === 'OPTIONS') { @@ -57,7 +68,9 @@ function addCorsSupport (req, res) { return { preflight: false } } -const matchNextPageBundleRequest = route('/_next/static/:buildId/pages/:path*.js(.map)?') +const matchNextPageBundleRequest = route( + '/_next/static/:buildId/pages/:path*.js(.map)?' +) // Recursively look up the issuer till it ends up at the root function findEntryModule (issuer) { @@ -68,7 +81,7 @@ function findEntryModule (issuer) { return issuer } -function erroredPages (compilation, options = { enhanceName: (name) => name }) { +function erroredPages (compilation, options = { enhanceName: name => name }) { const failedPages = {} for (const error of compilation.errors) { if (!error.origin) { @@ -149,7 +162,8 @@ export default class HotReloader { const bundlePath = join( this.dir, this.config.distDir, - 'static/development/pages', page + '.js' + 'static/development/pages', + page + '.js' ) // make sure to 404 for AMP bundles in case they weren't removed @@ -177,7 +191,7 @@ export default class HotReloader { for (const fn of this.middlewares) { await new Promise((resolve, reject) => { - fn(req, res, (err) => { + fn(req, res, err => { if (err) return reject(err) resolve() }) @@ -198,15 +212,38 @@ export default class HotReloader { findPageFile(pagesDir, '/_document', this.config.pageExtensions) ]) - const pages = createPagesMapping(pagePaths.filter(i => i !== null), this.config.pageExtensions) - const entrypoints = createEntrypoints(pages, 'server', this.buildId, false, this.config) + const pages = createPagesMapping( + pagePaths.filter(i => i !== null), + this.config.pageExtensions + ) + const entrypoints = createEntrypoints( + pages, + 'server', + this.buildId, + false, + this.config + ) let additionalClientEntrypoints = {} - additionalClientEntrypoints[CLIENT_STATIC_FILES_RUNTIME_AMP] = `.${sep}` + relativePath(this.dir, join(NEXT_PROJECT_ROOT_DIST_CLIENT, 'amp-dev')) + additionalClientEntrypoints[CLIENT_STATIC_FILES_RUNTIME_AMP] = + `.${sep}` + + relativePath(this.dir, join(NEXT_PROJECT_ROOT_DIST_CLIENT, 'amp-dev')) return Promise.all([ - getBaseWebpackConfig(this.dir, { dev: true, isServer: false, config: this.config, buildId: this.buildId, entrypoints: { ...entrypoints.client, ...additionalClientEntrypoints } }), - getBaseWebpackConfig(this.dir, { dev: true, isServer: true, config: this.config, buildId: this.buildId, entrypoints: entrypoints.server }) + getBaseWebpackConfig(this.dir, { + dev: true, + isServer: false, + config: this.config, + buildId: this.buildId, + entrypoints: { ...entrypoints.client, ...additionalClientEntrypoints } + }), + getBaseWebpackConfig(this.dir, { + dev: true, + isServer: true, + config: this.config, + buildId: this.buildId, + entrypoints: entrypoints.server + }) ]) } @@ -227,7 +264,7 @@ export default class HotReloader { const middleware = webpackDevMiddleware || this.webpackDevMiddleware if (middleware) { return new Promise((resolve, reject) => { - middleware.close((err) => { + middleware.close(err => { if (err) return reject(err) resolve() }) @@ -252,7 +289,11 @@ export default class HotReloader { await this.stop(oldWebpackDevMiddleware) } - assignBuildTools ({ webpackDevMiddleware, webpackHotMiddleware, onDemandEntries }) { + assignBuildTools ({ + webpackDevMiddleware, + webpackHotMiddleware, + onDemandEntries + }) { this.webpackDevMiddleware = webpackDevMiddleware this.webpackHotMiddleware = webpackHotMiddleware this.onDemandEntries = onDemandEntries @@ -266,10 +307,7 @@ export default class HotReloader { } async prepareBuildTools (multiCompiler) { - watchCompiler( - multiCompiler.compilers[0], - multiCompiler.compilers[1] - ) + watchCompiler(multiCompiler.compilers[0], multiCompiler.compilers[1]) const tsConfigPath = join(this.dir, 'tsconfig.json') const useTypeScript = await fileExists(tsConfigPath) @@ -278,73 +316,83 @@ export default class HotReloader { } // This plugin watches for changes to _document.js and notifies the client side that it should reload the page - multiCompiler.compilers[1].hooks.done.tap('NextjsHotReloaderForServer', (stats) => { - if (!this.initialized) { - return - } + multiCompiler.compilers[1].hooks.done.tap( + 'NextjsHotReloaderForServer', + stats => { + if (!this.initialized) { + return + } - const { compilation } = stats + const { compilation } = stats - // We only watch `_document` for changes on the server compilation - // the rest of the files will be triggered by the client compilation - const documentChunk = compilation.chunks.find(c => c.name === normalize(`static/${this.buildId}/pages/_document.js`)) - // If the document chunk can't be found we do nothing - if (!documentChunk) { - console.warn('_document.js chunk not found') - return - } + // We only watch `_document` for changes on the server compilation + // the rest of the files will be triggered by the client compilation + const documentChunk = compilation.chunks.find( + c => c.name === normalize(`static/${this.buildId}/pages/_document.js`) + ) + // If the document chunk can't be found we do nothing + if (!documentChunk) { + console.warn('_document.js chunk not found') + return + } - // Initial value - if (this.serverPrevDocumentHash === null) { - this.serverPrevDocumentHash = documentChunk.hash - return - } + // Initial value + if (this.serverPrevDocumentHash === null) { + this.serverPrevDocumentHash = documentChunk.hash + return + } - // If _document.js didn't change we don't trigger a reload - if (documentChunk.hash === this.serverPrevDocumentHash) { - return - } + // If _document.js didn't change we don't trigger a reload + if (documentChunk.hash === this.serverPrevDocumentHash) { + return + } - // Notify reload to reload the page, as _document.js was changed (different hash) - this.send('reloadPage') - this.serverPrevDocumentHash = documentChunk.hash - }) + // Notify reload to reload the page, as _document.js was changed (different hash) + this.send('reloadPage') + this.serverPrevDocumentHash = documentChunk.hash + } + ) - multiCompiler.compilers[0].hooks.done.tap('NextjsHotReloaderForClient', (stats) => { - const { compilation } = stats - const chunkNames = new Set( - compilation.chunks - .map((c) => c.name) - .filter(name => IS_BUNDLED_PAGE_REGEX.test(name)) - ) + multiCompiler.compilers[0].hooks.done.tap( + 'NextjsHotReloaderForClient', + stats => { + const { compilation } = stats + const chunkNames = new Set( + compilation.chunks + .map(c => c.name) + .filter(name => IS_BUNDLED_PAGE_REGEX.test(name)) + ) - if (this.initialized) { - // detect chunks which have to be replaced with a new template - // e.g, pages/index.js <-> pages/_error.js - const addedPages = diff(chunkNames, this.prevChunkNames) - const removedPages = diff(this.prevChunkNames, chunkNames) - - if (addedPages.size > 0) { - for (const addedPage of addedPages) { - let page = '/' + ROUTE_NAME_REGEX.exec(addedPage)[1].replace(/\\/g, '/') - page = page === '/index' ? '/' : page - this.send('addedPage', page) + if (this.initialized) { + // detect chunks which have to be replaced with a new template + // e.g, pages/index.js <-> pages/_error.js + const addedPages = diff(chunkNames, this.prevChunkNames) + const removedPages = diff(this.prevChunkNames, chunkNames) + + if (addedPages.size > 0) { + for (const addedPage of addedPages) { + let page = + '/' + ROUTE_NAME_REGEX.exec(addedPage)[1].replace(/\\/g, '/') + page = page === '/index' ? '/' : page + this.send('addedPage', page) + } } - } - if (removedPages.size > 0) { - for (const removedPage of removedPages) { - let page = '/' + ROUTE_NAME_REGEX.exec(removedPage)[1].replace(/\\/g, '/') - page = page === '/index' ? '/' : page - this.send('removedPage', page) + if (removedPages.size > 0) { + for (const removedPage of removedPages) { + let page = + '/' + ROUTE_NAME_REGEX.exec(removedPage)[1].replace(/\\/g, '/') + page = page === '/index' ? '/' : page + this.send('removedPage', page) + } } } - } - this.initialized = true - this.stats = stats - this.prevChunkNames = chunkNames - }) + this.initialized = true + this.stats = stats + this.prevChunkNames = chunkNames + } + ) // We don’t watch .git/ .next/ and node_modules for changes const ignored = [ @@ -362,28 +410,44 @@ export default class HotReloader { } if (this.config.webpackDevMiddleware) { - console.log(`> Using "webpackDevMiddleware" config function defined in ${this.config.configOrigin}.`) - webpackDevMiddlewareConfig = this.config.webpackDevMiddleware(webpackDevMiddlewareConfig) + console.log( + `> Using "webpackDevMiddleware" config function defined in ${ + this.config.configOrigin + }.` + ) + webpackDevMiddlewareConfig = this.config.webpackDevMiddleware( + webpackDevMiddlewareConfig + ) } - const webpackDevMiddleware = WebpackDevMiddleware(multiCompiler, webpackDevMiddlewareConfig) + const webpackDevMiddleware = WebpackDevMiddleware( + multiCompiler, + webpackDevMiddlewareConfig + ) - const webpackHotMiddleware = WebpackHotMiddleware(multiCompiler.compilers[0], { - path: '/_next/webpack-hmr', - log: false, - heartbeat: 2500 - }) + const webpackHotMiddleware = WebpackHotMiddleware( + multiCompiler.compilers[0], + { + path: '/_next/webpack-hmr', + log: false, + heartbeat: 2500 + } + ) - const onDemandEntries = onDemandEntryHandler(webpackDevMiddleware, multiCompiler, { - dir: this.dir, - buildId: this.buildId, - distDir: this.config.distDir, - reload: this.reload.bind(this), - pageExtensions: this.config.pageExtensions, - publicRuntimeConfig: this.config.publicRuntimeConfig, - serverRuntimeConfig: this.config.serverRuntimeConfig, - ...this.config.onDemandEntries - }) + const onDemandEntries = onDemandEntryHandler( + webpackDevMiddleware, + multiCompiler, + { + dir: this.dir, + buildId: this.buildId, + distDir: this.config.distDir, + reload: this.reload.bind(this), + pageExtensions: this.config.pageExtensions, + publicRuntimeConfig: this.config.publicRuntimeConfig, + serverRuntimeConfig: this.config.serverRuntimeConfig, + ...this.config.onDemandEntries + } + ) return { webpackDevMiddleware, @@ -394,7 +458,7 @@ export default class HotReloader { waitUntilValid (webpackDevMiddleware) { const middleware = webpackDevMiddleware || this.webpackDevMiddleware - return new Promise((resolve) => { + return new Promise(resolve => { middleware.waitUntilValid(resolve) }) } @@ -413,7 +477,10 @@ export default class HotReloader { }) // If there is an error related to the requesting page we display it instead of the first error - if (failedPages[normalizedPage] && failedPages[normalizedPage].length > 0) { + if ( + failedPages[normalizedPage] && + failedPages[normalizedPage].length > 0 + ) { return failedPages[normalizedPage] } @@ -438,5 +505,5 @@ export default class HotReloader { } function diff (a, b) { - return new Set([...a].filter((v) => !b.has(v))) + return new Set([...a].filter(v => !b.has(v))) } diff --git a/packages/next/server/htmlescape.ts b/packages/next/server/htmlescape.ts index da15dc6c54142..befd09c7be467 100644 --- a/packages/next/server/htmlescape.ts +++ b/packages/next/server/htmlescape.ts @@ -1,7 +1,7 @@ // This utility is based on https://github.com/zertosh/htmlescape // License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE -const ESCAPE_LOOKUP: {[match: string]: string} = { +const ESCAPE_LOOKUP: { [match: string]: string } = { '&': '\\u0026', '>': '\\u003e', '<': '\\u003c', @@ -12,5 +12,5 @@ const ESCAPE_LOOKUP: {[match: string]: string} = { const ESCAPE_REGEX = /[&><\u2028\u2029]/g export function htmlEscapeJsonString(str: string) { - return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]) + return str.replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]) } diff --git a/packages/next/server/lib/find-page-file.ts b/packages/next/server/lib/find-page-file.ts index f49626d7564a7..e47ff82c4b80a 100644 --- a/packages/next/server/lib/find-page-file.ts +++ b/packages/next/server/lib/find-page-file.ts @@ -1,7 +1,11 @@ import { join } from 'path' -import {isWriteable} from '../../build/is-writeable' +import { isWriteable } from '../../build/is-writeable' -export async function findPageFile(rootDir: string, normalizedPagePath: string, pageExtensions: string[]): Promise<string|null> { +export async function findPageFile( + rootDir: string, + normalizedPagePath: string, + pageExtensions: string[] +): Promise<string | null> { for (const extension of pageExtensions) { const relativePagePath = `${normalizedPagePath}.${extension}` const pagePath = join(rootDir, relativePagePath) @@ -10,7 +14,10 @@ export async function findPageFile(rootDir: string, normalizedPagePath: string, return relativePagePath } - const relativePagePathWithIndex = join(normalizedPagePath, `index.${extension}`) + const relativePagePathWithIndex = join( + normalizedPagePath, + `index.${extension}` + ) const pagePathWithIndex = join(rootDir, relativePagePathWithIndex) if (await isWriteable(pagePathWithIndex)) { return relativePagePathWithIndex diff --git a/packages/next/server/lib/start-server.ts b/packages/next/server/lib/start-server.ts index 1a858328bf38b..55ecb0c618e51 100644 --- a/packages/next/server/lib/start-server.ts +++ b/packages/next/server/lib/start-server.ts @@ -1,7 +1,11 @@ import http from 'http' import next from '../next' -export default async function start(serverOptions: any, port?: number, hostname?: string) { +export default async function start( + serverOptions: any, + port?: number, + hostname?: string +) { const app = next(serverOptions) const srv = http.createServer(app.getRequestHandler()) await new Promise((resolve, reject) => { diff --git a/packages/next/server/next-dev-server.js b/packages/next/server/next-dev-server.js index 8f9bb56c4b144..829aac75b087f 100644 --- a/packages/next/server/next-dev-server.js +++ b/packages/next/server/next-dev-server.js @@ -109,8 +109,7 @@ export default class DevServer extends Server { continue } - let pageName = - '/' + relative(pagesDir, fileName).replace(/\\+/g, '/') + let pageName = '/' + relative(pagesDir, fileName).replace(/\\+/g, '/') if (!pageName.includes('/$')) { continue } diff --git a/packages/next/server/on-demand-entry-handler.js b/packages/next/server/on-demand-entry-handler.js index 2f56bbde6cfe1..25b89c73af435 100644 --- a/packages/next/server/on-demand-entry-handler.js +++ b/packages/next/server/on-demand-entry-handler.js @@ -18,24 +18,28 @@ const BUILT = Symbol('built') function addEntry (compilation, context, name, entry) { return new Promise((resolve, reject) => { const dep = DynamicEntryPlugin.createDependency(entry, name) - compilation.addEntry(context, dep, name, (err) => { + compilation.addEntry(context, dep, name, err => { if (err) return reject(err) resolve() }) }) } -export default function onDemandEntryHandler (devMiddleware, multiCompiler, { - buildId, - dir, - distDir, - reload, - pageExtensions, - maxInactiveAge, - pagesBufferLength, - publicRuntimeConfig, - serverRuntimeConfig -}) { +export default function onDemandEntryHandler ( + devMiddleware, + multiCompiler, + { + buildId, + dir, + distDir, + reload, + pageExtensions, + maxInactiveAge, + pagesBufferLength, + publicRuntimeConfig, + serverRuntimeConfig + } +) { const pagesDir = join(dir, 'pages') const { compilers } = multiCompiler const invalidator = new Invalidator(devMiddleware, multiCompiler) @@ -48,10 +52,10 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { let lastEntry = null for (const compiler of compilers) { - compiler.hooks.make.tapPromise('NextJsOnDemandEntries', (compilation) => { + compiler.hooks.make.tapPromise('NextJsOnDemandEntries', compilation => { invalidator.startBuilding() - const allEntries = Object.keys(entries).map(async (page) => { + const allEntries = Object.keys(entries).map(async page => { if (compiler.name === 'client' && page.startsWith('/api')) { return } @@ -64,27 +68,35 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { } entries[page].status = BUILDING - return addEntry(compilation, compiler.context, name, [compiler.name === 'client' ? `next-client-pages-loader?${stringify({ page, absolutePagePath })}!` : absolutePagePath]) + return addEntry(compilation, compiler.context, name, [ + compiler.name === 'client' + ? `next-client-pages-loader?${stringify({ + page, + absolutePagePath + })}!` + : absolutePagePath + ]) }) - return Promise.all(allEntries) - .catch(err => console.error(err)) + return Promise.all(allEntries).catch(err => console.error(err)) }) } function findHardFailedPages (errors) { - return errors.filter(e => { - // Make sure to only pick errors which marked with missing modules - const hasNoModuleFoundError = /ENOENT/.test(e.message) || /Module not found/.test(e.message) - if (!hasNoModuleFoundError) return false - - // The page itself is missing. So this is a failed page. - if (IS_BUNDLED_PAGE_REGEX.test(e.module.name)) return true - - // No dependencies means this is a top level page. - // So this is a failed page. - return e.module.dependencies.length === 0 - }) + return errors + .filter(e => { + // Make sure to only pick errors which marked with missing modules + const hasNoModuleFoundError = + /ENOENT/.test(e.message) || /Module not found/.test(e.message) + if (!hasNoModuleFoundError) return false + + // The page itself is missing. So this is a failed page. + if (IS_BUNDLED_PAGE_REGEX.test(e.module.name)) return true + + // No dependencies means this is a top level page. + // So this is a failed page. + return e.module.dependencies.length === 0 + }) .map(e => e.module.chunks) .reduce((a, b) => [...a, ...b], []) .map(c => { @@ -113,10 +125,18 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { return pagePaths } - multiCompiler.hooks.done.tap('NextJsOnDemandEntries', (multiStats) => { + multiCompiler.hooks.done.tap('NextJsOnDemandEntries', multiStats => { const [clientStats, serverStats] = multiStats.stats - const hardFailedPages = [...new Set([...findHardFailedPages(clientStats.compilation.errors), ...findHardFailedPages(serverStats.compilation.errors)])] - const pagePaths = new Set([...getPagePathsFromEntrypoints(clientStats.compilation.entrypoints), ...(getPagePathsFromEntrypoints(serverStats.compilation.entrypoints))]) + const hardFailedPages = [ + ...new Set([ + ...findHardFailedPages(clientStats.compilation.errors), + ...findHardFailedPages(serverStats.compilation.errors) + ]) + ] + const pagePaths = new Set([ + ...getPagePathsFromEntrypoints(clientStats.compilation.entrypoints), + ...getPagePathsFromEntrypoints(serverStats.compilation.entrypoints) + ]) // compilation.entrypoints is a Map object, so iterating over it 0 is the key and 1 is the value for (const pagePath of pagePaths) { @@ -139,7 +159,11 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { invalidator.doneBuilding() if (hardFailedPages.length > 0 && !reloading) { - console.log(`> Reloading webpack due to inconsistant state of pages(s): ${hardFailedPages.join(', ')}`) + console.log( + `> Reloading webpack due to inconsistant state of pages(s): ${hardFailedPages.join( + ', ' + )}` + ) reloading = true reload() .then(() => { @@ -157,7 +181,12 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { const disposeHandler = setInterval(function () { if (stopped) return - disposeInactiveEntries(devMiddleware, entries, lastAccessPages, maxInactiveAge) + disposeInactiveEntries( + devMiddleware, + entries, + lastAccessPages, + maxInactiveAge + ) }, 5000) disposeHandler.unref() @@ -176,7 +205,9 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { // If there's no entry, it may have been invalidated and needs to be re-built. if (!entryInfo) { - if (page !== lastEntry) Log.event(`client pings, but there's no entry for page: ${page}`) + if (page !== lastEntry) { + Log.event(`client pings, but there's no entry for page: ${page}`) + } lastEntry = page return { invalid: true } } @@ -207,7 +238,7 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { return { waitUntilReloaded () { if (!reloading) return Promise.resolve(true) - return new Promise((resolve) => { + return new Promise(resolve => { reloadCallbacks.once('done', function () { resolve() }) @@ -224,7 +255,11 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { throw pageNotFoundError(normalizedPagePath) } - let pagePath = await findPageFile(pagesDir, normalizedPagePath, pageExtensions) + let pagePath = await findPageFile( + pagesDir, + normalizedPagePath, + pageExtensions + ) // Default the /_error route to the Next.js provided default page if (page === '/_error' && pagePath === null) { @@ -235,11 +270,15 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { throw pageNotFoundError(normalizedPagePath) } - let pageUrl = `/${pagePath.replace(new RegExp(`\\.+(?:${pageExtensions.join('|')})$`), '').replace(/\\/g, '/')}`.replace(/\/index$/, '') + let pageUrl = `/${pagePath + .replace(new RegExp(`\\.+(?:${pageExtensions.join('|')})$`), '') + .replace(/\\/g, '/')}`.replace(/\/index$/, '') pageUrl = pageUrl === '' ? '/' : pageUrl const bundleFile = pageUrl === '/' ? '/index.js' : `${pageUrl}.js` const name = join('static', buildId, 'pages', bundleFile) - const absolutePagePath = pagePath.startsWith('next/dist/pages') ? require.resolve(pagePath) : join(pagesDir, pagePath) + const absolutePagePath = pagePath.startsWith('next/dist/pages') + ? require.resolve(pagePath) + : join(pagesDir, pagePath) page = posix.normalize(pageUrl) @@ -286,12 +325,11 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { // Webpack config is reloading. So, we need to wait until it's done and // reload user's browser. // So the user could connect to the new handler and webpack setup. - this.waitUntilReloaded() - .then(() => { - res.statusCode = 302 - res.setHeader('Location', req.url) - res.end('302') - }) + this.waitUntilReloaded().then(() => { + res.statusCode = 302 + res.setHeader('Location', req.url) + res.end('302') + }) } else { if (!/^\/_next\/webpack-hmr/.test(req.url)) return next() @@ -318,10 +356,15 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { } } -function disposeInactiveEntries (devMiddleware, entries, lastAccessPages, maxInactiveAge) { +function disposeInactiveEntries ( + devMiddleware, + entries, + lastAccessPages, + maxInactiveAge +) { const disposingPages = [] - Object.keys(entries).forEach((page) => { + Object.keys(entries).forEach(page => { const { lastActiveTime, status } = entries[page] // This means this entry is currently building or just added @@ -339,7 +382,7 @@ function disposeInactiveEntries (devMiddleware, entries, lastAccessPages, maxIna }) if (disposingPages.length > 0) { - disposingPages.forEach((page) => { + disposingPages.forEach(page => { delete entries[page] }) Log.event(`disposing inactive page(s): ${disposingPages.join(', ')}`) diff --git a/packages/next/taskfile-babel.js b/packages/next/taskfile-babel.js index 919e14f319522..b3c6077f78ee0 100644 --- a/packages/next/taskfile-babel.js +++ b/packages/next/taskfile-babel.js @@ -28,12 +28,20 @@ module.exports = function (task) { } // Workaround for noop.js loading - if (file.base === 'next-dev.js') output.code = output.code.replace('// REPLACE_NOOP_IMPORT', `import('./noop');`) + if (file.base === 'next-dev.js') { + output.code = output.code.replace( + '// REPLACE_NOOP_IMPORT', + `import('./noop');` + ) + } file.data = Buffer.from(setNextVersion(output.code)) }) } function setNextVersion (code) { - return code.replace(/process\.env\.__NEXT_VERSION/, `"${require('./package.json').version}"`) + return code.replace( + /process\.env\.__NEXT_VERSION/, + `"${require('./package.json').version}"` + ) } diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 442b3ca376446..948cb364f1c57 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -4,42 +4,49 @@ const relative = require('path').relative const babelClientOpts = { presets: [ '@babel/preset-typescript', - ['@babel/preset-env', { - modules: 'commonjs', - targets: { - 'esmodules': true - }, - loose: true, - exclude: ['transform-typeof-symbol'] - }], + [ + '@babel/preset-env', + { + modules: 'commonjs', + targets: { + esmodules: true + }, + loose: true, + exclude: ['transform-typeof-symbol'] + } + ], '@babel/preset-react' ], plugins: [ ['@babel/plugin-proposal-class-properties', { loose: true }], - ['@babel/plugin-transform-runtime', { - corejs: 2, - helpers: true, - regenerator: false, - useESModules: false - }] + [ + '@babel/plugin-transform-runtime', + { + corejs: 2, + helpers: true, + regenerator: false, + useESModules: false + } + ] ] } const babelServerOpts = { presets: [ '@babel/preset-typescript', - ['@babel/preset-env', { - modules: 'commonjs', - targets: { - node: '8.3' - }, - loose: true, - exclude: ['transform-typeof-symbol'] - }] + [ + '@babel/preset-env', + { + modules: 'commonjs', + targets: { + node: '8.3' + }, + loose: true, + exclude: ['transform-typeof-symbol'] + } + ] ], - plugins: [ - ['@babel/plugin-proposal-class-properties', { loose: true }] - ] + plugins: [['@babel/plugin-proposal-class-properties', { loose: true }]] } // eslint-disable-next-line camelcase @@ -83,29 +90,53 @@ export async function ncc_text_table (task, opts) { } export async function precompile (task) { - await task.parallel(['ncc_unistore', 'ncc_resolve', 'ncc_arg', 'ncc_nanoid', 'ncc_text_table']) + await task.parallel([ + 'ncc_unistore', + 'ncc_resolve', + 'ncc_arg', + 'ncc_nanoid', + 'ncc_text_table' + ]) } export async function compile (task) { - await task.parallel(['cli', 'bin', 'server', 'nextbuild', 'nextbuildstatic', 'pages', 'lib', 'client']) + await task.parallel([ + 'cli', + 'bin', + 'server', + 'nextbuild', + 'nextbuildstatic', + 'pages', + 'lib', + 'client' + ]) } export async function bin (task, opts) { const babelOpts = { ...babelServerOpts, - plugins: [ ...babelServerOpts.plugins, 'babel-plugin-dynamic-import-node' ] + plugins: [...babelServerOpts.plugins, 'babel-plugin-dynamic-import-node'] } - await task.source(opts.src || 'bin/*').babel(babelOpts, { stripExtension: true }).target('dist/bin', { mode: '0755' }) + await task + .source(opts.src || 'bin/*') + .babel(babelOpts, { stripExtension: true }) + .target('dist/bin', { mode: '0755' }) notify('Compiled binaries') } export async function cli (task, opts) { - await task.source(opts.src || 'cli/**/*.+(js|ts|tsx)').babel(babelServerOpts).target('dist/cli') + await task + .source(opts.src || 'cli/**/*.+(js|ts|tsx)') + .babel(babelServerOpts) + .target('dist/cli') notify('Compiled cli files') } export async function lib (task, opts) { - await task.source(opts.src || 'lib/**/*.+(js|ts|tsx)').babel(babelServerOpts).target('dist/lib') + await task + .source(opts.src || 'lib/**/*.+(js|ts|tsx)') + .babel(babelServerOpts) + .target('dist/lib') notify('Compiled lib files') } @@ -113,30 +144,45 @@ export async function server (task, opts) { const babelOpts = { ...babelServerOpts, // the /server files may use React - presets: [ ...babelServerOpts.presets, '@babel/preset-react' ] + presets: [...babelServerOpts.presets, '@babel/preset-react'] } - await task.source(opts.src || 'server/**/*.+(js|ts|tsx)').babel(babelOpts).target('dist/server') + await task + .source(opts.src || 'server/**/*.+(js|ts|tsx)') + .babel(babelOpts) + .target('dist/server') notify('Compiled server files') } export async function nextbuild (task, opts) { - await task.source(opts.src || 'build/**/*.+(js|ts|tsx)').babel(babelServerOpts).target('dist/build') + await task + .source(opts.src || 'build/**/*.+(js|ts|tsx)') + .babel(babelServerOpts) + .target('dist/build') notify('Compiled build files') } export async function client (task, opts) { - await task.source(opts.src || 'client/**/*.+(js|ts|tsx)').babel(babelClientOpts).target('dist/client') + await task + .source(opts.src || 'client/**/*.+(js|ts|tsx)') + .babel(babelClientOpts) + .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|ts|tsx)').babel(babelServerOpts).target('dist/export') + await task + .source(opts.src || 'export/**/*.+(js|ts|tsx)') + .babel(babelServerOpts) + .target('dist/export') notify('Compiled export files') } export async function pages (task, opts) { - await task.source(opts.src || 'pages/**/*.+(js|ts|tsx)').babel(babelClientOpts).target('dist/pages') + await task + .source(opts.src || 'pages/**/*.+(js|ts|tsx)') + .babel(babelClientOpts) + .target('dist/pages') } export async function build (task) { diff --git a/packages/next/tsconfig.json b/packages/next/tsconfig.json index 24befc38c71ef..29765d3c9ac15 100644 --- a/packages/next/tsconfig.json +++ b/packages/next/tsconfig.json @@ -7,9 +7,5 @@ "moduleResolution": "node", "jsx": "react" }, - "exclude": [ - "dist", - "./*.d.ts", - "./router.d.ts" - ] + "exclude": ["dist", "./*.d.ts", "./router.d.ts"] } diff --git a/packages/next/types/index.d.ts b/packages/next/types/index.d.ts index e52c03029113b..3a8235b0e3376 100644 --- a/packages/next/types/index.d.ts +++ b/packages/next/types/index.d.ts @@ -1,5 +1,5 @@ import React from 'react' -import { NextPageContext, NextComponentType } from 'next-server/dist/lib/utils'; +import { NextPageContext, NextComponentType } from 'next-server/dist/lib/utils' /// <reference types="node" /> /// <reference types="react" /> @@ -24,7 +24,6 @@ declare module 'react' { } } - /** * `Page` type, use it as a guide to create `pages`. */ diff --git a/packages/next/types/misc.d.ts b/packages/next/types/misc.d.ts index 8a8aae99a0d81..aa3ed35178e31 100644 --- a/packages/next/types/misc.d.ts +++ b/packages/next/types/misc.d.ts @@ -1,14 +1,14 @@ -declare module '@babel/plugin-transform-modules-commonjs'; -declare module 'next-server/next-config'; -declare module 'next-server/constants'; -declare module 'webpack/lib/GraphHelpers'; -declare module 'unfetch'; -declare module 'styled-jsx/server'; +declare module '@babel/plugin-transform-modules-commonjs' +declare module 'next-server/next-config' +declare module 'next-server/constants' +declare module 'webpack/lib/GraphHelpers' +declare module 'unfetch' +declare module 'styled-jsx/server' declare module 'next/dist/compiled/nanoid/index.js' { - function nanoid(size?: number): string; + function nanoid(size?: number): string - export = nanoid; + export = nanoid } declare module 'next/dist/compiled/unistore' { @@ -19,27 +19,33 @@ declare module 'next/dist/compiled/unistore' { declare module 'next/dist/compiled/resolve/index.js' { import resolve from 'resolve' - export = resolve; + export = resolve } declare module 'next/dist/compiled/text-table' { - function textTable(rows: Array<Array<{}>>, opts?: { - hsep?: string, - align?: Array<'l' | 'r' | 'c' | '.'>, - stringLength?(str: string): number - }): string; + function textTable( + rows: Array<Array<{}>>, + opts?: { + hsep?: string + align?: Array<'l' | 'r' | 'c' | '.'> + stringLength?(str: string): number + } + ): string - export = textTable; + export = textTable } declare module 'next/dist/compiled/arg/index.js' { - function arg<T extends arg.Spec>(spec: T, options?: {argv?: string[], permissive?: boolean}): arg.Result<T>; + function arg<T extends arg.Spec>( + spec: T, + options?: { argv?: string[]; permissive?: boolean } + ): arg.Result<T> namespace arg { - export type Handler = (value: string) => any; + export type Handler = (value: string) => any export interface Spec { - [key: string]: string | Handler | [Handler]; + [key: string]: string | Handler | [Handler] } export type Result<T extends Spec> = { _: string[] } & { @@ -50,27 +56,27 @@ declare module 'next/dist/compiled/arg/index.js' { : T[K] extends [Handler] ? Array<ReturnType<T[K][0]>> : never - }; + } } - export = arg; + export = arg } declare module 'autodll-webpack-plugin' { import webpack from 'webpack' class AutoDllPlugin implements webpack.Plugin { constructor(settings?: { - inject?: boolean, - plugins?: webpack.Configuration["plugins"], - context?: string, - debug?: boolean, - filename?: string, - path?: string, - inherit?: boolean, - entry?: webpack.Entry, + inject?: boolean + plugins?: webpack.Configuration['plugins'] + context?: string + debug?: boolean + filename?: string + path?: string + inherit?: boolean + entry?: webpack.Entry config?: webpack.Configuration }) - apply: webpack.Plugin["apply"] + apply: webpack.Plugin['apply'] [k: string]: any } @@ -79,6 +85,6 @@ declare module 'autodll-webpack-plugin' { declare module NodeJS { interface Process { - crossOrigin?: string; + crossOrigin?: string } } diff --git a/packages/next/types/webpack.d.ts b/packages/next/types/webpack.d.ts index 0898fa52fda26..095faf699a4f9 100644 --- a/packages/next/types/webpack.d.ts +++ b/packages/next/types/webpack.d.ts @@ -22,1866 +22,2071 @@ /// <reference types="node" /> declare module 'webpack' { - import { Tapable, HookMap, - SyncBailHook, SyncHook, SyncLoopHook, SyncWaterfallHook, - AsyncParallelBailHook, AsyncParallelHook, AsyncSeriesBailHook, AsyncSeriesHook, AsyncSeriesWaterfallHook } from 'tapable'; - import * as UglifyJS from 'uglify-js'; - import * as anymatch from 'anymatch'; - import { RawSourceMap } from 'source-map'; - - export = webpack; - - function webpack( - options: webpack.Configuration, - handler: webpack.Compiler.Handler - ): webpack.Compiler.Watching | webpack.Compiler; - function webpack(options?: webpack.Configuration): webpack.Compiler; - - function webpack( - options: webpack.Configuration[], - handler: webpack.MultiCompiler.Handler - ): webpack.MultiWatching | webpack.MultiCompiler; - function webpack(options: webpack.Configuration[]): webpack.MultiCompiler; - - namespace webpack { - interface Configuration { - /** Enable production optimizations or development hints. */ - mode?: "development" | "production" | "none"; - /** Name of the configuration. Used when loading multiple configurations. */ - name?: string; - /** - * The base directory (absolute path!) for resolving the `entry` option. - * If `output.pathinfo` is set, the included pathinfo is shortened to this directory. - */ - context?: string; - entry?: string | string[] | Entry | EntryFunc; - /** Choose a style of source mapping to enhance the debugging process. These values can affect build and rebuild speed dramatically. */ - devtool?: Options.Devtool; - /** Options affecting the output. */ - output?: Output; - /** Options affecting the normal modules (NormalModuleFactory) */ - module?: Module; - /** Options affecting the resolving of modules. */ - resolve?: Resolve; - /** Like resolve but for loaders. */ - resolveLoader?: ResolveLoader; - /** - * Specify dependencies that shouldn’t be resolved by webpack, but should become dependencies of the resulting bundle. - * The kind of the dependency depends on output.libraryTarget. - */ - externals?: Externals; - /** - * - "web" Compile for usage in a browser-like environment (default). - * - "webworker" Compile as WebWorker. - * - "node" Compile for usage in a node.js-like environment (use require to load chunks). - * - "async-node" Compile for usage in a node.js-like environment (use fs and vm to load chunks async). - * - "node-webkit" Compile for usage in webkit, uses jsonp chunk loading but also supports builtin node.js modules plus require(“nw.gui”) (experimental) - * - "atom" Compile for usage in electron (formerly known as atom-shell), supports require for modules necessary to run Electron. - * - "electron-renderer" Compile for Electron for renderer process, providing a target using JsonpTemplatePlugin, FunctionModulePlugin for browser - * environments and NodeTargetPlugin and ExternalsPlugin for CommonJS and Electron built-in modules. - * - "electron-main" Compile for Electron for main process. - * - "atom" Alias for electron-main. - * - "electron" Alias for electron-main. - */ - target?: 'web' | 'webworker' | 'node' | 'async-node' | 'node-webkit' | 'atom' | 'electron' | 'electron-renderer' | 'electron-main' | ((compiler?: any) => void); - /** Report the first error as a hard error instead of tolerating it. */ - bail?: boolean; - /** Capture timing information for each module. */ - profile?: boolean; - /** Cache generated modules and chunks to improve performance for multiple incremental builds. */ - cache?: boolean | object; - /** Enter watch mode, which rebuilds on file change. */ - watch?: boolean; - watchOptions?: Options.WatchOptions; - /** Switch loaders to debug mode. */ - debug?: boolean; - /** Include polyfills or mocks for various node stuff */ - node?: Node | false; - /** Set the value of require.amd and define.amd. */ - amd?: { [moduleName: string]: boolean }; - /** Used for recordsInputPath and recordsOutputPath */ - recordsPath?: string; - /** Load compiler state from a json file. */ - recordsInputPath?: string; - /** Store compiler state to a json file. */ - recordsOutputPath?: string; - /** Add additional plugins to the compiler. */ - plugins?: Plugin[]; - /** Stats options for logging */ - stats?: Options.Stats; - /** Performance options */ - performance?: Options.Performance | false; - /** Limit the number of parallel processed modules. Can be used to fine tune performance or to get more reliable profiling results */ - parallelism?: number; - /** Optimization options */ - optimization?: Options.Optimization; - } + import { + Tapable, + HookMap, + SyncBailHook, + SyncHook, + SyncLoopHook, + SyncWaterfallHook, + AsyncParallelBailHook, + AsyncParallelHook, + AsyncSeriesBailHook, + AsyncSeriesHook, + AsyncSeriesWaterfallHook, + } from 'tapable' + import * as UglifyJS from 'uglify-js' + import * as anymatch from 'anymatch' + import { RawSourceMap } from 'source-map' + + export = webpack + + function webpack( + options: webpack.Configuration, + handler: webpack.Compiler.Handler + ): webpack.Compiler.Watching | webpack.Compiler + function webpack(options?: webpack.Configuration): webpack.Compiler + + function webpack( + options: webpack.Configuration[], + handler: webpack.MultiCompiler.Handler + ): webpack.MultiWatching | webpack.MultiCompiler + function webpack(options: webpack.Configuration[]): webpack.MultiCompiler + + namespace webpack { + interface Configuration { + /** Enable production optimizations or development hints. */ + mode?: 'development' | 'production' | 'none' + /** Name of the configuration. Used when loading multiple configurations. */ + name?: string + /** + * The base directory (absolute path!) for resolving the `entry` option. + * If `output.pathinfo` is set, the included pathinfo is shortened to this directory. + */ + context?: string + entry?: string | string[] | Entry | EntryFunc + /** Choose a style of source mapping to enhance the debugging process. These values can affect build and rebuild speed dramatically. */ + devtool?: Options.Devtool + /** Options affecting the output. */ + output?: Output + /** Options affecting the normal modules (NormalModuleFactory) */ + module?: Module + /** Options affecting the resolving of modules. */ + resolve?: Resolve + /** Like resolve but for loaders. */ + resolveLoader?: ResolveLoader + /** + * Specify dependencies that shouldn’t be resolved by webpack, but should become dependencies of the resulting bundle. + * The kind of the dependency depends on output.libraryTarget. + */ + externals?: Externals + /** + * - "web" Compile for usage in a browser-like environment (default). + * - "webworker" Compile as WebWorker. + * - "node" Compile for usage in a node.js-like environment (use require to load chunks). + * - "async-node" Compile for usage in a node.js-like environment (use fs and vm to load chunks async). + * - "node-webkit" Compile for usage in webkit, uses jsonp chunk loading but also supports builtin node.js modules plus require(“nw.gui”) (experimental) + * - "atom" Compile for usage in electron (formerly known as atom-shell), supports require for modules necessary to run Electron. + * - "electron-renderer" Compile for Electron for renderer process, providing a target using JsonpTemplatePlugin, FunctionModulePlugin for browser + * environments and NodeTargetPlugin and ExternalsPlugin for CommonJS and Electron built-in modules. + * - "electron-main" Compile for Electron for main process. + * - "atom" Alias for electron-main. + * - "electron" Alias for electron-main. + */ + target?: + | 'web' + | 'webworker' + | 'node' + | 'async-node' + | 'node-webkit' + | 'atom' + | 'electron' + | 'electron-renderer' + | 'electron-main' + | ((compiler?: any) => void) + /** Report the first error as a hard error instead of tolerating it. */ + bail?: boolean + /** Capture timing information for each module. */ + profile?: boolean + /** Cache generated modules and chunks to improve performance for multiple incremental builds. */ + cache?: boolean | object + /** Enter watch mode, which rebuilds on file change. */ + watch?: boolean + watchOptions?: Options.WatchOptions + /** Switch loaders to debug mode. */ + debug?: boolean + /** Include polyfills or mocks for various node stuff */ + node?: Node | false + /** Set the value of require.amd and define.amd. */ + amd?: { [moduleName: string]: boolean } + /** Used for recordsInputPath and recordsOutputPath */ + recordsPath?: string + /** Load compiler state from a json file. */ + recordsInputPath?: string + /** Store compiler state to a json file. */ + recordsOutputPath?: string + /** Add additional plugins to the compiler. */ + plugins?: Plugin[] + /** Stats options for logging */ + stats?: Options.Stats + /** Performance options */ + performance?: Options.Performance | false + /** Limit the number of parallel processed modules. Can be used to fine tune performance or to get more reliable profiling results */ + parallelism?: number + /** Optimization options */ + optimization?: Options.Optimization + } - interface Entry { - [name: string]: string | string[]; - } + interface Entry { + [name: string]: string | string[] + } - type EntryFunc = () => (string | string[] | Entry | Promise<string | string[] | Entry>); - - interface DevtoolModuleFilenameTemplateInfo { - identifier: string; - shortIdentifier: string; - resource: any; - resourcePath: string; - absoluteResourcePath: string; - allLoaders: any[]; - query: string; - moduleId: string; - hash: string; - } + type EntryFunc = () => + | string + | string[] + | Entry + | Promise<string | string[] | Entry> + + interface DevtoolModuleFilenameTemplateInfo { + identifier: string + shortIdentifier: string + resource: any + resourcePath: string + absoluteResourcePath: string + allLoaders: any[] + query: string + moduleId: string + hash: string + } - interface Output { - /** When used in tandem with output.library and output.libraryTarget, this option allows users to insert comments within the export wrapper. */ - auxiliaryComment?: string | AuxiliaryCommentObject; - /** The filename of the entry chunk as relative path inside the output.path directory. */ - filename?: string | Function; - /** The filename of non-entry chunks as relative path inside the output.path directory. */ - chunkFilename?: string; - /** Number of milliseconds before chunk request expires, defaults to 120,000. */ - chunkLoadTimeout?: number; - /** This option enables cross-origin loading of chunks. */ - crossOriginLoading?: string | boolean; - /** The JSONP function used by webpack for asnyc loading of chunks. */ - jsonpFunction?: string; - /** Allows customization of the script type webpack injects script tags into the DOM to download async chunks. */ - jsonpScriptType?: 'text/javascript' | 'module'; - /** Filename template string of function for the sources array in a generated SourceMap. */ - devtoolModuleFilenameTemplate?: string | ((info: DevtoolModuleFilenameTemplateInfo) => string); - /** Similar to output.devtoolModuleFilenameTemplate, but used in the case of duplicate module identifiers. */ - devtoolFallbackModuleFilenameTemplate?: string | ((info: DevtoolModuleFilenameTemplateInfo) => string); - /** - * Enable line to line mapped mode for all/specified modules. - * Line to line mapped mode uses a simple SourceMap where each line of the generated source is mapped to the same line of the original source. - * It’s a performance optimization. Only use it if your performance need to be better and you are sure that input lines match which generated lines. - * true enables it for all modules (not recommended) - */ - devtoolLineToLine?: boolean; - /** This option determines the modules namespace used with the output.devtoolModuleFilenameTemplate. */ - devtoolNamespace?: string; - /** The filename of the Hot Update Chunks. They are inside the output.path directory. */ - hotUpdateChunkFilename?: string; - /** The JSONP function used by webpack for async loading of hot update chunks. */ - hotUpdateFunction?: string; - /** The filename of the Hot Update Main File. It is inside the output.path directory. */ - hotUpdateMainFilename?: string; - /** If set, export the bundle as library. output.library is the name. */ - library?: string | string[]; - /** - * Which format to export the library: - * - "var" - Export by setting a variable: var Library = xxx (default) - * - "this" - Export by setting a property of this: this["Library"] = xxx - * - "commonjs" - Export by setting a property of exports: exports["Library"] = xxx - * - "commonjs2" - Export by setting module.exports: module.exports = xxx - * - "amd" - Export to AMD (optionally named) - * - "umd" - Export to AMD, CommonJS2 or as property in root - * - "window" - Assign to window - * - "assign" - Assign to a global variable - * - "jsonp" - Generate Webpack JSONP module - */ - libraryTarget?: LibraryTarget; - /** Configure which module or modules will be exposed via the `libraryTarget` */ - libraryExport?: string | string[]; - /** If output.libraryTarget is set to umd and output.library is set, setting this to true will name the AMD module. */ - umdNamedDefine?: boolean; - /** The output directory as absolute path. */ - path?: string; - /** Include comments with information about the modules. */ - pathinfo?: boolean; - /** The output.path from the view of the Javascript / HTML page. */ - publicPath?: string; - /** The filename of the SourceMaps for the JavaScript files. They are inside the output.path directory. */ - sourceMapFilename?: string; - /** Prefixes every line of the source in the bundle with this string. */ - sourcePrefix?: string; - /** The encoding to use when generating the hash, defaults to 'hex' */ - hashDigest?: 'hex' | 'latin1' | 'base64'; - /** The prefix length of the hash digest to use, defaults to 20. */ - hashDigestLength?: number; - /** Algorithm used for generation the hash (see node.js crypto package) */ - hashFunction?: string | ((algorithm: string, options?: any) => any); - /** An optional salt to update the hash via Node.JS' hash.update. */ - hashSalt?: string; - /** An expression which is used to address the global object/scope in runtime code. */ - globalObject?: string; - /** Handles exceptions in module loading correctly at a performance cost. */ - strictModuleExceptionHandling?: boolean; - /** Use the future version of asset emitting logic, which is allows freeing memory of assets after emitting. It could break plugins which assume that assets are still readable after emitting. Will be the new default in the next major version. */ - futureEmitAssets?: boolean; - /** The filename of WebAssembly modules as relative path inside the `output.path` directory. */ - webassemblyModuleFilename?: string; - } + interface Output { + /** When used in tandem with output.library and output.libraryTarget, this option allows users to insert comments within the export wrapper. */ + auxiliaryComment?: string | AuxiliaryCommentObject + /** The filename of the entry chunk as relative path inside the output.path directory. */ + filename?: string | Function + /** The filename of non-entry chunks as relative path inside the output.path directory. */ + chunkFilename?: string + /** Number of milliseconds before chunk request expires, defaults to 120,000. */ + chunkLoadTimeout?: number + /** This option enables cross-origin loading of chunks. */ + crossOriginLoading?: string | boolean + /** The JSONP function used by webpack for asnyc loading of chunks. */ + jsonpFunction?: string + /** Allows customization of the script type webpack injects script tags into the DOM to download async chunks. */ + jsonpScriptType?: 'text/javascript' | 'module' + /** Filename template string of function for the sources array in a generated SourceMap. */ + devtoolModuleFilenameTemplate?: + | string + | ((info: DevtoolModuleFilenameTemplateInfo) => string) + /** Similar to output.devtoolModuleFilenameTemplate, but used in the case of duplicate module identifiers. */ + devtoolFallbackModuleFilenameTemplate?: + | string + | ((info: DevtoolModuleFilenameTemplateInfo) => string) + /** + * Enable line to line mapped mode for all/specified modules. + * Line to line mapped mode uses a simple SourceMap where each line of the generated source is mapped to the same line of the original source. + * It’s a performance optimization. Only use it if your performance need to be better and you are sure that input lines match which generated lines. + * true enables it for all modules (not recommended) + */ + devtoolLineToLine?: boolean + /** This option determines the modules namespace used with the output.devtoolModuleFilenameTemplate. */ + devtoolNamespace?: string + /** The filename of the Hot Update Chunks. They are inside the output.path directory. */ + hotUpdateChunkFilename?: string + /** The JSONP function used by webpack for async loading of hot update chunks. */ + hotUpdateFunction?: string + /** The filename of the Hot Update Main File. It is inside the output.path directory. */ + hotUpdateMainFilename?: string + /** If set, export the bundle as library. output.library is the name. */ + library?: string | string[] + /** + * Which format to export the library: + * - "var" - Export by setting a variable: var Library = xxx (default) + * - "this" - Export by setting a property of this: this["Library"] = xxx + * - "commonjs" - Export by setting a property of exports: exports["Library"] = xxx + * - "commonjs2" - Export by setting module.exports: module.exports = xxx + * - "amd" - Export to AMD (optionally named) + * - "umd" - Export to AMD, CommonJS2 or as property in root + * - "window" - Assign to window + * - "assign" - Assign to a global variable + * - "jsonp" - Generate Webpack JSONP module + */ + libraryTarget?: LibraryTarget + /** Configure which module or modules will be exposed via the `libraryTarget` */ + libraryExport?: string | string[] + /** If output.libraryTarget is set to umd and output.library is set, setting this to true will name the AMD module. */ + umdNamedDefine?: boolean + /** The output directory as absolute path. */ + path?: string + /** Include comments with information about the modules. */ + pathinfo?: boolean + /** The output.path from the view of the Javascript / HTML page. */ + publicPath?: string + /** The filename of the SourceMaps for the JavaScript files. They are inside the output.path directory. */ + sourceMapFilename?: string + /** Prefixes every line of the source in the bundle with this string. */ + sourcePrefix?: string + /** The encoding to use when generating the hash, defaults to 'hex' */ + hashDigest?: 'hex' | 'latin1' | 'base64' + /** The prefix length of the hash digest to use, defaults to 20. */ + hashDigestLength?: number + /** Algorithm used for generation the hash (see node.js crypto package) */ + hashFunction?: string | ((algorithm: string, options?: any) => any) + /** An optional salt to update the hash via Node.JS' hash.update. */ + hashSalt?: string + /** An expression which is used to address the global object/scope in runtime code. */ + globalObject?: string + /** Handles exceptions in module loading correctly at a performance cost. */ + strictModuleExceptionHandling?: boolean + /** Use the future version of asset emitting logic, which is allows freeing memory of assets after emitting. It could break plugins which assume that assets are still readable after emitting. Will be the new default in the next major version. */ + futureEmitAssets?: boolean + /** The filename of WebAssembly modules as relative path inside the `output.path` directory. */ + webassemblyModuleFilename?: string + } - type LibraryTarget = 'var' | 'assign' | 'this' | 'window' | 'global' | 'commonjs' | 'commonjs2' | 'amd' | 'umd' | 'jsonp'; - - type AuxiliaryCommentObject = { [P in LibraryTarget]: string }; - - interface Module { - /** A array of applied pre loaders. */ - preLoaders?: RuleSetRule[]; - /** A array of applied post loaders. */ - postLoaders?: RuleSetRule[]; - /** A RegExp or an array of RegExps. Don’t parse files matching. */ - noParse?: RegExp | RegExp[] | ((content: string) => boolean); - unknownContextRequest?: string; - unknownContextRecursive?: boolean; - unknownContextRegExp?: RegExp; - unknownContextCritical?: boolean; - exprContextRequest?: string; - exprContextRegExp?: RegExp; - exprContextRecursive?: boolean; - exprContextCritical?: boolean; - wrappedContextRegExp?: RegExp; - wrappedContextRecursive?: boolean; - wrappedContextCritical?: boolean; - strictExportPresence?: boolean; - /** An array of rules applied for modules. */ - rules: RuleSetRule[]; - } + type LibraryTarget = + | 'var' + | 'assign' + | 'this' + | 'window' + | 'global' + | 'commonjs' + | 'commonjs2' + | 'amd' + | 'umd' + | 'jsonp' + + type AuxiliaryCommentObject = { [P in LibraryTarget]: string } + + interface Module { + /** A array of applied pre loaders. */ + preLoaders?: RuleSetRule[] + /** A array of applied post loaders. */ + postLoaders?: RuleSetRule[] + /** A RegExp or an array of RegExps. Don’t parse files matching. */ + noParse?: RegExp | RegExp[] | ((content: string) => boolean) + unknownContextRequest?: string + unknownContextRecursive?: boolean + unknownContextRegExp?: RegExp + unknownContextCritical?: boolean + exprContextRequest?: string + exprContextRegExp?: RegExp + exprContextRecursive?: boolean + exprContextCritical?: boolean + wrappedContextRegExp?: RegExp + wrappedContextRecursive?: boolean + wrappedContextCritical?: boolean + strictExportPresence?: boolean + /** An array of rules applied for modules. */ + rules: RuleSetRule[] + } - interface Resolve { - /** - * A list of directories to resolve modules from. - * - * Absolute paths will be searched once. - * - * If an entry is relative, will be resolved using node's resolution algorithm - * relative to the requested file. - * - * Defaults to `["node_modules"]` - */ - modules?: string[]; - - /** - * A list of package description files to search for. - * - * Defaults to `["package.json"]` - */ - descriptionFiles?: string[]; - - /** - * A list of fields in a package description object to use for finding - * the entry point. - * - * Defaults to `["browser", "module", "main"]` or `["module", "main"]`, - * depending on the value of the `target` `Configuration` value. - */ - mainFields?: string[] | string[][]; - - /** - * A list of fields in a package description object to try to parse - * in the same format as the `alias` resolve option. - * - * Defaults to `["browser"]` or `[]`, depending on the value of the - * `target` `Configuration` value. - * - * @see alias - */ - aliasFields?: string[] | string[][]; - - /** - * A list of file names to search for when requiring directories that - * don't contain a package description file. - * - * Defaults to `["index"]`. - */ - mainFiles?: string[]; - - /** - * A list of file extensions to try when requesting files. - * - * An empty string is considered invalid. - */ - extensions?: string[]; - - /** - * If true, requires that all requested paths must use an extension - * from `extensions`. - */ - enforceExtension?: boolean; - - /** - * Replace the given module requests with other modules or paths. - * - * @see aliasFields - */ - alias?: { [key: string]: string; }; - - /** - * Whether to use a cache for resolving, or the specific object - * to use for caching. Sharing objects may be useful when running - * multiple webpack compilers. - * - * Defaults to `true`. - */ - unsafeCache?: {} | boolean; - - /** - * A function used to decide whether to cache the given resolve request. - * - * Defaults to `() => true`. - */ - cachePredicate?(data: { path: string, request: string }): boolean; - - /** - * A list of additional resolve plugins which should be applied. - */ - plugins?: ResolvePlugin[]; - - /** - * Whether to resolve symlinks to their symlinked location. - * - * Defaults to `true` - */ - symlinks?: boolean; - - /** - * If unsafe cache is enabled, includes request.context in the cache key. - * This option is taken into account by the enhanced-resolve module. - * Since webpack 3.1.0 context in resolve caching is ignored when resolve or resolveLoader plugins are provided. - * This addresses a performance regression. - */ - cacheWithContext?: boolean; - } + interface Resolve { + /** + * A list of directories to resolve modules from. + * + * Absolute paths will be searched once. + * + * If an entry is relative, will be resolved using node's resolution algorithm + * relative to the requested file. + * + * Defaults to `["node_modules"]` + */ + modules?: string[] + + /** + * A list of package description files to search for. + * + * Defaults to `["package.json"]` + */ + descriptionFiles?: string[] + + /** + * A list of fields in a package description object to use for finding + * the entry point. + * + * Defaults to `["browser", "module", "main"]` or `["module", "main"]`, + * depending on the value of the `target` `Configuration` value. + */ + mainFields?: string[] | string[][] + + /** + * A list of fields in a package description object to try to parse + * in the same format as the `alias` resolve option. + * + * Defaults to `["browser"]` or `[]`, depending on the value of the + * `target` `Configuration` value. + * + * @see alias + */ + aliasFields?: string[] | string[][] + + /** + * A list of file names to search for when requiring directories that + * don't contain a package description file. + * + * Defaults to `["index"]`. + */ + mainFiles?: string[] + + /** + * A list of file extensions to try when requesting files. + * + * An empty string is considered invalid. + */ + extensions?: string[] + + /** + * If true, requires that all requested paths must use an extension + * from `extensions`. + */ + enforceExtension?: boolean + + /** + * Replace the given module requests with other modules or paths. + * + * @see aliasFields + */ + alias?: { [key: string]: string } + + /** + * Whether to use a cache for resolving, or the specific object + * to use for caching. Sharing objects may be useful when running + * multiple webpack compilers. + * + * Defaults to `true`. + */ + unsafeCache?: {} | boolean + + /** + * A function used to decide whether to cache the given resolve request. + * + * Defaults to `() => true`. + */ + cachePredicate?(data: { path: string; request: string }): boolean + + /** + * A list of additional resolve plugins which should be applied. + */ + plugins?: ResolvePlugin[] + + /** + * Whether to resolve symlinks to their symlinked location. + * + * Defaults to `true` + */ + symlinks?: boolean + + /** + * If unsafe cache is enabled, includes request.context in the cache key. + * This option is taken into account by the enhanced-resolve module. + * Since webpack 3.1.0 context in resolve caching is ignored when resolve or resolveLoader plugins are provided. + * This addresses a performance regression. + */ + cacheWithContext?: boolean + } - interface ResolveLoader extends Resolve { - /** - * List of strings to append to a loader's name when trying to resolve it. - */ - moduleExtensions?: string[]; + interface ResolveLoader extends Resolve { + /** + * List of strings to append to a loader's name when trying to resolve it. + */ + moduleExtensions?: string[] - enforceModuleExtension?: boolean; - } + enforceModuleExtension?: boolean + } - /** - * This interface was referenced by `WebpackOptions`'s JSON-Schema - * via the `definition` "Externals". - */ - export type Externals = - | (( - context: string, - request: string, - callback: (err?: Error, result?: string) => void + /** + * This interface was referenced by `WebpackOptions`'s JSON-Schema + * via the `definition` "Externals". + */ + export type Externals = + | (( + context: string, + request: string, + callback: (err?: Error, result?: string) => void + ) => void) + | ExternalItem + | ( + | (( + context: string, + request: string, + callback: (err?: Error, result?: string) => void ) => void) - | ExternalItem - | ( - | (( - context: string, - request: string, - callback: (err?: Error, result?: string) => void - ) => void) - | ExternalItem)[]; - /** - * This interface was referenced by `WebpackOptions`'s JSON-Schema - * via the `definition` "ExternalItem". - */ - export type ExternalItem = - | string - | { - /** - * The dependency used for the external - */ - [k: string]: - | string - | { - [k: string]: any; - } - | ArrayOfStringValues - | boolean; - } - | RegExp; - /** - * This interface was referenced by `WebpackOptions`'s JSON-Schema - * via the `definition` "ArrayOfStringValues". - */ - export type ArrayOfStringValues = string[]; - - interface Node { - console?: boolean | 'mock'; - process?: boolean | 'mock'; - global?: boolean; - __filename?: boolean | 'mock'; - __dirname?: boolean | 'mock'; - Buffer?: boolean | 'mock'; - setImmediate?: boolean | 'mock' | 'empty'; - [nodeBuiltin: string]: boolean | 'mock' | 'empty' | undefined; - } - - interface NewLoader { - loader: string; - options?: { [name: string]: any }; - } - type Loader = string | NewLoader; - - interface ParserOptions { - [optName: string]: any; - system?: boolean; - } - - type RuleSetCondition = - | RegExp + | ExternalItem)[] + /** + * This interface was referenced by `WebpackOptions`'s JSON-Schema + * via the `definition` "ExternalItem". + */ + export type ExternalItem = + | string + | { + /** + * The dependency used for the external + */ + [k: string]: | string - | ((path: string) => boolean) - | RuleSetConditions | { - /** - * Logical AND - */ - and?: RuleSetCondition[]; - /** - * Exclude all modules matching any of these conditions - */ - exclude?: RuleSetCondition; - /** - * Exclude all modules matching not any of these conditions - */ - include?: RuleSetCondition; - /** - * Logical NOT - */ - not?: RuleSetCondition[]; - /** - * Logical OR - */ - or?: RuleSetCondition[]; - /** - * Exclude all modules matching any of these conditions - */ - test?: RuleSetCondition; - }; - - // A hack around circular type referencing - interface RuleSetConditions extends Array<RuleSetCondition> {} - - interface RuleSetRule { - /** - * Enforce this rule as pre or post step - */ - enforce?: "pre" | "post"; - /** - * Shortcut for resource.exclude - */ - exclude?: RuleSetCondition; - /** - * Shortcut for resource.include - */ - include?: RuleSetCondition; - /** - * Match the issuer of the module (The module pointing to this module) - */ - issuer?: RuleSetCondition; - /** - * Shortcut for use.loader - */ - loader?: RuleSetUse; - /** - * Shortcut for use.loader - */ - loaders?: RuleSetUse; - /** - * Only execute the first matching rule in this array - */ - oneOf?: RuleSetRule[]; - /** - * Shortcut for use.options - */ - options?: RuleSetQuery; - /** - * Options for parsing - */ - parser?: { [k: string]: any }; - /** - * Options for the resolver - */ - resolve?: Resolve; - /** - * Flags a module as with or without side effects - */ - sideEffects?: boolean; - /** - * Shortcut for use.query - */ - query?: RuleSetQuery; - /** - * Module type to use for the module - */ - type?: "javascript/auto" | "javascript/dynamic" | "javascript/esm" | "json" | "webassembly/experimental"; - /** - * Match the resource path of the module - */ - resource?: RuleSetCondition; - /** - * Match the resource query of the module - */ - resourceQuery?: RuleSetCondition; - /** - * Match the child compiler name - */ - compiler?: RuleSetCondition; - /** - * Match and execute these rules when this rule is matched - */ - rules?: RuleSetRule[]; - /** - * Shortcut for resource.test - */ - test?: RuleSetCondition; - /** - * Modifiers applied to the module when rule is matched - */ - use?: RuleSetUse; + [k: string]: any + } + | ArrayOfStringValues + | boolean } + | RegExp + /** + * This interface was referenced by `WebpackOptions`'s JSON-Schema + * via the `definition` "ArrayOfStringValues". + */ + export type ArrayOfStringValues = string[] + + interface Node { + console?: boolean | 'mock' + process?: boolean | 'mock' + global?: boolean + __filename?: boolean | 'mock' + __dirname?: boolean | 'mock' + Buffer?: boolean | 'mock' + setImmediate?: boolean | 'mock' | 'empty' + [nodeBuiltin: string]: boolean | 'mock' | 'empty' | undefined + } - type RuleSetUse = - | RuleSetUseItem - | RuleSetUseItem[] - | ((data: any) => RuleSetUseItem | RuleSetUseItem[]); - - interface RuleSetLoader { - /** - * Loader name - */ - loader?: string; - /** - * Loader options - */ - options?: RuleSetQuery; - /** - * Unique loader identifier - */ - ident?: string; - /** - * Loader query - */ - query?: RuleSetQuery; + interface NewLoader { + loader: string + options?: { [name: string]: any } + } + type Loader = string | NewLoader + + interface ParserOptions { + [optName: string]: any + system?: boolean + } + + type RuleSetCondition = + | RegExp + | string + | ((path: string) => boolean) + | RuleSetConditions + | { + /** + * Logical AND + */ + and?: RuleSetCondition[] + /** + * Exclude all modules matching any of these conditions + */ + exclude?: RuleSetCondition + /** + * Exclude all modules matching not any of these conditions + */ + include?: RuleSetCondition + /** + * Logical NOT + */ + not?: RuleSetCondition[] + /** + * Logical OR + */ + or?: RuleSetCondition[] + /** + * Exclude all modules matching any of these conditions + */ + test?: RuleSetCondition } - type RuleSetUseItem = - | string - | RuleSetLoader - | ((data: any) => string | RuleSetLoader); + // A hack around circular type referencing + interface RuleSetConditions extends Array<RuleSetCondition> {} + + interface RuleSetRule { + /** + * Enforce this rule as pre or post step + */ + enforce?: 'pre' | 'post' + /** + * Shortcut for resource.exclude + */ + exclude?: RuleSetCondition + /** + * Shortcut for resource.include + */ + include?: RuleSetCondition + /** + * Match the issuer of the module (The module pointing to this module) + */ + issuer?: RuleSetCondition + /** + * Shortcut for use.loader + */ + loader?: RuleSetUse + /** + * Shortcut for use.loader + */ + loaders?: RuleSetUse + /** + * Only execute the first matching rule in this array + */ + oneOf?: RuleSetRule[] + /** + * Shortcut for use.options + */ + options?: RuleSetQuery + /** + * Options for parsing + */ + parser?: { [k: string]: any } + /** + * Options for the resolver + */ + resolve?: Resolve + /** + * Flags a module as with or without side effects + */ + sideEffects?: boolean + /** + * Shortcut for use.query + */ + query?: RuleSetQuery + /** + * Module type to use for the module + */ + type?: + | 'javascript/auto' + | 'javascript/dynamic' + | 'javascript/esm' + | 'json' + | 'webassembly/experimental' + /** + * Match the resource path of the module + */ + resource?: RuleSetCondition + /** + * Match the resource query of the module + */ + resourceQuery?: RuleSetCondition + /** + * Match the child compiler name + */ + compiler?: RuleSetCondition + /** + * Match and execute these rules when this rule is matched + */ + rules?: RuleSetRule[] + /** + * Shortcut for resource.test + */ + test?: RuleSetCondition + /** + * Modifiers applied to the module when rule is matched + */ + use?: RuleSetUse + } - type RuleSetQuery = - | string - | { [k: string]: any }; + type RuleSetUse = + | RuleSetUseItem + | RuleSetUseItem[] + | ((data: any) => RuleSetUseItem | RuleSetUseItem[]) + + interface RuleSetLoader { + /** + * Loader name + */ + loader?: string + /** + * Loader options + */ + options?: RuleSetQuery + /** + * Unique loader identifier + */ + ident?: string + /** + * Loader query + */ + query?: RuleSetQuery + } + type RuleSetUseItem = + | string + | RuleSetLoader + | ((data: any) => string | RuleSetLoader) + + type RuleSetQuery = string | { [k: string]: any } + + /** + * @deprecated Use RuleSetCondition instead + */ + type Condition = RuleSetCondition + + /** + * @deprecated Use RuleSetRule instead + */ + type Rule = RuleSetRule + + namespace Options { + // tslint:disable-next-line:max-line-length + type Devtool = + | 'eval' + | 'inline-source-map' + | 'cheap-eval-source-map' + | 'cheap-source-map' + | 'cheap-module-eval-source-map' + | 'cheap-module-source-map' + | 'eval-source-map' + | 'source-map' + | 'nosources-source-map' + | 'hidden-source-map' + | 'nosources-source-map' + | 'inline-cheap-source-map' + | 'inline-cheap-module-source-map' + | '@eval' + | '@inline-source-map' + | '@cheap-eval-source-map' + | '@cheap-source-map' + | '@cheap-module-eval-source-map' + | '@cheap-module-source-map' + | '@eval-source-map' + | '@source-map' + | '@nosources-source-map' + | '@hidden-source-map' + | '@nosources-source-map' + | '#eval' + | '#inline-source-map' + | '#cheap-eval-source-map' + | '#cheap-source-map' + | '#cheap-module-eval-source-map' + | '#cheap-module-source-map' + | '#eval-source-map' + | '#source-map' + | '#nosources-source-map' + | '#hidden-source-map' + | '#nosources-source-map' + | '#@eval' + | '#@inline-source-map' + | '#@cheap-eval-source-map' + | '#@cheap-source-map' + | '#@cheap-module-eval-source-map' + | '#@cheap-module-source-map' + | '#@eval-source-map' + | '#@source-map' + | '#@nosources-source-map' + | '#@hidden-source-map' + | '#@nosources-source-map' + | boolean + + interface Performance { + /** This property allows webpack to control what files are used to calculate performance hints. */ + assetFilter?(assetFilename: string): boolean /** - * @deprecated Use RuleSetCondition instead + * Turns hints on/off. In addition, tells webpack to throw either an error or a warning when hints are + * found. This property is set to "warning" by default. */ - type Condition = RuleSetCondition; - + hints?: 'warning' | 'error' | false /** - * @deprecated Use RuleSetRule instead + * An asset is any emitted file from webpack. This option controls when webpack emits a performance hint + * based on individual asset size. The default value is 250000 (bytes). */ - type Rule = RuleSetRule; - - namespace Options { - // tslint:disable-next-line:max-line-length - type Devtool = 'eval' | 'inline-source-map' | 'cheap-eval-source-map' | 'cheap-source-map' | 'cheap-module-eval-source-map' | 'cheap-module-source-map' | 'eval-source-map' - | 'source-map' | 'nosources-source-map' | 'hidden-source-map' | 'nosources-source-map' | 'inline-cheap-source-map' | 'inline-cheap-module-source-map' | '@eval' - | '@inline-source-map' | '@cheap-eval-source-map' | '@cheap-source-map' | '@cheap-module-eval-source-map' | '@cheap-module-source-map' | '@eval-source-map' - | '@source-map' | '@nosources-source-map' | '@hidden-source-map' | '@nosources-source-map' | '#eval' | '#inline-source-map' | '#cheap-eval-source-map' - | '#cheap-source-map' | '#cheap-module-eval-source-map' | '#cheap-module-source-map' | '#eval-source-map' | '#source-map' | '#nosources-source-map' - | '#hidden-source-map' | '#nosources-source-map' | '#@eval' | '#@inline-source-map' | '#@cheap-eval-source-map' | '#@cheap-source-map' | '#@cheap-module-eval-source-map' - | '#@cheap-module-source-map' | '#@eval-source-map' | '#@source-map' | '#@nosources-source-map' | '#@hidden-source-map' | '#@nosources-source-map' | boolean; - - interface Performance { - /** This property allows webpack to control what files are used to calculate performance hints. */ - assetFilter?(assetFilename: string): boolean; - /** - * Turns hints on/off. In addition, tells webpack to throw either an error or a warning when hints are - * found. This property is set to "warning" by default. - */ - hints?: 'warning' | 'error' | false; - /** - * An asset is any emitted file from webpack. This option controls when webpack emits a performance hint - * based on individual asset size. The default value is 250000 (bytes). - */ - maxAssetSize?: number; - /** - * An entrypoint represents all assets that would be utilized during initial load time for a specific entry. - * This option controls when webpack should emit performance hints based on the maximum entrypoint size. - * The default value is 250000 (bytes). - */ - maxEntrypointSize?: number; - } - type Stats = Stats.ToStringOptions; - type WatchOptions = ICompiler.WatchOptions; - interface CacheGroupsOptions { - /** Assign modules to a cache group */ - test?: ((...args: any[]) => boolean) | string | RegExp; - /** Select chunks for determining cache group content (defaults to \"initial\", \"initial\" and \"all\" requires adding these chunks to the HTML) */ - chunks?: "initial" | "async" | "all" | ((chunk: compilation.Chunk) => boolean); - /** Ignore minimum size, minimum chunks and maximum requests and always create chunks for this cache group */ - enforce?: boolean; - /** Priority of this cache group */ - priority?: number; - /** Minimal size for the created chunk */ - minSize?: number; - /** Maximum size for the created chunk */ - maxSize?: number; - /** Minimum number of times a module has to be duplicated until it's considered for splitting */ - minChunks?: number; - /** Maximum number of requests which are accepted for on-demand loading */ - maxAsyncRequests?: number; - /** Maximum number of initial chunks which are accepted for an entry point */ - maxInitialRequests?: number; - /** Try to reuse existing chunk (with name) when it has matching modules */ - reuseExistingChunk?: boolean; - /** Give chunks created a name (chunks with equal name are merged) */ - name?: boolean | string | ((...args: any[]) => any); - } - interface SplitChunksOptions { - /** Select chunks for determining shared modules (defaults to \"async\", \"initial\" and \"all\" requires adding these chunks to the HTML) */ - chunks?: "initial" | "async" | "all" | ((chunk: compilation.Chunk) => boolean); - /** Minimal size for the created chunk */ - minSize?: number; - /** Maximum size for the created chunk */ - maxSize?: number; - /** Minimum number of times a module has to be duplicated until it's considered for splitting */ - minChunks?: number; - /** Maximum number of requests which are accepted for on-demand loading */ - maxAsyncRequests?: number; - /** Maximum number of initial chunks which are accepted for an entry point */ - maxInitialRequests?: number; - /** Give chunks created a name (chunks with equal name are merged) */ - name?: boolean | string | ((...args: any[]) => any); - /** Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks) */ - cacheGroups?: false | string | ((...args: any[]) => any) | RegExp | { [key: string]: CacheGroupsOptions | false }; - } - interface RuntimeChunkOptions { - /** The name or name factory for the runtime chunks. */ - name?: string | ((...args: any[]) => any); - } - interface Optimization { - /** - * Modules are removed from chunks when they are already available in all parent chunk groups. - * This reduces asset size. Smaller assets also result in faster builds since less code generation has to be performed. - */ - removeAvailableModules?: boolean; - /** Empty chunks are removed. This reduces load in filesystem and results in faster builds. */ - removeEmptyChunks?: boolean; - /** Equal chunks are merged. This results in less code generation and faster builds. */ - mergeDuplicateChunks?: boolean; - /** Chunks which are subsets of other chunks are determined and flagged in a way that subsets don’t have to be loaded when the bigger chunk has been loaded. */ - flagIncludedChunks?: boolean; - /** Give more often used ids smaller (shorter) values. */ - occurrenceOrder?: boolean; - /** Determine exports for each module when possible. This information is used by other optimizations or code generation. I. e. to generate more efficient code for export * from. */ - providedExports?: boolean; - /** - * Determine used exports for each module. This depends on optimization.providedExports. This information is used by other optimizations or code generation. - * I. e. exports are not generated for unused exports, export names are mangled to single char identifiers when all usages are compatible. - * DCE in minimizers will benefit from this and can remove unused exports. - */ - usedExports?: boolean; - /** - * Recognise the sideEffects flag in package.json or rules to eliminate modules. This depends on optimization.providedExports and optimization.usedExports. - * These dependencies have a cost, but eliminating modules has positive impact on performance because of less code generation. It depends on your codebase. - * Try it for possible performance wins. - */ - sideEffects?: boolean; - /** Tries to find segments of the module graph which can be safely concatenated into a single module. Depends on optimization.providedExports and optimization.usedExports. */ - concatenateModules?: boolean; - /** Finds modules which are shared between chunk and splits them into separate chunks to reduce duplication or separate vendor modules from application modules. */ - splitChunks?: SplitChunksOptions | false; - /** Create a separate chunk for the webpack runtime code and chunk hash maps. This chunk should be inlined into the HTML */ - runtimeChunk?: boolean | "single" | "multiple" | RuntimeChunkOptions; - /** Avoid emitting assets when errors occur. */ - noEmitOnErrors?: boolean; - /** Instead of numeric ids, give modules readable names for better debugging. */ - namedModules?: boolean; - /** Instead of numeric ids, give chunks readable names for better debugging. */ - namedChunks?: boolean; - /** Defines the process.env.NODE_ENV constant to a compile-time-constant value. This allows to remove development only code from code. */ - nodeEnv?: string | false; - /** Use the minimizer (optimization.minimizer, by default uglify-js) to minimize output assets. */ - minimize?: boolean; - /** Minimizer(s) to use for minimizing the output */ - minimizer?: Array<Plugin | Tapable.Plugin>; - /** Generate records with relative paths to be able to move the context folder". */ - portableRecords?: boolean; - /** Tells webpack which algorithm to use when choosing chunk ids. */ - chunkIds?: false | 'natural' | 'named'| 'size' | 'total-size' - } - } + maxAssetSize?: number + /** + * An entrypoint represents all assets that would be utilized during initial load time for a specific entry. + * This option controls when webpack should emit performance hints based on the maximum entrypoint size. + * The default value is 250000 (bytes). + */ + maxEntrypointSize?: number + } + type Stats = Stats.ToStringOptions + type WatchOptions = ICompiler.WatchOptions + interface CacheGroupsOptions { + /** Assign modules to a cache group */ + test?: ((...args: any[]) => boolean) | string | RegExp + /** Select chunks for determining cache group content (defaults to \"initial\", \"initial\" and \"all\" requires adding these chunks to the HTML) */ + chunks?: + | 'initial' + | 'async' + | 'all' + | ((chunk: compilation.Chunk) => boolean) + /** Ignore minimum size, minimum chunks and maximum requests and always create chunks for this cache group */ + enforce?: boolean + /** Priority of this cache group */ + priority?: number + /** Minimal size for the created chunk */ + minSize?: number + /** Maximum size for the created chunk */ + maxSize?: number + /** Minimum number of times a module has to be duplicated until it's considered for splitting */ + minChunks?: number + /** Maximum number of requests which are accepted for on-demand loading */ + maxAsyncRequests?: number + /** Maximum number of initial chunks which are accepted for an entry point */ + maxInitialRequests?: number + /** Try to reuse existing chunk (with name) when it has matching modules */ + reuseExistingChunk?: boolean + /** Give chunks created a name (chunks with equal name are merged) */ + name?: boolean | string | ((...args: any[]) => any) + } + interface SplitChunksOptions { + /** Select chunks for determining shared modules (defaults to \"async\", \"initial\" and \"all\" requires adding these chunks to the HTML) */ + chunks?: + | 'initial' + | 'async' + | 'all' + | ((chunk: compilation.Chunk) => boolean) + /** Minimal size for the created chunk */ + minSize?: number + /** Maximum size for the created chunk */ + maxSize?: number + /** Minimum number of times a module has to be duplicated until it's considered for splitting */ + minChunks?: number + /** Maximum number of requests which are accepted for on-demand loading */ + maxAsyncRequests?: number + /** Maximum number of initial chunks which are accepted for an entry point */ + maxInitialRequests?: number + /** Give chunks created a name (chunks with equal name are merged) */ + name?: boolean | string | ((...args: any[]) => any) + /** Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks) */ + cacheGroups?: + | false + | string + | ((...args: any[]) => any) + | RegExp + | { [key: string]: CacheGroupsOptions | false } + } + interface RuntimeChunkOptions { + /** The name or name factory for the runtime chunks. */ + name?: string | ((...args: any[]) => any) + } + interface Optimization { + /** + * Modules are removed from chunks when they are already available in all parent chunk groups. + * This reduces asset size. Smaller assets also result in faster builds since less code generation has to be performed. + */ + removeAvailableModules?: boolean + /** Empty chunks are removed. This reduces load in filesystem and results in faster builds. */ + removeEmptyChunks?: boolean + /** Equal chunks are merged. This results in less code generation and faster builds. */ + mergeDuplicateChunks?: boolean + /** Chunks which are subsets of other chunks are determined and flagged in a way that subsets don’t have to be loaded when the bigger chunk has been loaded. */ + flagIncludedChunks?: boolean + /** Give more often used ids smaller (shorter) values. */ + occurrenceOrder?: boolean + /** Determine exports for each module when possible. This information is used by other optimizations or code generation. I. e. to generate more efficient code for export * from. */ + providedExports?: boolean + /** + * Determine used exports for each module. This depends on optimization.providedExports. This information is used by other optimizations or code generation. + * I. e. exports are not generated for unused exports, export names are mangled to single char identifiers when all usages are compatible. + * DCE in minimizers will benefit from this and can remove unused exports. + */ + usedExports?: boolean + /** + * Recognise the sideEffects flag in package.json or rules to eliminate modules. This depends on optimization.providedExports and optimization.usedExports. + * These dependencies have a cost, but eliminating modules has positive impact on performance because of less code generation. It depends on your codebase. + * Try it for possible performance wins. + */ + sideEffects?: boolean + /** Tries to find segments of the module graph which can be safely concatenated into a single module. Depends on optimization.providedExports and optimization.usedExports. */ + concatenateModules?: boolean + /** Finds modules which are shared between chunk and splits them into separate chunks to reduce duplication or separate vendor modules from application modules. */ + splitChunks?: SplitChunksOptions | false + /** Create a separate chunk for the webpack runtime code and chunk hash maps. This chunk should be inlined into the HTML */ + runtimeChunk?: boolean | 'single' | 'multiple' | RuntimeChunkOptions + /** Avoid emitting assets when errors occur. */ + noEmitOnErrors?: boolean + /** Instead of numeric ids, give modules readable names for better debugging. */ + namedModules?: boolean + /** Instead of numeric ids, give chunks readable names for better debugging. */ + namedChunks?: boolean + /** Defines the process.env.NODE_ENV constant to a compile-time-constant value. This allows to remove development only code from code. */ + nodeEnv?: string | false + /** Use the minimizer (optimization.minimizer, by default uglify-js) to minimize output assets. */ + minimize?: boolean + /** Minimizer(s) to use for minimizing the output */ + minimizer?: Array<Plugin | Tapable.Plugin> + /** Generate records with relative paths to be able to move the context folder". */ + portableRecords?: boolean + /** Tells webpack which algorithm to use when choosing chunk ids. */ + chunkIds?: false | 'natural' | 'named' | 'size' | 'total-size' + } + } - namespace debug { - interface ProfilingPluginOptions { - /** A relative path to a custom output file (json) */ - outputPath?: string; - } - /** - * Generate Chrome profile file which includes timings of plugins execution. Outputs `events.json` file by - * default. It is possible to provide custom file path using `outputPath` option. - * - * In order to view the profile file: - * * Run webpack with ProfilingPlugin. - * * Go to Chrome, open the Profile Tab. - * * Drag and drop generated file (events.json by default) into the profiler. - * - * It will then display timeline stats and calls per plugin! - */ - class ProfilingPlugin extends Plugin { - constructor(options?: ProfilingPluginOptions); - } + namespace debug { + interface ProfilingPluginOptions { + /** A relative path to a custom output file (json) */ + outputPath?: string + } + /** + * Generate Chrome profile file which includes timings of plugins execution. Outputs `events.json` file by + * default. It is possible to provide custom file path using `outputPath` option. + * + * In order to view the profile file: + * * Run webpack with ProfilingPlugin. + * * Go to Chrome, open the Profile Tab. + * * Drag and drop generated file (events.json by default) into the profiler. + * + * It will then display timeline stats and calls per plugin! + */ + class ProfilingPlugin extends Plugin { + constructor(options?: ProfilingPluginOptions) + } + } + namespace compilation { + class Asset {} + + class Module {} + + class Record {} + + class Chunk { + constructor(name: string) + id: any + ids: any + debugId: number + name: any + entryModule: any + files: any[] + rendered: boolean + hash: any + renderedHash: any + chunkReason: any + extraAsync: boolean + + hasRuntime(): boolean + canBeInitial(): boolean + isOnlyInitial(): boolean + hasEntryModule(): boolean + + addModule(module: any): boolean + removeModule(module: any): boolean + setModules(modules: any): void + getNumberOfModules(): number + modulesIterable: any[] + + addGroup(chunkGroup: any): boolean + removeGroup(chunkGroup: any): boolean + isInGroup(chunkGroup: any): boolean + getNumberOfGroups(): number + groupsIterable: any[] + + compareTo(otherChunk: any): -1 | 0 | 1 + containsModule(module: any): boolean + getModules(): any[] + getModulesIdent(): any[] + remove(reason: any): void + moveModule(module: any, otherChunk: any): void + integrate(otherChunk: any, reason: any): boolean + split(newChunk: any): void + isEmpty(): boolean + updateHash(hash: any): void + canBeIntegrated(otherChunk: any): boolean + addMultiplierAndOverhead(size: number, options: any): number + modulesSize(): number + size(options: any): number + integratedSize(otherChunk: any, options: any): number + // tslint:disable-next-line:ban-types + sortModules(sortByFn: Function): void + getAllAsyncChunks(): Set<any> + getChunkMaps(realHash: any): { hash: any; name: any } + // tslint:disable-next-line:ban-types + getChunkModuleMaps(filterFn: Function): { id: any; hash: any } + // tslint:disable-next-line:ban-types + hasModuleInGraph(filterFn: Function, filterChunkFn: Function): boolean + toString(): string + } + + class ChunkGroup {} + + class ChunkHash {} + + class Dependency { + constructor() + getResourceIdentifier(): any + getReference(): any + getExports(): any + getWarnings(): any + getErrors(): any + updateHash(hash: any): void + disconnect(): void + static compare(a: any, b: any): any + } + + interface NormalModuleFactoryHooks { + resolver: SyncWaterfallHook + factory: SyncWaterfallHook + beforeResolve: AsyncSeriesWaterfallHook + afterResolve: AsyncSeriesWaterfallHook + createModule: SyncBailHook + module: SyncWaterfallHook + createParser: HookMap + parser: HookMap + createGenerator: HookMap + generator: HookMap + } + + class NormalModuleFactory extends Tapable { + hooks: NormalModuleFactoryHooks + } + + interface ContextModuleFactoryHooks { + beforeResolve: AsyncSeriesWaterfallHook + afterResolve: AsyncSeriesWaterfallHook + contextModuleFiles: SyncWaterfallHook + alternatives: AsyncSeriesWaterfallHook + } + + class ContextModuleFactory extends Tapable { + hooks: ContextModuleFactoryHooks + } + + class DllModuleFactory extends Tapable { + hooks: {} + } + + interface CompilationHooks { + buildModule: SyncHook<Module> + rebuildModule: SyncHook<Module> + failedModule: SyncHook<Module, Error> + succeedModule: SyncHook<Module> + + finishModules: SyncHook<Module[]> + finishRebuildingModule: SyncHook<Module> + + unseal: SyncHook + seal: SyncHook + + optimizeDependenciesBasic: SyncBailHook<Module[]> + optimizeDependencies: SyncBailHook<Module[]> + optimizeDependenciesAdvanced: SyncBailHook<Module[]> + afterOptimizeDependencies: SyncHook<Module[]> + + optimize: SyncHook + + optimizeModulesBasic: SyncBailHook<Module[]> + optimizeModules: SyncBailHook<Module[]> + optimizeModulesAdvanced: SyncBailHook<Module[]> + afterOptimizeModules: SyncHook<Module[]> + + optimizeChunksBasic: SyncBailHook<Chunk[], ChunkGroup[]> + optimizeChunks: SyncBailHook<Chunk[], ChunkGroup[]> + optimizeChunksAdvanced: SyncBailHook<Chunk[], ChunkGroup[]> + afterOptimizeChunks: SyncHook<Chunk[], ChunkGroup[]> + + optimizeTree: AsyncSeriesHook<Chunk[], Module[]> + afterOptimizeTree: SyncHook<Chunk[], Module[]> + + optimizeChunkModulesBasic: SyncBailHook<Chunk[], Module[]> + optimizeChunkModules: SyncBailHook<Chunk[], Module[]> + optimizeChunkModulesAdvanced: SyncBailHook<Chunk[], Module[]> + afterOptimizeChunkModules: SyncHook<Chunk[], Module[]> + shouldRecord: SyncBailHook + + reviveModules: SyncHook<Module[], Record[]> + optimizeModuleOrder: SyncHook<Module[]> + advancedOptimizeModuleOrder: SyncHook<Module[]> + beforeModuleIds: SyncHook<Module[]> + moduleIds: SyncHook<Module[]> + optimizeModuleIds: SyncHook<Module[]> + afterOptimizeModuleIds: SyncHook<Module[]> + + reviveChunks: SyncHook<Chunk[], Record[]> + optimizeChunkOrder: SyncHook<Chunk[]> + beforeChunkIds: SyncHook<Chunk[]> + optimizeChunkIds: SyncHook<Chunk[]> + afterOptimizeChunkIds: SyncHook<Chunk[]> + + recordModules: SyncHook<Module[], Record[]> + recordChunks: SyncHook<Chunk[], Record[]> + + beforeHash: SyncHook + afterHash: SyncHook + + recordHash: SyncHook<Record[]> + + record: SyncHook<Compilation, Record[]> + + beforeModuleAssets: SyncHook + shouldGenerateChunkAssets: SyncBailHook + beforeChunkAssets: SyncHook + additionalChunkAssets: SyncHook<Chunk[]> + + records: SyncHook<Compilation, Record[]> + + additionalAssets: AsyncSeriesHook + optimizeChunkAssets: AsyncSeriesHook<Chunk[]> + afterOptimizeChunkAssets: SyncHook<Chunk[]> + optimizeAssets: AsyncSeriesHook<Asset[]> + afterOptimizeAssets: SyncHook<Asset[]> + + needAdditionalSeal: SyncBailHook + afterSeal: AsyncSeriesHook + + chunkHash: SyncHook<Chunk, ChunkHash> + moduleAsset: SyncHook<Module, string> + chunkAsset: SyncHook<Chunk, string> + + assetPath: SyncWaterfallHook<string> + + needAdditionalPass: SyncBailHook + childCompiler: SyncHook + + normalModuleLoader: SyncHook<any, Module> + + optimizeExtractedChunksBasic: SyncBailHook<Chunk[]> + optimizeExtractedChunks: SyncBailHook<Chunk[]> + optimizeExtractedChunksAdvanced: SyncBailHook<Chunk[]> + afterOptimizeExtractedChunks: SyncHook<Chunk[]> + } + + interface CompilationModule { + module: any + issuer: boolean + build: boolean + dependencies: boolean + } + + class MainTemplate extends Tapable {} + class ChunkTemplate extends Tapable {} + class HotUpdateChunkTemplate extends Tapable {} + class RuntimeTemplate {} + + interface ModuleTemplateHooks { + content: SyncWaterfallHook + module: SyncWaterfallHook + render: SyncWaterfallHook + package: SyncWaterfallHook + hash: SyncHook + } + + class ModuleTemplate extends Tapable { + hooks: ModuleTemplateHooks + } + + class Compilation extends Tapable { + hooks: CompilationHooks + compiler: Compiler + + resolverFactory: any + inputFileSystem: any + requestShortener: any + + outputOptions: any + bail: any + profile: any + performance: any + + mainTemplate: MainTemplate + chunkTemplate: ChunkTemplate + hotUpdateChunkTemplate: HotUpdateChunkTemplate + runtimeTemplate: RuntimeTemplate + moduleTemplates: { + javascript: ModuleTemplate + webassembly: ModuleTemplate } - namespace compilation { - class Asset { - } - class Module { - } - - class Record { - } - - class Chunk { - constructor(name: string); - id: any; - ids: any; - debugId: number; - name: any; - entryModule: any; - files: any[]; - rendered: boolean; - hash: any; - renderedHash: any; - chunkReason: any; - extraAsync: boolean; - - hasRuntime(): boolean; - canBeInitial(): boolean; - isOnlyInitial(): boolean; - hasEntryModule(): boolean; - - addModule(module: any): boolean; - removeModule(module: any): boolean; - setModules(modules: any): void; - getNumberOfModules(): number; - modulesIterable: any[]; - - addGroup(chunkGroup: any): boolean; - removeGroup(chunkGroup: any): boolean; - isInGroup(chunkGroup: any): boolean; - getNumberOfGroups(): number; - groupsIterable: any[]; - - compareTo(otherChunk: any): -1 | 0 | 1; - containsModule(module: any): boolean; - getModules(): any[]; - getModulesIdent(): any[]; - remove(reason: any): void; - moveModule(module: any, otherChunk: any): void; - integrate(otherChunk: any, reason: any): boolean; - split(newChunk: any): void; - isEmpty(): boolean; - updateHash(hash: any): void; - canBeIntegrated(otherChunk: any): boolean; - addMultiplierAndOverhead(size: number, options: any): number; - modulesSize(): number; - size(options: any): number; - integratedSize(otherChunk: any, options: any): number; - // tslint:disable-next-line:ban-types - sortModules(sortByFn: Function): void; - getAllAsyncChunks(): Set<any>; - getChunkMaps(realHash: any): { hash: any, name: any }; - // tslint:disable-next-line:ban-types - getChunkModuleMaps(filterFn: Function): { id: any, hash: any }; - // tslint:disable-next-line:ban-types - hasModuleInGraph(filterFn: Function, filterChunkFn: Function): boolean; - toString(): string; - } + entries: any[] + _preparedEntrypoints: any[] + entrypoints: Map<any, any> + chunks: any[] + chunkGroups: any[] + namedChunkGroups: Map<any, any> + namedChunks: Map<any, any> + modules: any[] + _modules: Map<any, any> + cache: any + records: any + nextFreeModuleIndex: any + nextFreeModuleIndex2: any + additionalChunkAssets: any[] + assets: any + errors: any[] + warnings: any[] + children: any[] + dependencyFactories: Map<typeof Dependency, Tapable> + dependencyTemplates: Map<typeof Dependency, Tapable> + childrenCounters: any + usedChunkIds: any + usedModuleIds: any + fileTimestamps: Map<string, number> + contextTimestamps: Map<string, number> + fileDependencies: SortableSet<string> + contextDependencies: SortableSet<string> + missingDependencies: SortableSet<string> + hash?: string + getStats(): Stats + addModule(module: CompilationModule, cacheGroup: any): any + // tslint:disable-next-line:ban-types + addEntry(context: any, entry: any, name: any, callback: Function): void + getPath( + filename: string, + data: { + hash?: any + chunk?: any + filename?: string + basename?: string + query?: any + } + ): string + /** + * @deprecated Compilation.applyPlugins is deprecated. Use new API on `.hooks` instead + */ + applyPlugins(name: string, ...args: any[]): void + } + + interface CompilerHooks { + shouldEmit: SyncBailHook<Compilation> + done: AsyncSeriesHook<Stats> + additionalPass: AsyncSeriesHook + beforeRun: AsyncSeriesHook<Compiler> + run: AsyncSeriesHook<Compiler> + emit: AsyncSeriesHook<Compilation> + afterEmit: AsyncSeriesHook<Compilation> + thisCompilation: SyncHook< + Compilation, + { normalModuleFactory: NormalModuleFactory } + > + compilation: SyncHook< + Compilation, + { normalModuleFactory: NormalModuleFactory } + > + normalModuleFactory: SyncHook<NormalModuleFactory> + contextModuleFactory: SyncHook<ContextModuleFactory> + beforeCompile: AsyncSeriesHook<{}> + compile: SyncHook<{}> + make: AsyncParallelHook<Compilation> + afterCompile: AsyncSeriesHook<Compilation> + watchRun: AsyncSeriesHook<Compiler> + failed: SyncHook<Error> + invalid: SyncHook<string, Date> + watchClose: SyncHook + environment: SyncHook + afterEnvironment: SyncHook + afterPlugins: SyncHook<Compiler> + afterResolvers: SyncHook<Compiler> + entryOption: SyncBailHook + } + } + // tslint:disable-next-line:interface-name + interface ICompiler { + run(handler: ICompiler.Handler): void + watch( + watchOptions: ICompiler.WatchOptions, + handler: ICompiler.Handler + ): Watching + } - class ChunkGroup { - } + namespace ICompiler { + type Handler = (err: Error, stats: Stats) => void - class ChunkHash { - } + interface WatchOptions { + /** + * Add a delay before rebuilding once the first file changed. This allows webpack to aggregate any other + * changes made during this time period into one rebuild. + * Pass a value in milliseconds. Default: 300. + */ + aggregateTimeout?: number + /** + * For some systems, watching many file systems can result in a lot of CPU or memory usage. + * It is possible to exclude a huge folder like node_modules. + * It is also possible to use anymatch patterns. + */ + ignored?: anymatch.Matcher + /** Turn on polling by passing true, or specifying a poll interval in milliseconds. */ + poll?: boolean | number + } + } - class Dependency { - constructor(); - getResourceIdentifier(): any; - getReference(): any; - getExports(): any; - getWarnings(): any; - getErrors(): any; - updateHash(hash: any): void; - disconnect(): void; - static compare(a: any, b: any): any; - } + interface Watching { + close(callback: () => void): void + invalidate(): void + } - interface NormalModuleFactoryHooks { - resolver: SyncWaterfallHook; - factory: SyncWaterfallHook; - beforeResolve: AsyncSeriesWaterfallHook; - afterResolve: AsyncSeriesWaterfallHook; - createModule: SyncBailHook; - module: SyncWaterfallHook; - createParser: HookMap; - parser: HookMap; - createGenerator: HookMap; - generator: HookMap; - } + interface InputFileSystem { + purge?(): void + readFile( + path: string, + callback: (err: Error | undefined | null, contents: Buffer) => void + ): void + readFileSync(path: string): Buffer + readlink( + path: string, + callback: (err: Error | undefined | null, linkString: string) => void + ): void + readlinkSync(path: string): string + stat( + path: string, + callback: (err: Error | undefined | null, stats: any) => void + ): void + statSync(path: string): any + } - class NormalModuleFactory extends Tapable { - hooks: NormalModuleFactoryHooks; - } + interface OutputFileSystem { + join(...paths: string[]): string + mkdir( + path: string, + callback: (err: Error | undefined | null) => void + ): void + mkdirp( + path: string, + callback: (err: Error | undefined | null) => void + ): void + rmdir( + path: string, + callback: (err: Error | undefined | null) => void + ): void + unlink( + path: string, + callback: (err: Error | undefined | null) => void + ): void + writeFile( + path: string, + data: any, + callback: (err: Error | undefined | null) => void + ): void + } - interface ContextModuleFactoryHooks { - beforeResolve: AsyncSeriesWaterfallHook; - afterResolve: AsyncSeriesWaterfallHook; - contextModuleFiles: SyncWaterfallHook; - alternatives: AsyncSeriesWaterfallHook; - } + interface SortableSet<T> extends Set<T> { + sortWith(sortFn: (a: T, b: T) => number): void + sort(): void + getFromCache(fn: (set: SortableSet<T>) => T[]): T[] + getFromUnorderedCache( + fn: (set: SortableSet<T>) => string | number | T[] + ): any + } - class ContextModuleFactory extends Tapable { - hooks: ContextModuleFactoryHooks; - } + class Compiler extends Tapable implements ICompiler { + constructor() + + hooks: compilation.CompilerHooks + _pluginCompat: SyncBailHook<compilation.Compilation> + + name: string + options: Configuration + inputFileSystem: InputFileSystem + outputFileSystem: OutputFileSystem + fileTimestamps: Map<string, number> + contextTimestamps: Map<string, number> + run(handler: Compiler.Handler): void + watch( + watchOptions: Compiler.WatchOptions, + handler: Compiler.Handler + ): Compiler.Watching + } - class DllModuleFactory extends Tapable { - hooks: {}; - } + namespace Compiler { + type Handler = ICompiler.Handler + type WatchOptions = ICompiler.WatchOptions + + class Watching implements Watching { + constructor( + compiler: Compiler, + watchOptions: Watching.WatchOptions, + handler: Watching.Handler + ) + + close(callback: () => void): void + invalidate(): void + } + + namespace Watching { + type WatchOptions = ICompiler.WatchOptions + type Handler = ICompiler.Handler + } + } - interface CompilationHooks { - buildModule: SyncHook<Module>; - rebuildModule: SyncHook<Module>; - failedModule: SyncHook<Module, Error>; - succeedModule: SyncHook<Module>; + abstract class MultiCompiler extends Tapable implements ICompiler { + compilers: Compiler[] + run(handler: MultiCompiler.Handler): void + watch( + watchOptions: MultiCompiler.WatchOptions, + handler: MultiCompiler.Handler + ): MultiWatching + } - finishModules: SyncHook<Module[]>; - finishRebuildingModule: SyncHook<Module>; + namespace MultiCompiler { + type Handler = ICompiler.Handler + type WatchOptions = ICompiler.WatchOptions + } - unseal: SyncHook; - seal: SyncHook; + abstract class MultiWatching implements Watching { + close(callback: () => void): void + invalidate(): void + } - optimizeDependenciesBasic: SyncBailHook<Module[]>; - optimizeDependencies: SyncBailHook<Module[]>; - optimizeDependenciesAdvanced: SyncBailHook<Module[]>; - afterOptimizeDependencies: SyncHook<Module[]>; + abstract class Plugin implements Tapable.Plugin { + apply(compiler: Compiler): void + } - optimize: SyncHook; + abstract class ResolvePlugin implements Tapable.Plugin { + apply(resolver: any /* EnhancedResolve.Resolver */): void + } - optimizeModulesBasic: SyncBailHook<Module[]>; - optimizeModules: SyncBailHook<Module[]>; - optimizeModulesAdvanced: SyncBailHook<Module[]>; - afterOptimizeModules: SyncHook<Module[]>; + abstract class Stats { + compilation: compilation.Compilation + hash?: string + startTime?: Date + endTime?: Date + /** Returns true if there were errors while compiling. */ + hasErrors(): boolean + /** Returns true if there were warnings while compiling. */ + hasWarnings(): boolean + /** Returns compilation information as a JSON object. */ + toJson(options?: Stats.ToJsonOptions): any + /** Returns a formatted string of the compilation information (similar to CLI output). */ + toString(options?: Stats.ToStringOptions): string + } - optimizeChunksBasic: SyncBailHook<Chunk[], ChunkGroup[]>; - optimizeChunks: SyncBailHook<Chunk[], ChunkGroup[]>; - optimizeChunksAdvanced: SyncBailHook<Chunk[], ChunkGroup[]>; - afterOptimizeChunks: SyncHook<Chunk[], ChunkGroup[]>; + namespace Stats { + type Preset = + | boolean + | 'errors-only' + | 'minimal' + | 'none' + | 'normal' + | 'verbose' + + interface ToJsonOptionsObject { + /** fallback value for stats options when an option is not defined (has precedence over local webpack defaults) */ + all?: boolean + /** Add asset Information */ + assets?: boolean + /** Sort assets by a field */ + assetsSort?: string + /** Add built at time information */ + builtAt?: boolean + /** Add information about cached (not built) modules */ + cached?: boolean + /** Show cached assets (setting this to `false` only shows emitted files) */ + cachedAssets?: boolean + /** Add children information */ + children?: boolean + /** Add built modules information to chunk information */ + chunkModules?: boolean + /** Add the origins of chunks and chunk merging info */ + chunkOrigins?: boolean + /** Add chunk information (setting this to `false` allows for a less verbose output) */ + chunks?: boolean + /** Sort the chunks by a field */ + chunksSort?: string + /** Context directory for request shortening */ + context?: string + /** Display the distance from the entry point for each module */ + depth?: boolean + /** Display the entry points with the corresponding bundles */ + entrypoints?: boolean + /** Add --env information */ + env?: boolean + /** Add errors */ + errors?: boolean + /** Add details to errors (like resolving log) */ + errorDetails?: boolean + /** Exclude assets from being displayed in stats */ + excludeAssets?: StatsExcludeFilter + /** Exclude modules from being displayed in stats */ + excludeModules?: StatsExcludeFilter + /** See excludeModules */ + exclude?: StatsExcludeFilter + /** Add the hash of the compilation */ + hash?: boolean + /** Set the maximum number of modules to be shown */ + maxModules?: number + /** Add built modules information */ + modules?: boolean + /** Sort the modules by a field */ + modulesSort?: string + /** Show dependencies and origin of warnings/errors */ + moduleTrace?: boolean + /** Add public path information */ + publicPath?: boolean + /** Add information about the reasons why modules are included */ + reasons?: boolean + /** Add the source code of modules */ + source?: boolean + /** Add timing information */ + timings?: boolean + /** Add webpack version information */ + version?: boolean + /** Add warnings */ + warnings?: boolean + /** Show which exports of a module are used */ + usedExports?: boolean + /** Filter warnings to be shown */ + warningsFilter?: + | string + | RegExp + | Array<string | RegExp> + | ((warning: string) => boolean) + /** Show performance hint when file size exceeds `performance.maxAssetSize` */ + performance?: boolean + /** Show the exports of the modules */ + providedExports?: boolean + } + + type ToJsonOptions = Preset | ToJsonOptionsObject + + type StatsExcludeFilter = + | string + | string[] + | RegExp + | RegExp[] + | ((assetName: string) => boolean) + | Array<(assetName: string) => boolean> + + interface ToStringOptionsObject extends ToJsonOptionsObject { + /** `webpack --colors` equivalent */ + colors?: boolean | string + } + + type ToStringOptions = Preset | ToStringOptionsObject + } - optimizeTree: AsyncSeriesHook<Chunk[], Module[]>; - afterOptimizeTree: SyncHook<Chunk[], Module[]>; + /** + * Plugins + */ - optimizeChunkModulesBasic: SyncBailHook<Chunk[], Module[]>; - optimizeChunkModules: SyncBailHook<Chunk[], Module[]>; - optimizeChunkModulesAdvanced: SyncBailHook<Chunk[], Module[]>; - afterOptimizeChunkModules: SyncHook<Chunk[], Module[]>; - shouldRecord: SyncBailHook; + class BannerPlugin extends Plugin { + constructor(options: string | BannerPlugin.Options) + } - reviveModules: SyncHook<Module[], Record[]>; - optimizeModuleOrder: SyncHook<Module[]>; - advancedOptimizeModuleOrder: SyncHook<Module[]>; - beforeModuleIds: SyncHook<Module[]>; - moduleIds: SyncHook<Module[]>; - optimizeModuleIds: SyncHook<Module[]>; - afterOptimizeModuleIds: SyncHook<Module[]>; + namespace BannerPlugin { + type Filter = string | RegExp + + interface Options { + banner: string + entryOnly?: boolean + exclude?: Filter | Filter[] + include?: Filter | Filter[] + raw?: boolean + test?: Filter | Filter[] + } + } - reviveChunks: SyncHook<Chunk[], Record[]>; - optimizeChunkOrder: SyncHook<Chunk[]>; - beforeChunkIds: SyncHook<Chunk[]>; - optimizeChunkIds: SyncHook<Chunk[]>; - afterOptimizeChunkIds: SyncHook<Chunk[]>; + class ContextReplacementPlugin extends Plugin { + constructor( + resourceRegExp: any, + newContentResource?: any, + newContentRecursive?: any, + newContentRegExp?: any + ) + } - recordModules: SyncHook<Module[], Record[]>; - recordChunks: SyncHook<Chunk[], Record[]>; + class DefinePlugin extends Plugin { + constructor(definitions: { [key: string]: any }) + } - beforeHash: SyncHook; - afterHash: SyncHook; + class DllPlugin extends Plugin { + constructor(options: DllPlugin.Options | DllPlugin.Options[]) + } - recordHash: SyncHook<Record[]>; + namespace DllPlugin { + interface Options { + /** + * The context of requests in the manifest file. + * + * Defaults to the webpack context. + */ + context?: string - record: SyncHook<Compilation, Record[]>; + /** + * The name of the exposed DLL function (keep consistent with `output.library`). + */ + name: string - beforeModuleAssets: SyncHook; - shouldGenerateChunkAssets: SyncBailHook; - beforeChunkAssets: SyncHook; - additionalChunkAssets: SyncHook<Chunk[]>; + /** + * The absolute path to the manifest json file (output). + */ + path: string + } + } - records: SyncHook<Compilation, Record[]>; + class DllReferencePlugin extends Plugin { + constructor(options: DllReferencePlugin.Options) + } - additionalAssets: AsyncSeriesHook; - optimizeChunkAssets: AsyncSeriesHook<Chunk[]>; - afterOptimizeChunkAssets: SyncHook<Chunk[]>; - optimizeAssets: AsyncSeriesHook<Asset[]>; - afterOptimizeAssets: SyncHook<Asset[]>; + namespace DllReferencePlugin { + interface Options { + /** + * The mappings from the request to module ID. + * + * Defaults to `manifest.content`. + */ + content?: any - needAdditionalSeal: SyncBailHook; - afterSeal: AsyncSeriesHook; + /** + * The context of requests in the manifest (or content property). + * + * This is an <b>absolute path</b>. + */ + context: string - chunkHash: SyncHook<Chunk, ChunkHash>; - moduleAsset: SyncHook<Module, string>; - chunkAsset: SyncHook<Chunk, string>; + /** + * An object containing `content` and `name`. + */ + manifest: { content: string; name: string } | string - assetPath: SyncWaterfallHook<string>; + /** + * The name where the DLL is exposed. + * + * Defaults to `manifest.name`. + * + * See also `externals`. + */ + name?: string - needAdditionalPass: SyncBailHook; - childCompiler: SyncHook; + /** + * The prefix which is used for accessing the content of the DLL. + */ + scope?: string - normalModuleLoader: SyncHook<any, Module>; + /** + * The type how the DLL is exposed. + * + * Defaults to `"var"`. + * + * See also `externals`. + */ + sourceType?: string + } + } - optimizeExtractedChunksBasic: SyncBailHook<Chunk[]>; - optimizeExtractedChunks: SyncBailHook<Chunk[]>; - optimizeExtractedChunksAdvanced: SyncBailHook<Chunk[]>; - afterOptimizeExtractedChunks: SyncHook<Chunk[]>; - } + class EvalSourceMapDevToolPlugin extends Plugin { + constructor(options?: false | string | EvalSourceMapDevToolPlugin.Options) + } - interface CompilationModule { - module: any; - issuer: boolean; - build: boolean; - dependencies: boolean; + namespace EvalSourceMapDevToolPlugin { + interface Options { + append?: false | string + columns?: boolean + lineToLine?: + | boolean + | { + exclude?: Condition | Condition[] + include?: Condition | Condition[] + test?: Condition | Condition[] } + module?: boolean + moduleFilenameTemplate?: string + sourceRoot?: string + } + } - class MainTemplate extends Tapable {} - class ChunkTemplate extends Tapable {} - class HotUpdateChunkTemplate extends Tapable {} - class RuntimeTemplate {} - - interface ModuleTemplateHooks { - content: SyncWaterfallHook; - module: SyncWaterfallHook; - render: SyncWaterfallHook; - package: SyncWaterfallHook; - hash: SyncHook; - } + class ExtendedAPIPlugin extends Plugin { + constructor() + } - class ModuleTemplate extends Tapable { - hooks: ModuleTemplateHooks; - } + class HashedModuleIdsPlugin extends Plugin { + constructor(options?: { + hashFunction?: string + hashDigest?: string + hashDigestLength?: number + }) + } - class Compilation extends Tapable { - hooks: CompilationHooks; - compiler: Compiler; - - resolverFactory: any; - inputFileSystem: any; - requestShortener: any; - - outputOptions: any; - bail: any; - profile: any; - performance: any; - - mainTemplate: MainTemplate; - chunkTemplate: ChunkTemplate; - hotUpdateChunkTemplate: HotUpdateChunkTemplate; - runtimeTemplate: RuntimeTemplate; - moduleTemplates: { - javascript: ModuleTemplate; - webassembly: ModuleTemplate; - }; - - entries: any[]; - _preparedEntrypoints: any[]; - entrypoints: Map<any, any>; - chunks: any[]; - chunkGroups: any[]; - namedChunkGroups: Map<any, any>; - namedChunks: Map<any, any>; - modules: any[]; - _modules: Map<any, any>; - cache: any; - records: any; - nextFreeModuleIndex: any; - nextFreeModuleIndex2: any; - additionalChunkAssets: any[]; - assets: any; - errors: any[]; - warnings: any[]; - children: any[]; - dependencyFactories: Map<typeof Dependency, Tapable>; - dependencyTemplates: Map<typeof Dependency, Tapable>; - childrenCounters: any; - usedChunkIds: any; - usedModuleIds: any; - fileTimestamps: Map<string, number>; - contextTimestamps: Map<string, number>; - fileDependencies: SortableSet<string>; - contextDependencies: SortableSet<string>; - missingDependencies: SortableSet<string>; - hash?: string; - getStats(): Stats; - addModule(module: CompilationModule, cacheGroup: any): any; - // tslint:disable-next-line:ban-types - addEntry(context: any, entry: any, name: any, callback: Function): void; - getPath(filename: string, data: {hash?: any, chunk?: any, filename?: string, basename?: string, query?: any}): string; - /** - * @deprecated Compilation.applyPlugins is deprecated. Use new API on `.hooks` instead - */ - applyPlugins(name: string, ...args: any[]): void; - } + class HotModuleReplacementPlugin extends Plugin { + constructor(options?: any) + } - interface CompilerHooks { - shouldEmit: SyncBailHook<Compilation>; - done: AsyncSeriesHook<Stats>; - additionalPass: AsyncSeriesHook; - beforeRun: AsyncSeriesHook<Compiler>; - run: AsyncSeriesHook<Compiler>; - emit: AsyncSeriesHook<Compilation>; - afterEmit: AsyncSeriesHook<Compilation>; - thisCompilation: SyncHook<Compilation, { normalModuleFactory: NormalModuleFactory }>; - compilation: SyncHook<Compilation, { normalModuleFactory: NormalModuleFactory }>; - normalModuleFactory: SyncHook<NormalModuleFactory>; - contextModuleFactory: SyncHook<ContextModuleFactory>; - beforeCompile: AsyncSeriesHook<{}>; - compile: SyncHook<{}>; - make: AsyncParallelHook<Compilation>; - afterCompile: AsyncSeriesHook<Compilation>; - watchRun: AsyncSeriesHook<Compiler>; - failed: SyncHook<Error>; - invalid: SyncHook<string, Date>; - watchClose: SyncHook; - environment: SyncHook; - afterEnvironment: SyncHook; - afterPlugins: SyncHook<Compiler>; - afterResolvers: SyncHook<Compiler>; - entryOption: SyncBailHook; - } - } - // tslint:disable-next-line:interface-name - interface ICompiler { - run(handler: ICompiler.Handler): void; - watch(watchOptions: ICompiler.WatchOptions, handler: ICompiler.Handler): Watching; - } + class IgnorePlugin extends Plugin { + constructor(requestRegExp: any, contextRegExp?: any) + } - namespace ICompiler { - type Handler = (err: Error, stats: Stats) => void; - - interface WatchOptions { - /** - * Add a delay before rebuilding once the first file changed. This allows webpack to aggregate any other - * changes made during this time period into one rebuild. - * Pass a value in milliseconds. Default: 300. - */ - aggregateTimeout?: number; - /** - * For some systems, watching many file systems can result in a lot of CPU or memory usage. - * It is possible to exclude a huge folder like node_modules. - * It is also possible to use anymatch patterns. - */ - ignored?: anymatch.Matcher; - /** Turn on polling by passing true, or specifying a poll interval in milliseconds. */ - poll?: boolean | number; - } - } + class LoaderOptionsPlugin extends Plugin { + constructor(options: any) + } - interface Watching { - close(callback: () => void): void; - invalidate(): void; - } + /** @deprecated use config.optimization.namedModules */ + class NamedModulesPlugin extends Plugin { + constructor() + } - interface InputFileSystem { - purge?(): void; - readFile(path: string, callback: (err: Error | undefined | null, contents: Buffer) => void): void; - readFileSync(path: string): Buffer; - readlink(path: string, callback: (err: Error | undefined | null, linkString: string) => void): void; - readlinkSync(path: string): string; - stat(path: string, callback: (err: Error | undefined | null, stats: any) => void): void; - statSync(path: string): any; - } + class NamedChunksPlugin extends Plugin { + constructor(nameResolver?: (chunk: any) => string | null) + } - interface OutputFileSystem { - join(...paths: string[]): string; - mkdir(path: string, callback: (err: Error | undefined | null) => void): void; - mkdirp(path: string, callback: (err: Error | undefined | null) => void): void; - rmdir(path: string, callback: (err: Error | undefined | null) => void): void; - unlink(path: string, callback: (err: Error | undefined | null) => void): void; - writeFile(path: string, data: any, callback: (err: Error | undefined | null) => void): void; - } + /** @deprecated use config.optimization.noEmitOnErrors */ + class NoEmitOnErrorsPlugin extends Plugin { + constructor() + } - interface SortableSet<T> extends Set<T> { - sortWith(sortFn: (a: T, b: T) => number): void; - sort(): void; - getFromCache(fn: (set: SortableSet<T>) => T[]): T[]; - getFromUnorderedCache(fn: (set: SortableSet<T>) => string|number|T[]): any; - } + class NormalModuleReplacementPlugin extends Plugin { + constructor(resourceRegExp: any, newResource: any) + } - class Compiler extends Tapable implements ICompiler { - constructor(); + class PrefetchPlugin extends Plugin { + // tslint:disable-next-line:unified-signatures + constructor(context: any, request: any) + constructor(request: any) + } - hooks: compilation.CompilerHooks; - _pluginCompat: SyncBailHook<compilation.Compilation>; + class ProgressPlugin extends Plugin { + constructor( + options?: ( + percentage: number, + msg: string, + moduleProgress?: string, + activeModules?: string, + moduleName?: string + ) => void + ) + } - name: string; - options: Configuration; - inputFileSystem: InputFileSystem; - outputFileSystem: OutputFileSystem; - fileTimestamps: Map<string, number>; - contextTimestamps: Map<string, number>; - run(handler: Compiler.Handler): void; - watch(watchOptions: Compiler.WatchOptions, handler: Compiler.Handler): Compiler.Watching; - } + class EnvironmentPlugin extends Plugin { + constructor(envs: string[] | { [key: string]: any }) + } - namespace Compiler { - type Handler = ICompiler.Handler; - type WatchOptions = ICompiler.WatchOptions; + class ProvidePlugin extends Plugin { + constructor(definitions: { [key: string]: any }) + } - class Watching implements Watching { - constructor(compiler: Compiler, watchOptions: Watching.WatchOptions, handler: Watching.Handler); + class SplitChunksPlugin extends Plugin { + constructor(options?: Options.SplitChunksOptions) + } - close(callback: () => void): void; - invalidate(): void; - } + class SourceMapDevToolPlugin extends Plugin { + constructor( + options?: null | false | string | SourceMapDevToolPlugin.Options + ) + } - namespace Watching { - type WatchOptions = ICompiler.WatchOptions; - type Handler = ICompiler.Handler; + namespace SourceMapDevToolPlugin { + /** @todo extend EvalSourceMapDevToolPlugin.Options */ + interface Options { + append?: false | string + columns?: boolean + exclude?: Condition | Condition[] + fallbackModuleFilenameTemplate?: string + filename?: null | false | string + include?: Condition | Condition[] + lineToLine?: + | boolean + | { + exclude?: Condition | Condition[] + include?: Condition | Condition[] + test?: Condition | Condition[] } - } - - abstract class MultiCompiler extends Tapable implements ICompiler { - compilers: Compiler[]; - run(handler: MultiCompiler.Handler): void; - watch(watchOptions: MultiCompiler.WatchOptions, handler: MultiCompiler.Handler): MultiWatching; - } + module?: boolean + moduleFilenameTemplate?: string + noSources?: boolean + sourceRoot?: null | string + test?: Condition | Condition[] + } + } - namespace MultiCompiler { - type Handler = ICompiler.Handler; - type WatchOptions = ICompiler.WatchOptions; - } + class WatchIgnorePlugin extends Plugin { + constructor(paths: Array<string | RegExp>) + } - abstract class MultiWatching implements Watching { - close(callback: () => void): void; - invalidate(): void; - } + class SingleEntryPlugin extends Plugin { + constructor(context: string, entry: string, name: string) + } - abstract class Plugin implements Tapable.Plugin { - apply(compiler: Compiler): void; + namespace optimize { + /** @deprecated use config.optimization.concatenateModules */ + class ModuleConcatenationPlugin extends Plugin {} + class AggressiveMergingPlugin extends Plugin { + constructor(options?: AggressiveMergingPlugin.Options) + } + + namespace AggressiveMergingPlugin { + interface Options { + /** + * When options.moveToParents is set, moving to an entry chunk is more expensive. + * Defaults to 10, which means moving to an entry chunk is ten times more expensive than moving to a + * normal chunk. + */ + entryChunkMultiplicator?: number + /** + * A factor which defines the minimum required size reduction for chunk merging. + * Defaults to 1.5 which means that the total size needs to be reduced by 50% for chunk merging. + */ + minSizeReduce?: number + /** + * When set, modules that are not in both merged chunks are moved to all parents of the chunk. + * Defaults to false. + */ + moveToParents?: boolean } - - abstract class ResolvePlugin implements Tapable.Plugin { - apply(resolver: any /* EnhancedResolve.Resolver */): void; + } + + class AggressiveSplittingPlugin extends Plugin { + constructor(options?: AggressiveSplittingPlugin.Options) + } + + namespace AggressiveSplittingPlugin { + interface Options { + /** + * Size in byte. + * Only chunks bigger than the specified minSize are stored in records. + * This ensures the chunks fill up as your application grows, + * instead of creating too many chunks for every change. + * + * Default: 30720 + */ + minSize: 30000 + /** + * Size in byte. + * maximum size prefered for each chunk. + * + * Default: 51200 + */ + maxSize: 50000 + chunkOverhead: 0 + entryChunkMultiplicator: 1 } - - abstract class Stats { - compilation: compilation.Compilation; - hash?: string; - startTime?: Date; - endTime?: Date; - /** Returns true if there were errors while compiling. */ - hasErrors(): boolean; - /** Returns true if there were warnings while compiling. */ - hasWarnings(): boolean; - /** Returns compilation information as a JSON object. */ - toJson(options?: Stats.ToJsonOptions): any; - /** Returns a formatted string of the compilation information (similar to CLI output). */ - toString(options?: Stats.ToStringOptions): string; + } + + /** @deprecated */ + class DedupePlugin extends Plugin { + constructor() + } + + class LimitChunkCountPlugin extends Plugin { + constructor(options: any) + } + + class MinChunkSizePlugin extends Plugin { + constructor(options: any) + } + + class OccurrenceOrderPlugin extends Plugin { + constructor(preferEntry: boolean) + } + + class UglifyJsPlugin extends Plugin { + constructor(options?: UglifyJsPlugin.Options) + } + + namespace UglifyJsPlugin { + type CommentFilter = (astNode: any, comment: any) => boolean + + interface Options extends UglifyJS.MinifyOptions { + beautify?: boolean + comments?: boolean | RegExp | CommentFilter + exclude?: Condition | Condition[] + include?: Condition | Condition[] + /** Parallelization can speedup your build significantly and is therefore highly recommended. */ + parallel?: boolean | { cache: boolean; workers: boolean | number } + sourceMap?: boolean + test?: Condition | Condition[] } + } + } - namespace Stats { - type Preset - = boolean - | 'errors-only' - | 'minimal' - | 'none' - | 'normal' - | 'verbose'; - - interface ToJsonOptionsObject { - /** fallback value for stats options when an option is not defined (has precedence over local webpack defaults) */ - all?: boolean; - /** Add asset Information */ - assets?: boolean; - /** Sort assets by a field */ - assetsSort?: string; - /** Add built at time information */ - builtAt?: boolean; - /** Add information about cached (not built) modules */ - cached?: boolean; - /** Show cached assets (setting this to `false` only shows emitted files) */ - cachedAssets?: boolean; - /** Add children information */ - children?: boolean; - /** Add built modules information to chunk information */ - chunkModules?: boolean; - /** Add the origins of chunks and chunk merging info */ - chunkOrigins?: boolean; - /** Add chunk information (setting this to `false` allows for a less verbose output) */ - chunks?: boolean; - /** Sort the chunks by a field */ - chunksSort?: string; - /** Context directory for request shortening */ - context?: string; - /** Display the distance from the entry point for each module */ - depth?: boolean; - /** Display the entry points with the corresponding bundles */ - entrypoints?: boolean; - /** Add --env information */ - env?: boolean; - /** Add errors */ - errors?: boolean; - /** Add details to errors (like resolving log) */ - errorDetails?: boolean; - /** Exclude assets from being displayed in stats */ - excludeAssets?: StatsExcludeFilter; - /** Exclude modules from being displayed in stats */ - excludeModules?: StatsExcludeFilter; - /** See excludeModules */ - exclude?: StatsExcludeFilter; - /** Add the hash of the compilation */ - hash?: boolean; - /** Set the maximum number of modules to be shown */ - maxModules?: number; - /** Add built modules information */ - modules?: boolean; - /** Sort the modules by a field */ - modulesSort?: string; - /** Show dependencies and origin of warnings/errors */ - moduleTrace?: boolean; - /** Add public path information */ - publicPath?: boolean; - /** Add information about the reasons why modules are included */ - reasons?: boolean; - /** Add the source code of modules */ - source?: boolean; - /** Add timing information */ - timings?: boolean; - /** Add webpack version information */ - version?: boolean; - /** Add warnings */ - warnings?: boolean; - /** Show which exports of a module are used */ - usedExports?: boolean; - /** Filter warnings to be shown */ - warningsFilter?: string | RegExp | Array<string | RegExp> | ((warning: string) => boolean); - /** Show performance hint when file size exceeds `performance.maxAssetSize` */ - performance?: boolean; - /** Show the exports of the modules */ - providedExports?: boolean; - } - - type ToJsonOptions = Preset | ToJsonOptionsObject; - - type StatsExcludeFilter = string | string[] | RegExp | RegExp[] | ((assetName: string) => boolean) | Array<(assetName: string) => boolean>; + namespace dependencies {} - interface ToStringOptionsObject extends ToJsonOptionsObject { - /** `webpack --colors` equivalent */ - colors?: boolean | string; - } - - type ToStringOptions = Preset | ToStringOptionsObject; - } + namespace loader { + interface Loader extends Function { + ( + this: LoaderContext, + source: string | Buffer, + sourceMap?: RawSourceMap + ): string | Buffer | void | undefined /** - * Plugins + * The order of chained loaders are always called from right to left. + * But, in some cases, loaders do not care about the results of the previous loader or the resource. + * They only care for metadata. The pitch method on the loaders is called from left to right before the loaders are called (from right to left). + * If a loader delivers a result in the pitch method the process turns around and skips the remaining loaders, + * continuing with the calls to the more left loaders. data can be passed between pitch and normal call. */ + pitch?( + remainingRequest: string, + precedingRequest: string, + data: any + ): any - class BannerPlugin extends Plugin { - constructor(options: string | BannerPlugin.Options); - } - - namespace BannerPlugin { - type Filter = string | RegExp; - - interface Options { - banner: string; - entryOnly?: boolean; - exclude?: Filter | Filter[]; - include?: Filter | Filter[]; - raw?: boolean; - test?: Filter | Filter[]; - } - } - - class ContextReplacementPlugin extends Plugin { - constructor(resourceRegExp: any, newContentResource?: any, newContentRecursive?: any, newContentRegExp?: any); - } - - class DefinePlugin extends Plugin { - constructor(definitions: { [key: string]: any }); - } + /** + * By default, the resource file is treated as utf-8 string and passed as String to the loader. + * By setting raw to true the loader is passed the raw Buffer. + * Every loader is allowed to deliver its result as String or as Buffer. + * The compiler converts them between loaders. + */ + raw?: boolean + } - class DllPlugin extends Plugin { - constructor(options: DllPlugin.Options | DllPlugin.Options[]); - } + type loaderCallback = ( + err: Error | undefined | null, + content?: string | Buffer, + sourceMap?: RawSourceMap + ) => void - namespace DllPlugin { - interface Options { - /** - * The context of requests in the manifest file. - * - * Defaults to the webpack context. - */ - context?: string; - - /** - * The name of the exposed DLL function (keep consistent with `output.library`). - */ - name: string; - - /** - * The absolute path to the manifest json file (output). - */ - path: string; - } - } + interface LoaderContext { + /** + * Loader API version. Currently 2. + * This is useful for providing backwards compatibility. + * Using the version you can specify custom logic or fallbacks for breaking changes. + */ + version: string - class DllReferencePlugin extends Plugin { - constructor(options: DllReferencePlugin.Options); - } + /** + * The directory of the module. Can be used as context for resolving other stuff. + * In the example: /abc because resource.js is in this directory + */ + context: string - namespace DllReferencePlugin { - interface Options { - /** - * The mappings from the request to module ID. - * - * Defaults to `manifest.content`. - */ - content?: any; - - /** - * The context of requests in the manifest (or content property). - * - * This is an <b>absolute path</b>. - */ - context: string; - - /** - * An object containing `content` and `name`. - */ - manifest: { content: string, name: string } | string; - - /** - * The name where the DLL is exposed. - * - * Defaults to `manifest.name`. - * - * See also `externals`. - */ - name?: string; - - /** - * The prefix which is used for accessing the content of the DLL. - */ - scope?: string; - - /** - * The type how the DLL is exposed. - * - * Defaults to `"var"`. - * - * See also `externals`. - */ - sourceType?: string; - } - } + /** + * Starting with webpack 4, the formerly `this.options.context` is provided as `this.rootContext`. + */ + rootContext: string - class EvalSourceMapDevToolPlugin extends Plugin { - constructor(options?: false | string | EvalSourceMapDevToolPlugin.Options); - } + /** + * The resolved request string. + * In the example: "/abc/loader1.js?xyz!/abc/node_modules/loader2/index.js!/abc/resource.js?rrr" + */ + request: string - namespace EvalSourceMapDevToolPlugin { - interface Options { - append?: false | string; - columns?: boolean; - lineToLine?: boolean | { - exclude?: Condition | Condition[]; - include?: Condition | Condition[]; - test?: Condition | Condition[]; - }; - module?: boolean; - moduleFilenameTemplate?: string; - sourceRoot?: string; - } - } + /** + * A string or any object. The query of the request for the current loader. + */ + query: any - class ExtendedAPIPlugin extends Plugin { - constructor(); - } + /** + * A data object shared between the pitch and the normal phase. + */ + data?: any - class HashedModuleIdsPlugin extends Plugin { - constructor(options?: { - hashFunction?: string, - hashDigest?: string, - hashDigestLength?: number - }); - } + callback: loaderCallback - class HotModuleReplacementPlugin extends Plugin { - constructor(options?: any); - } + /** + * Make this loader async. + */ + async(): loaderCallback | undefined - class IgnorePlugin extends Plugin { - constructor(requestRegExp: any, contextRegExp?: any); - } + /** + * Make this loader result cacheable. By default it's not cacheable. + * A cacheable loader must have a deterministic result, when inputs and dependencies haven't changed. + * This means the loader shouldn't have other dependencies than specified with this.addDependency. + * Most loaders are deterministic and cacheable. + */ + cacheable(flag?: boolean): void - class LoaderOptionsPlugin extends Plugin { - constructor(options: any); - } + /** + * loaders = [{request: string, path: string, query: string, module: function}] + * An array of all the loaders. It is writeable in the pitch phase. + * In the example: + * [ + * { request: "/abc/loader1.js?xyz", + * path: "/abc/loader1.js", + * query: "?xyz", + * module: [Function] + * }, + * { request: "/abc/node_modules/loader2/index.js", + * path: "/abc/node_modules/loader2/index.js", + * query: "", + * module: [Function] + * } + * ] + */ + loaders: any[] - /** @deprecated use config.optimization.namedModules */ - class NamedModulesPlugin extends Plugin { - constructor(); - } + /** + * The index in the loaders array of the current loader. + * In the example: in loader1: 0, in loader2: 1 + */ + loaderIndex: number - class NamedChunksPlugin extends Plugin { - constructor(nameResolver?: (chunk: any) => string | null); - } + /** + * The resource part of the request, including query. + * In the example: "/abc/resource.js?rrr" + */ + resource: string - /** @deprecated use config.optimization.noEmitOnErrors */ - class NoEmitOnErrorsPlugin extends Plugin { - constructor(); - } + /** + * The resource file. + * In the example: "/abc/resource.js" + */ + resourcePath: string - class NormalModuleReplacementPlugin extends Plugin { - constructor(resourceRegExp: any, newResource: any); - } + /** + * The query of the resource. + * In the example: "?rrr" + */ + resourceQuery: string - class PrefetchPlugin extends Plugin { - // tslint:disable-next-line:unified-signatures - constructor(context: any, request: any); - constructor(request: any); - } + /** + * Emit a warning. + */ + emitWarning(message: string | Error): void - class ProgressPlugin extends Plugin { - constructor(options?: (percentage: number, msg: string, moduleProgress?: string, activeModules?: string, moduleName?: string) => void); - } + /** + * Emit a error. + */ + emitError(message: string | Error): void - class EnvironmentPlugin extends Plugin { - constructor(envs: string[] | { [key: string]: any }); - } + /** + * Execute some code fragment like a module. + * + * Don't use require(this.resourcePath), use this function to make loaders chainable! + * + */ + exec(code: string, filename: string): any - class ProvidePlugin extends Plugin { - constructor(definitions: { [key: string]: any }); - } + /** + * Resolves the given request to a module, applies all configured loaders and calls + * back with the generated source, the sourceMap and the module instance (usually an + * instance of NormalModule). Use this function if you need to know the source code + * of another module to generate the result. + */ + loadModule( + request: string, + callback: ( + err: Error | null, + source: string, + sourceMap: RawSourceMap, + module: Module + ) => void + ): any - class SplitChunksPlugin extends Plugin { - constructor(options?: Options.SplitChunksOptions); - } + /** + * Resolve a request like a require expression. + */ + resolve( + context: string, + request: string, + callback: (err: Error, result: string) => void + ): any - class SourceMapDevToolPlugin extends Plugin { - constructor(options?: null | false | string | SourceMapDevToolPlugin.Options); - } + /** + * Resolve a request like a require expression. + */ + resolveSync(context: string, request: string): string - namespace SourceMapDevToolPlugin { - /** @todo extend EvalSourceMapDevToolPlugin.Options */ - interface Options { - append?: false | string; - columns?: boolean; - exclude?: Condition | Condition[]; - fallbackModuleFilenameTemplate?: string; - filename?: null | false | string; - include?: Condition | Condition[]; - lineToLine?: boolean | { - exclude?: Condition | Condition[]; - include?: Condition | Condition[]; - test?: Condition | Condition[]; - }; - module?: boolean; - moduleFilenameTemplate?: string; - noSources?: boolean; - sourceRoot?: null | string; - test?: Condition | Condition[]; - } - } + /** + * Adds a file as dependency of the loader result in order to make them watchable. + * For example, html-loader uses this technique as it finds src and src-set attributes. + * Then, it sets the url's for those attributes as dependencies of the html file that is parsed. + */ + addDependency(file: string): void - class WatchIgnorePlugin extends Plugin { - constructor(paths: Array<string | RegExp>); - } + /** + * Adds a file as dependency of the loader result in order to make them watchable. + * For example, html-loader uses this technique as it finds src and src-set attributes. + * Then, it sets the url's for those attributes as dependencies of the html file that is parsed. + */ + dependency(file: string): void - class SingleEntryPlugin extends Plugin { - constructor(context: string, entry: string, name: string); - } + /** + * Add a directory as dependency of the loader result. + */ + addContextDependency(directory: string): void - namespace optimize { - /** @deprecated use config.optimization.concatenateModules */ - class ModuleConcatenationPlugin extends Plugin { } - class AggressiveMergingPlugin extends Plugin { - constructor(options?: AggressiveMergingPlugin.Options); - } + /** + * Remove all dependencies of the loader result. Even initial dependencies and these of other loaders. Consider using pitch. + */ + clearDependencies(): void - namespace AggressiveMergingPlugin { - interface Options { - /** - * When options.moveToParents is set, moving to an entry chunk is more expensive. - * Defaults to 10, which means moving to an entry chunk is ten times more expensive than moving to a - * normal chunk. - */ - entryChunkMultiplicator?: number; - /** - * A factor which defines the minimum required size reduction for chunk merging. - * Defaults to 1.5 which means that the total size needs to be reduced by 50% for chunk merging. - */ - minSizeReduce?: number; - /** - * When set, modules that are not in both merged chunks are moved to all parents of the chunk. - * Defaults to false. - */ - moveToParents?: boolean; - } - } + /** + * Pass values to the next loader. + * If you know what your result exports if executed as module, set this value here (as a only element array). + */ + value: any - class AggressiveSplittingPlugin extends Plugin { - constructor(options?: AggressiveSplittingPlugin.Options); - } + /** + * Passed from the last loader. + * If you would execute the input argument as module, consider reading this variable for a shortcut (for performance). + */ + inputValue: any - namespace AggressiveSplittingPlugin { - interface Options { - /** - * Size in byte. - * Only chunks bigger than the specified minSize are stored in records. - * This ensures the chunks fill up as your application grows, - * instead of creating too many chunks for every change. - * - * Default: 30720 - */ - minSize: 30000; - /** - * Size in byte. - * maximum size prefered for each chunk. - * - * Default: 51200 - */ - maxSize: 50000; - chunkOverhead: 0; - entryChunkMultiplicator: 1; - } - } + /** + * A boolean flag. It is set when in debug mode. + */ + debug: boolean - /** @deprecated */ - class DedupePlugin extends Plugin { - constructor(); - } + /** + * Should the result be minimized. + */ + minimize: boolean - class LimitChunkCountPlugin extends Plugin { - constructor(options: any); - } + /** + * Should a SourceMap be generated. + */ + sourceMap: boolean - class MinChunkSizePlugin extends Plugin { - constructor(options: any); - } + /** + * Target of compilation. Passed from configuration options. + * Example values: "web", "node" + */ + target: + | 'web' + | 'webworker' + | 'async-node' + | 'node' + | 'electron-main' + | 'electron-renderer' + | 'node-webkit' + | string - class OccurrenceOrderPlugin extends Plugin { - constructor(preferEntry: boolean); - } + /** + * This boolean is set to true when this is compiled by webpack. + * + * Loaders were originally designed to also work as Babel transforms. + * Therefore if you write a loader that works for both, you can use this property to know if + * there is access to additional loaderContext and webpack features. + */ + webpack: boolean - class UglifyJsPlugin extends Plugin { - constructor(options?: UglifyJsPlugin.Options); - } + /** + * Emit a file. This is webpack-specific. + */ + emitFile(name: string, content: Buffer | string, sourceMap: any): void - namespace UglifyJsPlugin { - type CommentFilter = (astNode: any, comment: any) => boolean; - - interface Options extends UglifyJS.MinifyOptions { - beautify?: boolean; - comments?: boolean | RegExp | CommentFilter; - exclude?: Condition | Condition[]; - include?: Condition | Condition[]; - /** Parallelization can speedup your build significantly and is therefore highly recommended. */ - parallel?: boolean | { cache: boolean, workers: boolean | number }; - sourceMap?: boolean; - test?: Condition | Condition[]; - } - } - } + /** + * Access to the compilation's inputFileSystem property. + */ + fs: any - namespace dependencies { - } + /** + * Hacky access to the Compilation object of webpack. + */ + _compilation: any - namespace loader { - interface Loader extends Function { - (this: LoaderContext, source: string | Buffer, sourceMap?: RawSourceMap): string | Buffer | void | undefined; - - /** - * The order of chained loaders are always called from right to left. - * But, in some cases, loaders do not care about the results of the previous loader or the resource. - * They only care for metadata. The pitch method on the loaders is called from left to right before the loaders are called (from right to left). - * If a loader delivers a result in the pitch method the process turns around and skips the remaining loaders, - * continuing with the calls to the more left loaders. data can be passed between pitch and normal call. - */ - pitch?(remainingRequest: string, precedingRequest: string, data: any): any; - - /** - * By default, the resource file is treated as utf-8 string and passed as String to the loader. - * By setting raw to true the loader is passed the raw Buffer. - * Every loader is allowed to deliver its result as String or as Buffer. - * The compiler converts them between loaders. - */ - raw?: boolean; - } + /** + * Hacky access to the Compiler object of webpack. + */ + _compiler: Compiler - type loaderCallback = (err: Error | undefined | null, content?: string | Buffer, sourceMap?: RawSourceMap) => void; - - interface LoaderContext { - /** - * Loader API version. Currently 2. - * This is useful for providing backwards compatibility. - * Using the version you can specify custom logic or fallbacks for breaking changes. - */ - version: string; - - /** - * The directory of the module. Can be used as context for resolving other stuff. - * In the example: /abc because resource.js is in this directory - */ - context: string; - - /** - * Starting with webpack 4, the formerly `this.options.context` is provided as `this.rootContext`. - */ - rootContext: string; - - /** - * The resolved request string. - * In the example: "/abc/loader1.js?xyz!/abc/node_modules/loader2/index.js!/abc/resource.js?rrr" - */ - request: string; - - /** - * A string or any object. The query of the request for the current loader. - */ - query: any; - - /** - * A data object shared between the pitch and the normal phase. - */ - data?: any; - - callback: loaderCallback; - - /** - * Make this loader async. - */ - async(): loaderCallback | undefined; - - /** - * Make this loader result cacheable. By default it's not cacheable. - * A cacheable loader must have a deterministic result, when inputs and dependencies haven't changed. - * This means the loader shouldn't have other dependencies than specified with this.addDependency. - * Most loaders are deterministic and cacheable. - */ - cacheable(flag?: boolean): void; - - /** - * loaders = [{request: string, path: string, query: string, module: function}] - * An array of all the loaders. It is writeable in the pitch phase. - * In the example: - * [ - * { request: "/abc/loader1.js?xyz", - * path: "/abc/loader1.js", - * query: "?xyz", - * module: [Function] - * }, - * { request: "/abc/node_modules/loader2/index.js", - * path: "/abc/node_modules/loader2/index.js", - * query: "", - * module: [Function] - * } - * ] - */ - loaders: any[]; - - /** - * The index in the loaders array of the current loader. - * In the example: in loader1: 0, in loader2: 1 - */ - loaderIndex: number; - - /** - * The resource part of the request, including query. - * In the example: "/abc/resource.js?rrr" - */ - resource: string; - - /** - * The resource file. - * In the example: "/abc/resource.js" - */ - resourcePath: string; - - /** - * The query of the resource. - * In the example: "?rrr" - */ - resourceQuery: string; - - /** - * Emit a warning. - */ - emitWarning(message: string | Error): void; - - /** - * Emit a error. - */ - emitError(message: string | Error): void; - - /** - * Execute some code fragment like a module. - * - * Don't use require(this.resourcePath), use this function to make loaders chainable! - * - */ - exec(code: string, filename: string): any; - - /** - * Resolves the given request to a module, applies all configured loaders and calls - * back with the generated source, the sourceMap and the module instance (usually an - * instance of NormalModule). Use this function if you need to know the source code - * of another module to generate the result. - */ - loadModule(request: string, callback: (err: Error | null, source: string, sourceMap: RawSourceMap, module: Module) => void): any; - - /** - * Resolve a request like a require expression. - */ - resolve(context: string, request: string, callback: (err: Error, result: string) => void): any; - - /** - * Resolve a request like a require expression. - */ - resolveSync(context: string, request: string): string; - - /** - * Adds a file as dependency of the loader result in order to make them watchable. - * For example, html-loader uses this technique as it finds src and src-set attributes. - * Then, it sets the url's for those attributes as dependencies of the html file that is parsed. - */ - addDependency(file: string): void; - - /** - * Adds a file as dependency of the loader result in order to make them watchable. - * For example, html-loader uses this technique as it finds src and src-set attributes. - * Then, it sets the url's for those attributes as dependencies of the html file that is parsed. - */ - dependency(file: string): void; - - /** - * Add a directory as dependency of the loader result. - */ - addContextDependency(directory: string): void; - - /** - * Remove all dependencies of the loader result. Even initial dependencies and these of other loaders. Consider using pitch. - */ - clearDependencies(): void; - - /** - * Pass values to the next loader. - * If you know what your result exports if executed as module, set this value here (as a only element array). - */ - value: any; - - /** - * Passed from the last loader. - * If you would execute the input argument as module, consider reading this variable for a shortcut (for performance). - */ - inputValue: any; - - /** - * A boolean flag. It is set when in debug mode. - */ - debug: boolean; - - /** - * Should the result be minimized. - */ - minimize: boolean; - - /** - * Should a SourceMap be generated. - */ - sourceMap: boolean; - - /** - * Target of compilation. Passed from configuration options. - * Example values: "web", "node" - */ - target: 'web' | 'webworker' | 'async-node' | 'node' | 'electron-main' | 'electron-renderer' | 'node-webkit' | string; - - /** - * This boolean is set to true when this is compiled by webpack. - * - * Loaders were originally designed to also work as Babel transforms. - * Therefore if you write a loader that works for both, you can use this property to know if - * there is access to additional loaderContext and webpack features. - */ - webpack: boolean; - - /** - * Emit a file. This is webpack-specific. - */ - emitFile(name: string, content: Buffer | string, sourceMap: any): void; - - /** - * Access to the compilation's inputFileSystem property. - */ - fs: any; - - /** - * Hacky access to the Compilation object of webpack. - */ - _compilation: any; - - /** - * Hacky access to the Compiler object of webpack. - */ - _compiler: Compiler; - - /** - * Hacky access to the Module object being loaded. - */ - _module: any; - - /** Flag if HMR is enabled */ - hot: boolean; - } - } + /** + * Hacky access to the Module object being loaded. + */ + _module: any - /** @deprecated */ - namespace compiler { - /** @deprecated use webpack.Compiler */ - // tslint:disable-next-line:no-unnecessary-qualifier - type Compiler = webpack.Compiler; + /** Flag if HMR is enabled */ + hot: boolean + } + } - /** @deprecated use webpack.Compiler.Watching */ - type Watching = Compiler.Watching; + /** @deprecated */ + namespace compiler { + /** @deprecated use webpack.Compiler */ + // tslint:disable-next-line:no-unnecessary-qualifier + type Compiler = webpack.Compiler - /** @deprecated use webpack.Compiler.WatchOptions */ + /** @deprecated use webpack.Compiler.Watching */ + type Watching = Compiler.Watching - type WatchOptions = Compiler.WatchOptions; + /** @deprecated use webpack.Compiler.WatchOptions */ - /** @deprecated use webpack.Stats */ - // tslint:disable-next-line:no-unnecessary-qualifier - type Stats = webpack.Stats; + type WatchOptions = Compiler.WatchOptions - /** @deprecated use webpack.Stats.ToJsonOptions */ - type StatsOptions = Stats.ToJsonOptions; + /** @deprecated use webpack.Stats */ + // tslint:disable-next-line:no-unnecessary-qualifier + type Stats = webpack.Stats - /** @deprecated use webpack.Stats.ToStringOptions */ - type StatsToStringOptions = Stats.ToStringOptions; + /** @deprecated use webpack.Stats.ToJsonOptions */ + type StatsOptions = Stats.ToJsonOptions - /** @deprecated use webpack.Compiler.Handler */ - type CompilerCallback = Compiler.Handler; - } + /** @deprecated use webpack.Stats.ToStringOptions */ + type StatsToStringOptions = Stats.ToStringOptions - /** @deprecated use webpack.Options.Performance */ - type PerformanceOptions = Options.Performance; - /** @deprecated use webpack.Options.WatchOptions */ - type WatchOptions = Options.WatchOptions; - /** @deprecated use webpack.EvalSourceMapDevToolPlugin.Options */ - type EvalSourceMapDevToolPluginOptions = EvalSourceMapDevToolPlugin.Options; - /** @deprecated use webpack.SourceMapDevToolPlugin.Options */ - type SourceMapDevToolPluginOptions = SourceMapDevToolPlugin.Options; - /** @deprecated use webpack.optimize.UglifyJsPlugin.CommentFilter */ - type UglifyCommentFunction = optimize.UglifyJsPlugin.CommentFilter; - /** @deprecated use webpack.optimize.UglifyJsPlugin.Options */ - type UglifyPluginOptions = optimize.UglifyJsPlugin.Options; + /** @deprecated use webpack.Compiler.Handler */ + type CompilerCallback = Compiler.Handler } + + /** @deprecated use webpack.Options.Performance */ + type PerformanceOptions = Options.Performance + /** @deprecated use webpack.Options.WatchOptions */ + type WatchOptions = Options.WatchOptions + /** @deprecated use webpack.EvalSourceMapDevToolPlugin.Options */ + type EvalSourceMapDevToolPluginOptions = EvalSourceMapDevToolPlugin.Options + /** @deprecated use webpack.SourceMapDevToolPlugin.Options */ + type SourceMapDevToolPluginOptions = SourceMapDevToolPlugin.Options + /** @deprecated use webpack.optimize.UglifyJsPlugin.CommentFilter */ + type UglifyCommentFunction = optimize.UglifyJsPlugin.CommentFilter + /** @deprecated use webpack.optimize.UglifyJsPlugin.Options */ + type UglifyPluginOptions = optimize.UglifyJsPlugin.Options + } } diff --git a/test/integration/client-navigation/lib/data.json b/test/integration/client-navigation/lib/data.json index 42ee7df230df2..716d95c863a03 100644 --- a/test/integration/client-navigation/lib/data.json +++ b/test/integration/client-navigation/lib/data.json @@ -1,3 +1,3 @@ { - "name": "Zeit" -} \ No newline at end of file + "name": "Zeit" +} diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 1abd6c9448c99..0000000000000 --- a/tslint.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": [ - "tslint:recommended" - ], - "jsRules": {}, - "rules": { - "curly": false, - "no-empty": false, - "object-literal-sort-keys": false, - "variable-name": false, - "max-line-length": false, - "max-classes-per-file": 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, - "no-console": [true, "log"] - }, - "rulesDirectory": [], - "linterOptions": { - "exclude": [ - "**/node_modules/**", - "**/build/**", - "**/types/**" - ] - } -}