Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,10 @@ export default async function getBaseWebpackConfig(
: []),
{
test: /\.(tsx|ts|js|mjs|jsx)$/,
include: [dir, ...babelIncludeRegexes],
...(config.experimental.externalDir
? // Allowing importing TS/TSX files from outside of the root dir.
{}
: { include: [dir, ...babelIncludeRegexes] }),
exclude: (excludePath: string) => {
if (babelIncludeRegexes.some((r) => r.test(excludePath))) {
return false
Expand Down Expand Up @@ -1042,6 +1045,9 @@ export default async function getBaseWebpackConfig(
'process.env.__NEXT_SCROLL_RESTORATION': JSON.stringify(
config.experimental.scrollRestoration
),
'process.env.__NEXT_EXTERNAL_DIR': JSON.stringify(
config.experimental.externalDir
),
'process.env.__NEXT_IMAGE_OPTS': JSON.stringify({
deviceSizes: config.images.deviceSizes,
imageSizes: config.images.imageSizes,
Expand Down
1 change: 1 addition & 0 deletions packages/next/next-server/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const defaultConfig: NextConfig = {
scrollRestoration: false,
scriptLoader: false,
stats: false,
externalDir: false,
},
future: {
strictPostcssConfiguration: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react'

export function World(): JSX.Element {
return <>World</>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
onDemandEntries: {
// Make sure entries are not getting disposed.
maxInactiveAge: 1000 * 60 * 60,
},
experimental: {
externalDir: true,
},
}
16 changes: 16 additions & 0 deletions test/integration/typescript-external-dir/project/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react'

import { World } from 'components/world'

// External
import { Counter } from '../../shared/components/counter'

export default function HelloPage(): JSX.Element {
return (
<div>
Hello <World />!
<br />
<Counter />
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-env jest */

import { join } from 'path'
import cheerio from 'cheerio'
import { renderViaHTTP, findPort, launchApp, killApp } from 'next-test-utils'

jest.setTimeout(1000 * 60 * 2)

const appDir = join(__dirname, '..')
let appPort
let app

async function get$(path, query) {
const html = await renderViaHTTP(appPort, path, query)
return cheerio.load(html)
}

describe('TypeScript Features', () => {
describe('default behavior', () => {
beforeAll(async () => {
appPort = await findPort()
app = await launchApp(appDir, appPort, {})
})
afterAll(() => killApp(app))

it('should render the page with external TS/TSX dependencies', async () => {
const $ = await get$('/')
expect($('body').text()).toMatch(/Hello World!Counter: 0/)
})
})
})
20 changes: 20 additions & 0 deletions test/integration/typescript-external-dir/project/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"baseUrl": ".",
"esModuleInterop": true,
"module": "esnext",
"jsx": "preserve",
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true
},
"exclude": ["node_modules"],
"include": ["next-env.d.ts", "components", "pages"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React, { useState } from 'react'

import inc from '../libs/inc'

export function Counter(): JSX.Element {
const [x, setX] = useState(0)
return (
<button id="counter" onClick={() => setX(inc(x))}>
Counter: {x}
</button>
)
}
3 changes: 3 additions & 0 deletions test/integration/typescript-external-dir/shared/libs/inc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function inc(x: number) {
return x + 1
}
18 changes: 18 additions & 0 deletions test/integration/typescript-external-dir/shared/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"esModuleInterop": true,
"module": "esnext",
"jsx": "preserve",
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true
},
"include": ["components", "libs"]
}