fix(bundling): separate image and font resources so they do not conflict (#17763)

This commit is contained in:
Jack Hsu 2023-06-26 09:18:27 -04:00 committed by GitHub
parent b736992968
commit 9c0c30edb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 19 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

View File

@ -5,16 +5,20 @@ import {
createFile, createFile,
isNotWindows, isNotWindows,
killPorts, killPorts,
listFiles,
newProject, newProject,
readFile, readFile,
rmDist, rmDist,
runCLI, runCLI,
runCLIAsync, runCLIAsync,
runCypressTests, runCypressTests,
tmpProjPath,
uniq, uniq,
updateFile, updateFile,
updateProjectConfig, updateProjectConfig,
} from '@nx/e2e/utils'; } from '@nx/e2e/utils';
import { join } from 'path';
import { copyFileSync } from 'fs';
describe('Web Components Applications', () => { describe('Web Components Applications', () => {
beforeEach(() => newProject()); beforeEach(() => newProject());
@ -29,24 +33,11 @@ describe('Web Components Applications', () => {
const lintResults = runCLI(`lint ${appName}`); const lintResults = runCLI(`lint ${appName}`);
expect(lintResults).toContain('All files pass linting.'); expect(lintResults).toContain('All files pass linting.');
runCLI(`build ${appName} --outputHashing none --compiler babel`);
checkFilesExist(
`dist/apps/${appName}/index.html`,
`dist/apps/${appName}/runtime.js`,
`dist/apps/${appName}/main.js`,
`dist/apps/${appName}/styles.css`
);
expect(readFile(`dist/apps/${appName}/index.html`)).toContain(
'<link rel="stylesheet" href="styles.css">'
);
const testResults = await runCLIAsync(`test ${appName}`); const testResults = await runCLIAsync(`test ${appName}`);
expect(testResults.combinedOutput).toContain( expect(testResults.combinedOutput).toContain(
'Test Suites: 1 passed, 1 total' 'Test Suites: 1 passed, 1 total'
); );
const lintE2eResults = runCLI(`lint ${appName}-e2e`); const lintE2eResults = runCLI(`lint ${appName}-e2e`);
expect(lintE2eResults).toContain('All files pass linting.'); expect(lintE2eResults).toContain('All files pass linting.');
@ -56,6 +47,55 @@ describe('Web Components Applications', () => {
expect(e2eResults).toContain('All specs passed!'); expect(e2eResults).toContain('All specs passed!');
expect(await killPorts()).toBeTruthy(); expect(await killPorts()).toBeTruthy();
} }
copyFileSync(
join(__dirname, 'test-fixtures/inlined.png'),
join(tmpProjPath(), `apps/${appName}/src/app/inlined.png`)
);
copyFileSync(
join(__dirname, 'test-fixtures/emitted.png'),
join(tmpProjPath(), `apps/${appName}/src/app/emitted.png`)
);
updateFile(
`apps/${appName}/src/app/app.element.ts`,
`
// @ts-ignore
import inlined from './inlined.png';
// @ts-ignore
import emitted from './emitted.png';
export class AppElement extends HTMLElement {
public static observedAttributes = [];
connectedCallback() {
this.innerHTML = \`
<img src="\${inlined} "/>
<img src="\${emitted} "/>
\`;
}
}
customElements.define('app-root', AppElement);
`
);
runCLI(`build ${appName} --outputHashing none --compiler babel`);
checkFilesExist(
`dist/apps/${appName}/index.html`,
`dist/apps/${appName}/runtime.js`,
`dist/apps/${appName}/emitted.png`,
`dist/apps/${appName}/main.js`,
`dist/apps/${appName}/styles.css`
);
checkFilesDoNotExist(`dist/apps/${appName}/inlined.png`);
expect(readFile(`dist/apps/${appName}/main.js`)).toContain(
'<img src="data:image/png;base64'
);
// Should not be a JS module but kept as a PNG
expect(readFile(`dist/apps/${appName}/emitted.png`)).not.toContain(
'export default'
);
expect(readFile(`dist/apps/${appName}/index.html`)).toContain(
'<link rel="stylesheet" href="styles.css">'
);
}, 500000); }, 500000);
it('should remove previous output before building', async () => { it('should remove previous output before building', async () => {

View File

@ -39,7 +39,6 @@
"css-loader": "^6.4.0", "css-loader": "^6.4.0",
"css-minimizer-webpack-plugin": "^5.0.0", "css-minimizer-webpack-plugin": "^5.0.0",
"dotenv": "~10.0.0", "dotenv": "~10.0.0",
"file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "7.2.13", "fork-ts-checker-webpack-plugin": "7.2.13",
"ignore": "^5.0.4", "ignore": "^5.0.4",
"less": "4.1.3", "less": "4.1.3",

View File

@ -409,20 +409,38 @@ export function withWeb(pluginOptions: WithWebOptions = {}): NxWebpackPlugin {
...config.module, ...config.module,
rules: [ rules: [
...(config.module.rules ?? []), ...(config.module.rules ?? []),
// Images: Inline small images, and emit a separate file otherwise.
{ {
test: /\.(bmp|png|jpe?g|gif|webp|avif)$/, test: /\.(avif|bmp|gif|ico|jpe?g|png|webp)$/,
type: 'asset', type: 'asset',
parser: { parser: {
dataUrlCondition: { dataUrlCondition: {
maxSize: 10_000, // 10 kB maxSize: 10_000, // 10 kB
}, },
}, },
generator: {
filename: `[name]${hashFormat.file}[ext]`,
},
}, },
// SVG: same as image but we need to separate it so it can be swapped for SVGR in the React plugin.
{ {
test: /\.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/, test: /\.svg$/,
loader: require.resolve('file-loader'), type: 'asset',
options: { parser: {
name: `[name]${hashFormat.file}.[ext]`, dataUrlCondition: {
maxSize: 10_000, // 10 kB
},
},
generator: {
filename: `[name]${hashFormat.file}[ext]`,
},
},
// Fonts: Emit separate file and export the URL.
{
test: /\.(eot|otf|ttf|woff|woff2)$/,
type: 'asset/resource',
generator: {
filename: `[name]${hashFormat.file}[ext]`,
}, },
}, },
...rules, ...rules,