From 5c15284a90d32fc81c6a8006884c7727683733b6 Mon Sep 17 00:00:00 2001
From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com>
Date: Wed, 21 Jun 2023 23:50:52 +0300
Subject: [PATCH] test: case for watch/serve and reemitting assets (#1812)
---
spec/fixtures/html-template-with-image.html | 13 ++
spec/hot.spec.js | 137 ++++++++++++++++++++
2 files changed, 150 insertions(+)
create mode 100644 spec/fixtures/html-template-with-image.html
diff --git a/spec/fixtures/html-template-with-image.html b/spec/fixtures/html-template-with-image.html
new file mode 100644
index 00000000..5e55a3d4
--- /dev/null
+++ b/spec/fixtures/html-template-with-image.html
@@ -0,0 +1,13 @@
+
+
+
+
+ Test
+
+
+Some unique text
+
+
+
+
+
diff --git a/spec/hot.spec.js b/spec/hot.spec.js
index a2d2c7f9..2a99be6e 100644
--- a/spec/hot.spec.js
+++ b/spec/hot.spec.js
@@ -20,6 +20,7 @@ const DEFAULT_LOADER = require.resolve('../lib/loader.js') + '?force';
const DEFAULT_TEMPLATE = DEFAULT_LOADER + '!' + require.resolve('../default_index.ejs');
jest.setTimeout(30000);
+
process.on('unhandledRejection', r => console.log(r));
describe('HtmlWebpackPluginHMR', () => {
@@ -85,4 +86,140 @@ describe('HtmlWebpackPluginHMR', () => {
})
.then(() => compiler.stopWatching());
});
+
+ it('should re-emit favicon and assets from a loader if watch is active', () => {
+ const template = path.join(__dirname, './fixtures/html-template-with-image.html');
+ const config = {
+ mode: 'development',
+ entry: path.join(__dirname, 'fixtures/index.js'),
+ output: {
+ assetModuleFilename: '[name][ext]',
+ path: OUTPUT_DIR
+ },
+ module: {
+ rules: [
+ {
+ test: /\.html$/,
+ loader: 'html-loader'
+ }
+ ]
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ favicon: path.join(__dirname, './fixtures/favicon.ico'),
+ template
+ })
+ ]
+ };
+
+ const templateContent = fs.readFileSync(template, 'utf-8');
+ const compiler = new WebpackRecompilationSimulator(webpack(config));
+ const jsFileTempPath = compiler.addTestFile(path.join(__dirname, 'fixtures/index.js'));
+ const expected = ['logo.png', 'main.js', 'favicon.ico', 'index.html'];
+
+ return compiler.startWatching()
+ // Change the template file and compile again
+ .then((stats) => {
+ expect(expected.every(val => Object.keys(stats.compilation.assets).includes(val))).toBe(true);
+ expect(stats.compilation.errors).toEqual([]);
+ expect(stats.compilation.warnings).toEqual([]);
+
+ fs.writeFileSync(jsFileTempPath, 'module.exports = function calc(a, b){ return a - b };');
+
+ return compiler.waitForWatchRunComplete();
+ })
+ .then(stats => {
+ expect(expected.every(val => Object.keys(stats.compilation.assets).includes(val))).toBe(true);
+ expect(stats.compilation.errors).toEqual([]);
+ expect(stats.compilation.warnings).toEqual([]);
+
+ fs.writeFileSync(template, templateContent.replace(/Some unique text/, 'Some other unique text'));
+
+ return compiler.waitForWatchRunComplete();
+ })
+ .then((stats) => {
+ expect(expected.every(val => Object.keys(stats.compilation.assets).includes(val))).toBe(true);
+ expect(stats.compilation.errors).toEqual([]);
+ expect(stats.compilation.warnings).toEqual([]);
+
+ fs.writeFileSync(template, templateContent);
+ })
+ .then(() => compiler.stopWatching());
+ });
+
+ it('should re-emit favicon and assets from a loader if watch is active and clean enabled', () => {
+ const expected = ['logo.png', 'main.js', 'favicon.ico', 'index.html'];
+
+ class MyPlugin {
+ apply (compiler) {
+ compiler.hooks.thisCompilation.tap({ name: this.constructor.name }, (compilation) => {
+ return compilation.hooks.processAssets.tap(
+ { name: this.constructor.name, stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ANALYSE },
+ (assets) => {
+ expect(expected.every(val => Object.keys(assets).includes(val))).toBe(true);
+ }
+ );
+ });
+ }
+ }
+
+ const template = path.join(__dirname, './fixtures/html-template-with-image.html');
+ const config = {
+ mode: 'development',
+ entry: path.join(__dirname, 'fixtures/index.js'),
+ output: {
+ clean: true,
+ assetModuleFilename: '[name][ext]',
+ path: OUTPUT_DIR
+ },
+ module: {
+ rules: [
+ {
+ test: /\.html$/,
+ loader: 'html-loader'
+ }
+ ]
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ favicon: path.join(__dirname, './fixtures/favicon.ico'),
+ template
+ }),
+ new MyPlugin()
+ ]
+ };
+
+ const templateContent = fs.readFileSync(template, 'utf-8');
+ const compiler = new WebpackRecompilationSimulator(webpack(config));
+ const jsFileTempPath = compiler.addTestFile(path.join(__dirname, 'fixtures/index.js'));
+
+ return compiler.startWatching()
+ // Change the template file and compile again
+ .then((stats) => {
+ expect(expected.every(val => Object.keys(stats.compilation.assets).includes(val))).toBe(true);
+ expect(stats.compilation.errors).toEqual([]);
+ expect(stats.compilation.warnings).toEqual([]);
+
+ fs.writeFileSync(jsFileTempPath, 'module.exports = function calc(a, b){ return a - b };');
+
+ return compiler.waitForWatchRunComplete();
+ })
+ .then(stats => {
+ expect(expected.every(val => Object.keys(stats.compilation.assets).includes(val))).toBe(true);
+ expect(stats.compilation.errors).toEqual([]);
+ expect(stats.compilation.warnings).toEqual([]);
+
+ fs.writeFileSync(template, templateContent.replace(/Some unique text/, 'Some other unique text'));
+
+ return compiler.waitForWatchRunComplete();
+ })
+ .then((stats) => {
+ expect(expected.every(val => Object.keys(stats.compilation.assets).includes(val))).toBe(true);
+ expect(stats.compilation.errors).toEqual([]);
+ expect(stats.compilation.warnings).toEqual([]);
+
+ fs.writeFileSync(template, templateContent);
+ })
+ .then(() => compiler.stopWatching());
+ });
});