diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 9a72997afdacb4206f2c33f4f233d32daf84a327..969eb4a486bfef72dbdf8bcf99985d78cae1a28a 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -51,6 +51,7 @@ import WebpackConformancePlugin, { ReactSyncScriptsConformanceCheck, } from './webpack/plugins/webpack-conformance-plugin' import { WellKnownErrorsPlugin } from './webpack/plugins/wellknown-errors-plugin' +import { codeFrameColumns } from '@babel/code-frame' type ExcludesFalse = (x: T | false) => x is T @@ -65,7 +66,16 @@ const escapePathVariables = (value: any) => { function parseJsonFile(path: string) { const JSON5 = require('next/dist/compiled/json5') const contents = readFileSync(path) - return JSON5.parse(contents) + try { + return JSON5.parse(contents) + } catch (err) { + const codeFrame = codeFrameColumns( + String(contents), + { start: { line: err.lineNumber, column: err.columnNumber } }, + { message: err.message, highlightCode: true } + ) + throw new Error(`Failed to parse "${path}":\n${codeFrame}`) + } } function getOptimizedAliases(isServer: boolean): { [pkg: string]: string } { diff --git a/packages/next/package.json b/packages/next/package.json index bcd5bbe8aa5833ee513017346ef63b689431b97b..156fbabd95b7ce774f361b4fc74382ff930ea05e 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -59,6 +59,7 @@ }, "dependencies": { "@ampproject/toolbox-optimizer": "2.3.1", + "@babel/code-frame": "7.8.3", "@babel/core": "7.7.7", "@babel/plugin-proposal-class-properties": "7.8.3", "@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3", @@ -119,6 +120,7 @@ "@taskr/esnext": "1.1.0", "@taskr/watch": "1.1.0", "@types/amphtml-validator": "1.0.0", + "@types/babel__code-frame": "7.0.1", "@types/babel__core": "7.1.7", "@types/babel__generator": "7.6.1", "@types/babel__template": "7.0.2", diff --git a/test/integration/jsconfig/jsconfig.json b/test/integration/jsconfig/jsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..0967ef424bce6791893e9a57bb952f80fd536e93 --- /dev/null +++ b/test/integration/jsconfig/jsconfig.json @@ -0,0 +1 @@ +{} diff --git a/test/integration/jsconfig/pages/hello.js b/test/integration/jsconfig/pages/hello.js new file mode 100644 index 0000000000000000000000000000000000000000..447b3a0a99096752d7809800984bcd57b4fd5514 --- /dev/null +++ b/test/integration/jsconfig/pages/hello.js @@ -0,0 +1 @@ +export default () =>
hello world
diff --git a/test/integration/jsconfig/test/index.test.js b/test/integration/jsconfig/test/index.test.js new file mode 100644 index 0000000000000000000000000000000000000000..531231a100249d78d4c89a5f2d117e747cf90dd7 --- /dev/null +++ b/test/integration/jsconfig/test/index.test.js @@ -0,0 +1,35 @@ +/* eslint-env jest */ + +import fs from 'fs-extra' +import { join } from 'path' +import { nextBuild } from 'next-test-utils' + +jest.setTimeout(1000 * 60 * 2) + +const appDir = join(__dirname, '..') + +describe('jsconfig.json', () => { + it('should build normally', async () => { + const res = await await nextBuild(appDir, [], { stdout: true }) + expect(res.stdout).toMatch(/Compiled successfully\./) + }) + + it('should fail on invalid jsconfig.json', async () => { + const jsconfigPath = join(appDir, 'jsconfig.json') + const originalJsconfig = await fs.readFile(jsconfigPath, { + encoding: 'utf-8', + }) + await fs.writeFile(jsconfigPath, '{', { + encoding: 'utf-8', + }) + try { + const res = await nextBuild(appDir, [], { stderr: true }) + expect(res.stderr).toMatch(/Error: Failed to parse "/) + expect(res.stderr).toMatch(/JSON5: invalid end of input at 1:2/) + } finally { + await fs.writeFile(jsconfigPath, originalJsconfig, { + encoding: 'utf-8', + }) + } + }) +}) diff --git a/yarn.lock b/yarn.lock index 30740eda0054d4f456fdaa3f00a15f2b5878a71d..da5d9c244bdc41e19f6ddb544a209c8c7f8207b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2689,6 +2689,11 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/babel__code-frame@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@types/babel__code-frame/-/babel__code-frame-7.0.1.tgz#baf2529c4abbfb5e4008c845efcfe39a187e2f99" + integrity sha512-FFfbQozKxYmOnCKFYV+EQprjBI7u2yaNc2ly/K9AhzyC8MzXtCtSRqptpw+HUJxhwCOo5mLwf1ATmzyhOaVbDg== + "@types/babel__core@7.1.7", "@types/babel__core@^7.1.7": version "7.1.7" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89"