Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable import assertion syntax parsing #33750

Merged
merged 5 commits into from Mar 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Expand Up @@ -15,7 +15,7 @@
"jsx": true
},
"babelOptions": {
"presets": ["@babel/preset-env", "@babel/preset-react"],
"presets": ["next/babel"],
"caller": {
// Eslint supports top level await when a parser for it is included. We enable the parser by default for Babel.
"supportsTopLevelAwait": true
Expand Down
10 changes: 6 additions & 4 deletions examples/cms-tina/.tina/__generated__/types.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -139,7 +139,7 @@
"postcss-short-size": "4.0.0",
"postcss-trolling": "0.1.7",
"pre-commit": "1.2.2",
"prettier": "2.3.2",
"prettier": "2.5.1",
"pretty-bytes": "5.3.0",
"pretty-ms": "7.0.0",
"random-seed": "0.3.0",
Expand All @@ -165,7 +165,7 @@
"tree-kill": "1.2.2",
"tsec": "0.2.1",
"turbo": "1.0.28",
"typescript": "4.4.3",
"typescript": "4.5.5",
"wait-port": "0.2.2",
"web-streams-polyfill": "2.1.1",
"webpack": "link:./node_modules/webpack5",
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-config-next/package.json
Expand Up @@ -11,7 +11,7 @@
"dependencies": {
"@next/eslint-plugin-next": "12.1.1-canary.6",
"@rushstack/eslint-patch": "1.0.8",
"@typescript-eslint/parser": "5.0.0",
"@typescript-eslint/parser": "5.10.1",
"eslint-import-resolver-node": "0.3.4",
"eslint-import-resolver-typescript": "2.4.0",
"eslint-plugin-import": "2.25.2",
Expand Down
1 change: 1 addition & 0 deletions packages/next/build/babel/preset.ts
Expand Up @@ -158,6 +158,7 @@ export default (
},
],
require('next/dist/compiled/babel/plugin-syntax-dynamic-import'),
require('next/dist/compiled/babel/plugin-syntax-import-assertions'),
require('./plugins/react-loadable-plugin'),
[
require('next/dist/compiled/babel/plugin-proposal-class-properties'),
Expand Down
5 changes: 4 additions & 1 deletion packages/next/build/swc/options.js
Expand Up @@ -18,6 +18,7 @@ export function getParserOptions({ filename, jsConfig, ...rest }) {
decorators: enableDecorators,
// Exclude regular TypeScript files from React transformation to prevent e.g. generic parameters and angle-bracket type assertion from being interpreted as JSX tags.
[isTypeScript ? 'tsx' : 'jsx']: isTSFile ? false : true,
importAssertions: true,
}
}

Expand Down Expand Up @@ -48,7 +49,9 @@ function getBaseSWCOptions({
}
: {}),
parser: parserConfig,

experimental: {
keepImportAssertions: true,
},
transform: {
// Enables https://github.com/swc-project/swc/blob/0359deb4841be743d73db4536d4a22ac797d7f65/crates/swc_ecma_ext_transforms/src/jest.rs
...(jest
Expand Down
10 changes: 10 additions & 0 deletions packages/next/bundles/babel/bundle.js
Expand Up @@ -40,6 +40,10 @@ function generator() {
return require('@babel/generator')
}

function parser() {
return require('@babel/parser')
}

function eslintParser() {
return require('next/dist/compiled/babel-packages').eslintParser()
}
Expand Down Expand Up @@ -68,6 +72,10 @@ function pluginSyntaxDynamicImport() {
return require('next/dist/compiled/babel-packages').pluginSyntaxDynamicImport()
}

function pluginSyntaxImportAssertions() {
return require('next/dist/compiled/babel-packages').pluginSyntaxImportAssertions()
}

function pluginSyntaxJsx() {
return require('next/dist/compiled/babel-packages').pluginSyntaxJsx()
}
Expand Down Expand Up @@ -112,12 +120,14 @@ module.exports = {
generator,
traverse,
eslintParser,
parser,
pluginProposalClassProperties,
pluginProposalExportNamespaceFrom,
pluginProposalNumericSeparator,
pluginProposalObjectRestSpread,
pluginSyntaxBigint,
pluginSyntaxDynamicImport,
pluginSyntaxImportAssertions,
pluginSyntaxJsx,
pluginTransformDefine,
pluginTransformModulesCommonjs,
Expand Down
5 changes: 5 additions & 0 deletions packages/next/bundles/babel/packages-bundle.js
Expand Up @@ -28,6 +28,10 @@ function pluginSyntaxDynamicImport() {
return require('@babel/plugin-syntax-dynamic-import')
}

function pluginSyntaxImportAssertions() {
return require('@babel/plugin-syntax-import-assertions')
}

function pluginSyntaxJsx() {
return require('@babel/plugin-syntax-jsx')
}
Expand Down Expand Up @@ -68,6 +72,7 @@ module.exports = {
pluginProposalObjectRestSpread,
pluginSyntaxBigint,
pluginSyntaxDynamicImport,
pluginSyntaxImportAssertions,
pluginSyntaxJsx,
pluginTransformDefine,
pluginTransformModulesCommonjs,
Expand Down
1 change: 1 addition & 0 deletions packages/next/bundles/babel/packages/parser.js
@@ -0,0 +1 @@
module.exports = require('./bundle').parser()
@@ -0,0 +1 @@
module.exports = require('./bundle').pluginSyntaxImportAssertions()
184 changes: 92 additions & 92 deletions packages/next/compiled/babel-packages/packages-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/next/compiled/babel/bundle.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/next/compiled/babel/parser.js
@@ -0,0 +1 @@
module.exports = require('./bundle').parser()
@@ -0,0 +1 @@
module.exports = require('./bundle').pluginSyntaxImportAssertions()
3 changes: 2 additions & 1 deletion packages/next/package.json
Expand Up @@ -97,14 +97,15 @@
"@ampproject/toolbox-optimizer": "2.7.1-alpha.0",
"@babel/code-frame": "7.12.11",
"@babel/core": "7.15.0",
"@babel/eslint-parser": "7.13.14",
"@babel/eslint-parser": "7.15.0",
"@babel/generator": "7.15.0",
"@babel/plugin-proposal-class-properties": "7.14.5",
"@babel/plugin-proposal-export-namespace-from": "7.14.5",
"@babel/plugin-proposal-numeric-separator": "7.14.5",
"@babel/plugin-proposal-object-rest-spread": "7.14.7",
"@babel/plugin-syntax-bigint": "7.8.3",
"@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/plugin-syntax-import-assertions": "7.16.7",
"@babel/plugin-syntax-jsx": "7.14.5",
"@babel/plugin-transform-modules-commonjs": "7.15.0",
"@babel/plugin-transform-runtime": "7.15.0",
Expand Down
15 changes: 14 additions & 1 deletion packages/next/taskfile-swc.js
Expand Up @@ -11,7 +11,11 @@ module.exports = function (task) {
task.plugin(
'swc',
{},
function* (file, serverOrClient, { stripExtension, dev } = {}) {
function* (
file,
serverOrClient,
{ stripExtension, keepImportAssertions = false } = {}
) {
// Don't compile .d.ts
if (file.base.endsWith('.d.ts')) return

Expand All @@ -29,8 +33,12 @@ module.exports = function (task) {
parser: {
syntax: 'typescript',
dynamicImport: true,
importAssertions: true,
tsx: file.base.endsWith('.tsx'),
},
experimental: {
keepImportAssertions,
},
transform: {
react: {
pragma: 'React.createElement',
Expand Down Expand Up @@ -59,8 +67,12 @@ module.exports = function (task) {
parser: {
syntax: 'typescript',
dynamicImport: true,
importAssertions: true,
tsx: file.base.endsWith('.tsx'),
},
experimental: {
keepImportAssertions,
},
transform: {
react: {
pragma: 'React.createElement',
Expand All @@ -82,6 +94,7 @@ module.exports = function (task) {
const options = {
filename: path.join(file.dir, file.base),
sourceMaps: true,
inlineSourcesContent: false,
sourceFileName: path.relative(distFilePath, fullFilePath),

...swcOptions,
Expand Down
23 changes: 19 additions & 4 deletions packages/next/taskfile.js
Expand Up @@ -781,6 +781,7 @@ const babelCorePackages = {
'@babel/traverse': 'next/dist/compiled/babel/traverse',
'@babel/types': 'next/dist/compiled/babel/types',
'@babel/core': 'next/dist/compiled/babel/core',
'@babel/parser': 'next/dist/compiled/babel/parser',
'@babel/core/lib/config': 'next/dist/compiled/babel/core-lib-config',
'@babel/core/lib/transformation/normalize-file':
'next/dist/compiled/babel/core-lib-normalize-config',
Expand Down Expand Up @@ -815,6 +816,20 @@ export async function ncc_babel_bundle(task, opts) {

// eslint-disable-next-line camelcase
export async function ncc_babel_bundle_packages(task, opts) {
const eslintParseFile = join(
dirname(require.resolve('@babel/eslint-parser')),
'./parse.cjs'
)
const content = fs.readFileSync(eslintParseFile, 'utf-8')
// Let parser.cjs require @babel/parser directly
const replacedContent = content
.replace(
`const babelParser = require((`,
`function noop(){};\nconst babelParser = require('@babel/parser');noop((`
)
.replace(/require.resolve/g, 'noop')
await fs.writeFile(eslintParseFile, replacedContent)

await task
.source(opts.src || 'bundles/babel/packages-bundle.js')
.ncc({
Expand Down Expand Up @@ -1810,28 +1825,28 @@ export async function nextbuildstatic(task, opts) {
export async function pages_app(task, opts) {
await task
.source('pages/_app.tsx')
.swc('client', { dev: opts.dev })
.swc('client', { dev: opts.dev, keepImportAssertions: true })
.target('dist/pages')
}

export async function pages_error(task, opts) {
await task
.source('pages/_error.tsx')
.swc('client', { dev: opts.dev })
.swc('client', { dev: opts.dev, keepImportAssertions: true })
.target('dist/pages')
}

export async function pages_document(task, opts) {
await task
.source('pages/_document.tsx')
.swc('server', { dev: opts.dev })
.swc('server', { dev: opts.dev, keepImportAssertions: true })
.target('dist/pages')
}

export async function pages_document_server(task, opts) {
await task
.source('pages/_document-concurrent.tsx')
.swc('client', { dev: opts.dev })
.swc('client', { dev: opts.dev, keepImportAssertions: true })
.target('dist/pages')
}

Expand Down
2 changes: 2 additions & 0 deletions test/integration/eslint/eslint-cache-custom-dir/.gitignore
@@ -0,0 +1,2 @@
build

1 change: 1 addition & 0 deletions test/integration/eslint/first-time-setup/.eslintrc.json
@@ -0,0 +1 @@
{ "extends": "next", "root": true }
8 changes: 5 additions & 3 deletions test/integration/eslint/test/index.test.js
Expand Up @@ -254,7 +254,7 @@ describe('ESLint', () => {
})

test('shows a successful message when completed', async () => {
const { stdout, eslintrcJson } = await nextLintTemp()
const { stdout } = await nextLintTemp()

expect(stdout).toContain(
'ESLint has successfully been configured. Run next lint again to view warnings and errors'
Expand Down Expand Up @@ -332,7 +332,7 @@ describe('ESLint', () => {

test('success message when no warnings or errors', async () => {
const eslintrcJson = join(dirFirstTimeSetup, '.eslintrc.json')
await fs.writeFile(eslintrcJson, '{ "extends": "next", "root": true }')
await fs.writeFile(eslintrcJson, '{ "extends": "next", "root": true }\n')

const { stdout, stderr } = await nextLint(dirFirstTimeSetup, [], {
stdout: true,
Expand Down Expand Up @@ -511,7 +511,9 @@ describe('ESLint', () => {
await fs.remove(cacheFile)
await nextLint(dirEslintCache, ['--cache-location', cacheFile])

expect(fs.existsSync(cacheFile)).toBe(true)
const hasCache = fs.existsSync(cacheFile)
await fs.remove(cacheFile) // remove after generate
expect(hasCache).toBe(true)
})

const getEslintCacheContent = async (cacheDir) => {
Expand Down
3 changes: 3 additions & 0 deletions test/integration/import-assertion/data
@@ -0,0 +1,3 @@
{
"foo": "foo"
}
2 changes: 2 additions & 0 deletions test/integration/import-assertion/data.d.ts
@@ -0,0 +1,2 @@
declare const data: any
export default data
5 changes: 5 additions & 0 deletions test/integration/import-assertion/pages/es.js
@@ -0,0 +1,5 @@
import data from '../data' assert { type: 'json' }

export default function Es() {
return data.foo
}
5 changes: 5 additions & 0 deletions test/integration/import-assertion/pages/ts.ts
@@ -0,0 +1,5 @@
import data from '../data' assert { type: 'json' }

export default function Ts() {
return data.foo
}
45 changes: 45 additions & 0 deletions test/integration/import-assertion/test/index.test.js
@@ -0,0 +1,45 @@
import { join } from 'path'
import {
nextBuild,
nextStart,
launchApp,
killApp,
findPort,
renderViaHTTP,
} from 'next-test-utils'

const appDir = join(__dirname, '../')

function runSuite(suiteName, env, runTests) {
const context = { appDir }
describe(`${suiteName} ${env}`, () => {
if (env === 'prod') {
beforeAll(async () => {
context.appPort = await findPort()
await nextBuild(context.appDir)
context.server = await nextStart(context.appDir, context.appPort)
})
}
if (env === 'dev') {
beforeAll(async () => {
context.appPort = await findPort()
context.server = await launchApp(context.appDir, context.appPort)
})
}
afterAll(async () => await killApp(context.server))

runTests(context, env)
})
}

function basic(context) {
it('should handle json assertions', async () => {
const esHtml = await renderViaHTTP(context.appPort, '/es')
const tsHtml = await renderViaHTTP(context.appPort, '/ts')
expect(esHtml).toContain('foo')
expect(tsHtml).toContain('foo')
})
}

runSuite('import-assertion', 'dev', basic)
runSuite('import-assertion', 'prod', basic)
20 changes: 20 additions & 0 deletions test/integration/import-assertion/tsconfig.json
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"incremental": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"exclude": ["node_modules"],
"include": ["**/*.d.ts", "**/*.ts", "**/*.tsx"]
}