Skip to content

Commit

Permalink
Update to only add image import types when enabled (#26485)
Browse files Browse the repository at this point in the history
* Update to only add image import types when enabled

* add type check to test
  • Loading branch information
ijjk committed Jun 22, 2021
1 parent 27d78a5 commit 917a9ac
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 75 deletions.
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 change: 1 addition & 0 deletions test/integration/image-component/typescript/next.config.js
@@ -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)
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')
})
})

0 comments on commit 917a9ac

Please sign in to comment.