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

Multiple assets emit different content to the same filename #7129

Closed
Rudolphous opened this issue Jul 11, 2024 · 2 comments
Closed

Multiple assets emit different content to the same filename #7129

Rudolphous opened this issue Jul 11, 2024 · 2 comments
Labels
bug Something isn't working pending triage The issue/PR is currently untouched.

Comments

@Rudolphous
Copy link

Rudolphous commented Jul 11, 2024

System Info

System:
OS: macOS 14.5
CPU: (10) arm64 Apple M1 Pro
Memory: 1.34 GB / 32.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 18.19.0 - ~/.nvm/versions/node/v18.19.0/bin/node
npm: 10.2.5 - ~/.nvm/versions/node/v18.19.0/bin/npm
Browsers:
Chrome: 126.0.6478.127
Safari: 17.5
npmPackages:
@rspack/cli: 1.0.0-alpha.3 => 1.0.0-alpha.3
@rspack/core: 1.0.0-alpha.3 => 1.0.0-alpha.3

Details

The following plugin works with rspack 0.7.5 and works with WebPack but gives errors after upgrading to 1.0.0-alpha.3 :

It prints the following errors:

ERROR in × Conflict: Multiple assets emit different content to the same filename index-nl-NL.html
ERROR in × Conflict: Multiple assets emit different content to the same filename index-ro-RO-demo.html
ERROR in × Conflict: Multiple assets emit different content to the same filename index-ro-RO.html
ERROR in × Conflict: Multiple assets emit different content to the same filename index.html
etc

It's unclear why this is or how this should be fixed.
We could not find changes related to emitAsset in the release notes.

Plugin code that does not work

const { injectPolyfillsLoader } = require('@web/polyfills-loader');

const {
  findElements,
  findElement,
  appendChild,
  createElement,
  getAttribute,
  getTagName,
  remove,
} = require('@web/parse5-utils');
const { parse, serialize } = require('parse5');
const path = require('path');
const fs = require('fs');

const polyfillsLoaderConfig = require('../polyfillsLoaderConfig.js');

function extractRollupScript(documentAst, rollupEntryName) {
  const scripts = findElements(documentAst, e => getTagName(e) === 'script');

  for (const script of scripts) {
    const src = getAttribute(script, 'src');
    if (src?.includes(rollupEntryName)) {
      remove(script);
    }
  }

  const links = findElements(documentAst, e => getTagName(e) === 'link');
  for (const link of links) {
    const href = getAttribute(link, 'href');
    if (href?.includes(rollupEntryName)) {
      remove(link);
    }
  }
}

function injectRspackScript(documentAst, rspackEntryNames) {
  for (const rspackEntryName of rspackEntryNames) {
    const script = createElement('script', { src: `./${rspackEntryName}` });
    const body = findElement(documentAst, e => getTagName(e) === 'body');
    appendChild(body, script);
  }
}

class RspackIndexHTMLPlugin {
  htmlFiles = [];

  polyfillFiles = [];

  constructor({ rollupDir, rollupEntryName } = {}) {
    this.rollupEntryName = rollupEntryName;

    for (const name of fs.readdirSync(rollupDir)) {
      if (name.endsWith('.html')) {
        const content = fs.readFileSync(path.join(rollupDir, name), 'utf-8');
        this.htmlFiles.push({ name, content });
      }
    }
  }

  apply(compiler) {
    compiler.hooks.compilation.tap('RspackIndexHTMLPlugin', compilation => {
      compilation.hooks.processAssets.tapPromise(
        {
          name: 'RspackIndexHTMLPlugin',
          stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
        },
        async () => {
          const { RawSource } = compiler.webpack.sources;
          const entries = [...compilation.entrypoints.values()]
            .map(x => x.getFiles().filter(file => file.endsWith('.js')))
            .flat();

          for (const htmlFile of this.htmlFiles) {
            let htmlString = htmlFile.content;

            const documentAst = parse(htmlString);

            extractRollupScript(documentAst, this.rollupEntryName);

            if (
              polyfillsLoaderConfig?.polyfills &&
              !Object.values(polyfillsLoaderConfig?.polyfills).every(e => e === false)
            ) {
              htmlString = serialize(documentAst);
              const result = await injectPolyfillsLoader(htmlString, {
                minify: true,
                preload: true,
                modern: {
                  files: entries.map(entry => ({ type: 'script', path: entry })),
                },
                ...polyfillsLoaderConfig,
              });
              htmlString = result.htmlString;
              this.polyfillFiles = result.polyfillFiles;
            } else {
              injectRspackScript(documentAst, entries);
              htmlString = serialize(documentAst);
            }
            compilation.emitAsset(htmlFile.name, new RawSource(htmlString));
          }

         for (const polyfillFile of this.polyfillFiles) {
            compilation.emitAsset(polyfillFile.path, new RawSource(polyfillFile.content));
          }
        },
      );
    });
  }
}

module.exports = RspackIndexHTMLPlugin;
@Rudolphous Rudolphous added bug Something isn't working pending triage The issue/PR is currently untouched. labels Jul 11, 2024
@shulaoda
Copy link
Contributor

Is there a reproducible repository?

@Rudolphous
Copy link
Author

After changing emitAsset to updateAsset it works.
Think you can close this ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working pending triage The issue/PR is currently untouched.
Projects
None yet
Development

No branches or pull requests

3 participants