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

Create React aliases for SVG components #67104

Merged
merged 1 commit into from
Jun 25, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 35 additions & 14 deletions packages/next/src/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2276,29 +2276,50 @@ export default async function getBaseWebpackConfig(
}
}

if (!config.images.disableStaticImages) {
const rules = webpackConfig.module?.rules || []
const hasCustomSvg = rules.some(
(rule) =>
rule &&
const rules = webpackConfig.module?.rules || []

const customSvgRule = rules.find(
(rule): rule is webpack.RuleSetRule =>
(rule &&
typeof rule === 'object' &&
rule.loader !== 'next-image-loader' &&
'test' in rule &&
rule.test instanceof RegExp &&
rule.test.test('.svg')
)
rule.test.test('.svg')) ||
false
)

if (customSvgRule && hasAppDir) {
// Create React aliases for SVG components that were transformed using a
// custom webpack config with e.g. the `@svgr/webpack` loader, or the
// `babel-plugin-inline-react-svg` plugin.
rules.push({
test: customSvgRule.test,
oneOf: [
WEBPACK_LAYERS.reactServerComponents,
WEBPACK_LAYERS.serverSideRendering,
WEBPACK_LAYERS.appPagesBrowser,
].map((layer) => ({
issuerLayer: layer,
resolve: {
alias: createRSCAliases(bundledReactChannel, {
reactProductionProfiling,
layer,
isEdgeServer,
}),
},
})),
})
}

if (!config.images.disableStaticImages) {
const nextImageRule = rules.find(
(rule) =>
rule && typeof rule === 'object' && rule.loader === 'next-image-loader'
)
if (
hasCustomSvg &&
nextImageRule &&
nextImageRule &&
typeof nextImageRule === 'object'
) {
if (customSvgRule && nextImageRule && typeof nextImageRule === 'object') {
// Exclude svg if the user already defined it in custom
// webpack config such as `@svgr/webpack` plugin or
// webpack config such as the `@svgr/webpack` loader, or
// the `babel-plugin-inline-react-svg` plugin.
nextImageRule.test = /\.(png|jpg|jpeg|gif|webp|avif|ico|bmp)$/i
}
Expand Down
9 changes: 9 additions & 0 deletions test/e2e/app-dir/react-owner-stacks-svgr/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ReactNode } from 'react'

export default function Root({ children }: { children: ReactNode }) {
return (
<html>
<body>{children}</body>
</html>
)
}
5 changes: 5 additions & 0 deletions test/e2e/app-dir/react-owner-stacks-svgr/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Icon from '../public/test.svg'

export default function Page() {
return <Icon />
}
25 changes: 25 additions & 0 deletions test/e2e/app-dir/react-owner-stacks-svgr/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
experimental: {
// Enabling PPR to force using the react experimental channel, which
// implements React owner stacks.
ppr: true,
turbo: {
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
},
},
webpack(config) {
config.module.rules.push({ test: /\.svg$/, use: '@svgr/webpack' })

return config
},
}

module.exports = nextConfig
10 changes: 10 additions & 0 deletions test/e2e/app-dir/react-owner-stacks-svgr/public/test.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { nextTestSetup } from 'e2e-utils'

describe('react-owner-stacks-svgr', () => {
const { next, isNextStart, isTurbopack } = nextTestSetup({
files: __dirname,
packageJson: { dependencies: { '@svgr/webpack': '8.1.0' } },
})

/* eslint-disable jest/no-standalone-expect */
// Turbopack currently only supports `next dev` and does not support `next
// build`: https://nextjs.org/docs/architecture/turbopack#unsupported-features
eps1lon marked this conversation as resolved.
Show resolved Hide resolved
;(isNextStart && isTurbopack ? it.skip : it)(
'renders an SVG that is transformed by @svgr/webpack into a React component',
async () => {
const browser = await next.browser('/')
expect(await browser.elementByCss('svg')).toBeDefined()
}
)
/* eslint-enable jest/no-standalone-expect */
})
Loading