Create React aliases for SVG components (#67104)
This commit is contained in:
parent
c8925c36db
commit
d824059439
6 changed files with 104 additions and 14 deletions
|
@ -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
|
||||
}
|
||||
|
|
9
test/e2e/app-dir/react-owner-stacks-svgr/app/layout.tsx
Normal file
9
test/e2e/app-dir/react-owner-stacks-svgr/app/layout.tsx
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { ReactNode } from 'react'
|
||||
|
||||
export default function Root({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
5
test/e2e/app-dir/react-owner-stacks-svgr/app/page.tsx
Normal file
5
test/e2e/app-dir/react-owner-stacks-svgr/app/page.tsx
Normal file
|
@ -0,0 +1,5 @@
|
|||
import Icon from '../public/test.svg'
|
||||
|
||||
export default function Page() {
|
||||
return <Icon />
|
||||
}
|
25
test/e2e/app-dir/react-owner-stacks-svgr/next.config.js
Normal file
25
test/e2e/app-dir/react-owner-stacks-svgr/next.config.js
Normal file
|
@ -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
test/e2e/app-dir/react-owner-stacks-svgr/public/test.svg
Normal file
10
test/e2e/app-dir/react-owner-stacks-svgr/public/test.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400" preserveAspectRatio="xMidYMid meet">
|
||||
<g transform="translate(0.000000,400.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none">
|
||||
<path d="M0 2000 l0 -2000 2000 0 2000 0 0 2000 0 2000 -2000 0 -2000 0 0
|
||||
-2000z m2401 118 l396 -693 -398 -3 c-220 -1 -578 -1 -798 0 l-398 3 396 693
|
||||
c217 380 398 692 401 692 3 0 184 -312 401 -692z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 601 B |
|
@ -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
|
||||
;(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…
Reference in a new issue