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

Update to only add image import types when enabled #26485

Merged
merged 3 commits into from Jun 22, 2021
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
8 changes: 7 additions & 1 deletion packages/next/build/index.ts
Expand Up @@ -192,7 +192,13 @@ export default async function build(
const verifyResult = await nextBuildSpan
.traceChild('verify-typescript-setup')
.traceAsyncFn(() =>
verifyTypeScriptSetup(dir, pagesDir, !ignoreTypeScriptErrors, cacheDir)
verifyTypeScriptSetup(
dir,
pagesDir,
!ignoreTypeScriptErrors,
!config.images.disableStaticImages,
cacheDir
)
)

const typeCheckEnd = process.hrtime(typeCheckStart)
Expand Down
62 changes: 62 additions & 0 deletions packages/next/image-types/global.d.ts
@@ -0,0 +1,62 @@
// this file is conditionally added/removed to next-env.d.ts
// if the static image import handling is enabled

interface StaticImageData {
src: string
height: number
width: number
placeholder?: string
}

declare module '*.png' {
const content: StaticImageData

export default content
}

declare module '*.svg' {
/**
* Use `any` to avoid conflicts with
* `@svgr/webpack` plugin or
* `babel-plugin-inline-react-svg` plugin.
*/
const content: any

export default content
}

declare module '*.jpg' {
const content: StaticImageData

export default content
}

declare module '*.jpeg' {
const content: StaticImageData

export default content
}

declare module '*.gif' {
const content: StaticImageData

export default content
}

declare module '*.webp' {
const content: StaticImageData

export default content
}

declare module '*.ico' {
const content: StaticImageData

export default content
}

declare module '*.bmp' {
const content: StaticImageData

export default content
}
27 changes: 15 additions & 12 deletions packages/next/lib/typescript/writeAppTypeDeclarations.ts
@@ -1,19 +1,22 @@
import { promises as fs } from 'fs'
import os from 'os'
import path from 'path'
import { fileExists } from '../file-exists'

export async function writeAppTypeDeclarations(baseDir: string): Promise<void> {
export async function writeAppTypeDeclarations(
baseDir: string,
imageImportsEnabled: boolean
): Promise<void> {
// Reference `next` types
const appTypeDeclarations = path.join(baseDir, 'next-env.d.ts')
const hasAppTypeDeclarations = await fileExists(appTypeDeclarations)
if (!hasAppTypeDeclarations) {
await fs.writeFile(
appTypeDeclarations,
'/// <reference types="next" />' +
os.EOL +
'/// <reference types="next/types/global" />' +
os.EOL
)
}

await fs.writeFile(
appTypeDeclarations,
'/// <reference types="next" />' +
os.EOL +
'/// <reference types="next/types/global" />' +
os.EOL +
(imageImportsEnabled
? '/// <reference types="next/image-types/global" />' + os.EOL
: '')
)
}
3 changes: 2 additions & 1 deletion packages/next/lib/verifyTypeScriptSetup.ts
Expand Up @@ -18,6 +18,7 @@ export async function verifyTypeScriptSetup(
dir: string,
pagesDir: string,
typeCheckPreflight: boolean,
imageImportsEnabled: boolean,
cacheDir?: string
): Promise<{ result?: TypeCheckResult; version: string | null }> {
const tsConfigPath = path.join(dir, 'tsconfig.json')
Expand Down Expand Up @@ -52,7 +53,7 @@ export async function verifyTypeScriptSetup(
await writeConfigurationDefaults(ts, tsConfigPath, firstTimeSetup)
// Write out the necessary `next-env.d.ts` file to correctly register
// Next.js' types:
await writeAppTypeDeclarations(dir)
await writeAppTypeDeclarations(dir, imageImportsEnabled)

let result
if (typeCheckPreflight) {
Expand Down
7 changes: 6 additions & 1 deletion packages/next/server/next-dev-server.ts
Expand Up @@ -275,7 +275,12 @@ export default class DevServer extends Server {
}

async prepare(): Promise<void> {
await verifyTypeScriptSetup(this.dir, this.pagesDir!, false)
await verifyTypeScriptSetup(
this.dir,
this.pagesDir!,
false,
!this.nextConfig.images.disableStaticImages
)

this.customRoutes = await loadCustomRoutes(this.nextConfig)

Expand Down
60 changes: 0 additions & 60 deletions packages/next/types/global.d.ts
Expand Up @@ -25,63 +25,3 @@ declare module '*.module.scss' {
const classes: { readonly [key: string]: string }
export default classes
}

interface StaticImageData {
src: string
height: number
width: number
placeholder?: string
}

declare module '*.png' {
const content: StaticImageData

export default content
}

declare module '*.svg' {
/**
* Use `any` to avoid conflicts with
* `@svgr/webpack` plugin or
* `babel-plugin-inline-react-svg` plugin.
*/
const content: any

export default content
}

declare module '*.jpg' {
const content: StaticImageData

export default content
}

declare module '*.jpeg' {
const content: StaticImageData

export default content
}

declare module '*.gif' {
const content: StaticImageData

export default content
}

declare module '*.webp' {
const content: StaticImageData

export default content
}

declare module '*.ico' {
const content: StaticImageData

export default content
}

declare module '*.bmp' {
const content: StaticImageData

export default content
}
@@ -1,5 +1,6 @@
module.exports = {
images: {
domains: ['via.placeholder.com'],
// disableStaticImages: true,
},
}
37 changes: 37 additions & 0 deletions test/integration/image-component/typescript/test/index.test.js
@@ -1,5 +1,6 @@
/* eslint-env jest */

import fs from 'fs-extra'
import { join } from 'path'
import {
renderViaHTTP,
Expand All @@ -12,6 +13,7 @@ import {
jest.setTimeout(1000 * 60 * 2)

const appDir = join(__dirname, '..')
const nextConfig = join(appDir, 'next.config.js')
let appPort
let app
let output
Expand All @@ -27,6 +29,23 @@ describe('TypeScript Image Component', () => {
expect(stderr).toMatch(/Failed to compile/)
expect(stderr).toMatch(/is not assignable to type/)
expect(code).toBe(1)
const envTypes = await fs.readFile(join(appDir, 'next-env.d.ts'), 'utf8')
expect(envTypes).toContain('image-types/global')
})

it('should remove global image types when disabled', async () => {
const content = await fs.readFile(nextConfig, 'utf8')
await fs.writeFile(
nextConfig,
content.replace('// disableStaticImages', 'disableStaticImages')
)
const { code, stderr } = await nextBuild(appDir, [], { stderr: true })
expect(stderr).toMatch(/Failed to compile/)
expect(stderr).toMatch(/is not assignable to type/)
expect(code).toBe(1)
styfle marked this conversation as resolved.
Show resolved Hide resolved
await fs.writeFile(nextConfig, content)
const envTypes = await fs.readFile(join(appDir, 'next-env.d.ts'), 'utf8')
expect(envTypes).not.toContain('image-types/global')
})
})

Expand All @@ -41,6 +60,11 @@ describe('TypeScript Image Component', () => {
})
afterAll(() => killApp(app))

it('should have image types when enabled', async () => {
const envTypes = await fs.readFile(join(appDir, 'next-env.d.ts'), 'utf8')
expect(envTypes).toContain('image-types/global')
})

it('should render the valid Image usage and not print error', async () => {
const html = await renderViaHTTP(appPort, '/valid', {})
expect(html).toMatch(/This is valid usage of the Image component/)
Expand All @@ -54,4 +78,17 @@ describe('TypeScript Image Component', () => {
)
})
})

it('should remove global image types when disabled (dev)', async () => {
const content = await fs.readFile(nextConfig, 'utf8')
await fs.writeFile(
nextConfig,
content.replace('// disableStaticImages', 'disableStaticImages')
)
const app = await launchApp(appDir, await findPort(), [])
await killApp(app)
await fs.writeFile(nextConfig, content)
const envTypes = await fs.readFile(join(appDir, 'next-env.d.ts'), 'utf8')
expect(envTypes).not.toContain('image-types/global')
})
})