diff --git a/bin/next b/bin/next index 72993ed9..884f19e5 100755 --- a/bin/next +++ b/bin/next @@ -88,6 +88,15 @@ const startProcess = () => { let proc = startProcess() +const wrapper = () => { + if (proc) { + proc.kill() + } +} +process.on('SIGINT', wrapper) +process.on('SIGTERM', wrapper) +process.on('exit', wrapper) + if (cmd === 'dev') { const {watchFile} = require('fs') watchFile(`${process.cwd()}/${CONFIG_FILE}`, (cur, prev) => { diff --git a/build/webpack.js b/build/webpack.js index ff5549ba..084258a4 100644 --- a/build/webpack.js +++ b/build/webpack.js @@ -137,7 +137,7 @@ export default async function getBaseWebpackConfig (dir: string, {dev = false, i module: { rules: [ dev && !isServer && { - test: /\.(js|jsx)$/, + test: defaultLoaders.hotSelfAccept.options.extensions, include: defaultLoaders.hotSelfAccept.options.include, use: defaultLoaders.hotSelfAccept }, diff --git a/package.json b/package.json index 4d8d89de..7b737382 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,7 @@ "@taskr/esnext": "1.1.0", "@taskr/watch": "1.1.0", "@zeit/next-css": "0.0.7", + "@zeit/next-typescript": "1.1.0", "babel-eslint": "8.2.2", "babel-jest": "21.2.0", "babel-plugin-istanbul": "4.1.5", diff --git a/test/integration/app-aspath/test/index.test.js b/test/integration/app-aspath/test/index.test.js index 1b905416..a0471e3d 100644 --- a/test/integration/app-aspath/test/index.test.js +++ b/test/integration/app-aspath/test/index.test.js @@ -18,7 +18,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5 describe('App asPath', () => { beforeAll(async () => { appPort = await findPort() - server = await launchApp(join(__dirname, '../'), appPort, true) + server = await launchApp(join(__dirname, '../'), appPort) // pre-build all pages at the start await Promise.all([ diff --git a/test/integration/app-document/test/index.test.js b/test/integration/app-document/test/index.test.js index 13cb8907..a073a191 100644 --- a/test/integration/app-document/test/index.test.js +++ b/test/integration/app-document/test/index.test.js @@ -19,7 +19,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5 describe('Document and App', () => { beforeAll(async () => { context.appPort = await findPort() - context.server = await launchApp(join(__dirname, '../'), context.appPort, true) + context.server = await launchApp(join(__dirname, '../'), context.appPort) // pre-build all pages at the start await Promise.all([ diff --git a/test/integration/babel/test/index.test.js b/test/integration/babel/test/index.test.js index dc359a9a..653f49f6 100644 --- a/test/integration/babel/test/index.test.js +++ b/test/integration/babel/test/index.test.js @@ -18,7 +18,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5 describe('Babel', () => { beforeAll(async () => { context.appPort = await findPort() - context.server = await launchApp(join(__dirname, '../'), context.appPort, true) + context.server = await launchApp(join(__dirname, '../'), context.appPort) // pre-build all pages at the start await Promise.all([ diff --git a/test/integration/basic/test/index.test.js b/test/integration/basic/test/index.test.js index d79a2684..9e5d9f8e 100644 --- a/test/integration/basic/test/index.test.js +++ b/test/integration/basic/test/index.test.js @@ -23,7 +23,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5 describe('Basic Features', () => { beforeAll(async () => { context.appPort = await findPort() - context.server = await launchApp(join(__dirname, '../'), context.appPort, true) + context.server = await launchApp(join(__dirname, '../'), context.appPort) // pre-build all pages at the start await Promise.all([ diff --git a/test/integration/config/test/index.test.js b/test/integration/config/test/index.test.js index c21577d9..ef67229c 100644 --- a/test/integration/config/test/index.test.js +++ b/test/integration/config/test/index.test.js @@ -19,7 +19,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5 describe('Configuration', () => { beforeAll(async () => { context.appPort = await findPort() - context.server = await launchApp(join(__dirname, '../'), context.appPort, true) + context.server = await launchApp(join(__dirname, '../'), context.appPort) // pre-build all pages at the start await Promise.all([ diff --git a/test/integration/page-extensions/.babelrc b/test/integration/page-extensions/.babelrc new file mode 100644 index 00000000..f1ced417 --- /dev/null +++ b/test/integration/page-extensions/.babelrc @@ -0,0 +1,6 @@ +{ + "presets": [ + "next/babel", + "@zeit/next-typescript/babel" + ] +} \ No newline at end of file diff --git a/test/integration/page-extensions/next.config.js b/test/integration/page-extensions/next.config.js new file mode 100644 index 00000000..eddd33b8 --- /dev/null +++ b/test/integration/page-extensions/next.config.js @@ -0,0 +1,7 @@ +const withTypescript = require('@zeit/next-typescript') +module.exports = withTypescript({ + onDemandEntries: { + // Make sure entries are not getting disposed. + maxInactiveAge: 1000 * 60 * 60 + } +}) diff --git a/test/integration/page-extensions/pages/hmr/some-page.tsx b/test/integration/page-extensions/pages/hmr/some-page.tsx new file mode 100644 index 00000000..e283ec20 --- /dev/null +++ b/test/integration/page-extensions/pages/hmr/some-page.tsx @@ -0,0 +1,23 @@ +import React from 'react' + +if(typeof window !== 'undefined' && !window['HMR_RANDOM_NUMBER']) { + window['HMR_RANDOM_NUMBER'] = Math.random() +} + +export default class Counter extends React.Component { + state = { count: 0 } + + incr () { + const { count } = this.state + this.setState({ count: count + 1 }) + } + + render () { + return ( +
+

COUNT: {this.state.count}

+ +
+ ) + } +} diff --git a/test/integration/page-extensions/test/.babelrc b/test/integration/page-extensions/test/.babelrc new file mode 100644 index 00000000..27c7237a --- /dev/null +++ b/test/integration/page-extensions/test/.babelrc @@ -0,0 +1,9 @@ +{ + "presets": [ + ["next/babel", { + "preset-env": { + "modules": "commonjs" + } + }] + ] +} \ No newline at end of file diff --git a/test/integration/page-extensions/test/hmr.js b/test/integration/page-extensions/test/hmr.js new file mode 100644 index 00000000..8b895666 --- /dev/null +++ b/test/integration/page-extensions/test/hmr.js @@ -0,0 +1,40 @@ +/* global describe, it, expect */ +import webdriver from 'next-webdriver' +import { readFileSync, writeFileSync } from 'fs' +import { join } from 'path' +import { waitFor } from 'next-test-utils' + +export default (context, renderViaHTTP) => { + describe('Hot Module Reloading', () => { + it('should reload typescript file without refresh', async () => { + let browser + const pagePath = join(__dirname, '../', 'pages', 'hmr', 'some-page.tsx') + + const originalContent = readFileSync(pagePath, 'utf8') + const editedContent = originalContent.replace('Increment', 'INCREMENT') + try { + browser = await webdriver(context.appPort, '/hmr/some-page') + const randomNumber = await browser.eval('window.HMR_RANDOM_NUMBER') + const originalButtonText = await browser.elementByCss('button').text() + expect(originalButtonText).toBe('Increment') + + // Change the about.js page + writeFileSync(pagePath, editedContent, 'utf8') + + // wait for 5 seconds + await waitFor(5000) + + const randomNumberAfterEdit = await browser.eval('window.HMR_RANDOM_NUMBER') + expect(randomNumberAfterEdit).toBe(randomNumber) + const updatedButtonText = await browser.elementByCss('button').text() + expect(updatedButtonText).toBe('INCREMENT') + } finally { + // restore the about page content. + writeFileSync(pagePath, originalContent, 'utf8') + if (browser) { + browser.close() + } + } + }) + }) +} diff --git a/test/integration/page-extensions/test/index.test.js b/test/integration/page-extensions/test/index.test.js new file mode 100644 index 00000000..ffe86afd --- /dev/null +++ b/test/integration/page-extensions/test/index.test.js @@ -0,0 +1,30 @@ +/* global jasmine, describe, beforeAll, afterAll */ + +import { join } from 'path' +import { + renderViaHTTP, + findPort, + launchApp, + killApp +} from 'next-test-utils' + +// test suits +import hmr from './hmr' + +const context = {} +jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5 + +describe('Page Extensions', () => { + beforeAll(async () => { + context.appPort = await findPort() + context.server = await launchApp(join(__dirname, '../'), context.appPort) + + // pre-build all pages at the start + await Promise.all([ + renderViaHTTP(context.appPort, '/hmr/some-page') + ]) + }) + afterAll(() => killApp(context.server)) + + hmr(context, (p, q) => renderViaHTTP(context.appPort, p, q)) +}) diff --git a/test/lib/next-test-utils.js b/test/lib/next-test-utils.js index d2c54d46..e34cd8b3 100644 --- a/test/lib/next-test-utils.js +++ b/test/lib/next-test-utils.js @@ -113,7 +113,7 @@ export async function startApp (app) { return server } -export async function stopApp (app) { +export async function stopApp (server) { if (server.__app) { await server.__app.close() } diff --git a/yarn.lock b/yarn.lock index 8d06a158..42385ccb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -349,6 +349,12 @@ dependencies: "@babel/helper-plugin-utils" "7.0.0-beta.42" +"@babel/plugin-syntax-typescript@7.0.0-beta.42": + version "7.0.0-beta.42" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.0.0-beta.42.tgz#ffc42945ca15e5ab369de6b9f5d9324499c623cf" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.42" + "@babel/plugin-transform-arrow-functions@7.0.0-beta.42": version "7.0.0-beta.42" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0-beta.42.tgz#b918eb8760c38d6503a1a9858fa073786b60ab2b" @@ -571,6 +577,13 @@ dependencies: "@babel/helper-plugin-utils" "7.0.0-beta.42" +"@babel/plugin-transform-typescript@7.0.0-beta.42": + version "7.0.0-beta.42" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.0.0-beta.42.tgz#e3a2d46014fd26e0729fd574b521fca4eb21144f" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.42" + "@babel/plugin-syntax-typescript" "7.0.0-beta.42" + "@babel/plugin-transform-unicode-regex@7.0.0-beta.42": version "7.0.0-beta.42" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0-beta.42.tgz#1e7bdcf678d9a9066d06e6d334ab41ca11ca00ad" @@ -641,6 +654,13 @@ "@babel/plugin-transform-react-jsx-self" "7.0.0-beta.42" "@babel/plugin-transform-react-jsx-source" "7.0.0-beta.42" +"@babel/preset-typescript@7.0.0-beta.42": + version "7.0.0-beta.42" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.0.0-beta.42.tgz#adb91d387a6eee7b45918de544d6c8fa122c2564" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.42" + "@babel/plugin-transform-typescript" "7.0.0-beta.42" + "@babel/runtime@7.0.0-beta.42": version "7.0.0-beta.42" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.42.tgz#352e40c92e0460d3e82f49bd7e79f6cda76f919f" @@ -751,6 +771,12 @@ postcss-loader "^2.0.10" style-loader "^0.19.1" +"@zeit/next-typescript@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@zeit/next-typescript/-/next-typescript-1.1.0.tgz#57a45c85c336fee8d71c1bd966195565016932b2" + dependencies: + "@babel/preset-typescript" "7.0.0-beta.42" + abab@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"