Skip to content

Commit

Permalink
fix: resolve public path base on html-webpack-plugin and webpack config
Browse files Browse the repository at this point in the history
  • Loading branch information
icelam committed Aug 9, 2023
1 parent cea06cd commit c333304
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 8 deletions.
9 changes: 5 additions & 4 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@
}],
"import/extensions": ["error", {
"js": "never",
"ts": "never",
}]
"ts": "never"
}],
"class-methods-use-this": "off"
},
"overrides": [
{
Expand All @@ -51,15 +52,15 @@
"airbnb-base",
"plugin:jest/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended"
],
"env": { "node": true },
"rules": {
"@typescript-eslint/no-var-requires": ["off"],
"no-console": ["off"],
"import/extensions": ["error", {
"js": "never",
"ts": "never",
"ts": "never"
}]
}
}
Expand Down
37 changes: 37 additions & 0 deletions __tests__/HtmlInlineScriptPlugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ignoreHtmlsConfig from './cases/ignore-htmls/webpack.config';
import ignoreScriptsAndHtmlsConfig from './cases/ignore-scripts-and-htmls/webpack.config';
import filenameWithSpecialCharactersConfig from './cases/filename-with-special-characters/webpack.config';
import escapeScriptTagEndConfig from './cases/escape-script-end-tag/webpack.config';
import htmlInsideSubfolderConfig from './cases/html-inside-subfolder/webpack.config';

describe('HtmlInlineScriptPlugin', () => {
it('should build simple webpack config without error', async () => {
Expand Down Expand Up @@ -205,6 +206,42 @@ describe('HtmlInlineScriptPlugin', () => {
await webpackPromise;
});

it('should build webpack config that outputs html file inside subfolder without error', async () => {
const webpackPromise = new Promise((resolve) => {
const compiler = webpack(htmlInsideSubfolderConfig);

compiler.run((error, stats) => {
expect(error).toBeNull();

const statsErrors = stats?.compilation.errors;
expect(statsErrors?.length).toBe(0);

const result = fs.readFileSync(
path.join(__dirname, 'cases/html-inside-subfolder/dist/frontend/index.html'),
'utf8',
);

const expected = fs.readFileSync(
path.join(__dirname, 'cases/html-inside-subfolder/expected/frontend/index.html'),
'utf8',
);
expect(result).toBe(expected);

const expectedParentFileList = fs.readdirSync(path.join(__dirname, 'cases/html-inside-subfolder/expected/'));
const generatedParentFileList = fs.readdirSync(path.join(__dirname, 'cases/html-inside-subfolder/dist/'));
expect(expectedParentFileList.sort()).toEqual(generatedParentFileList.sort());

const expectedChildFileList = fs.readdirSync(path.join(__dirname, 'cases/html-inside-subfolder/expected/'));
const generatedChildFileList = fs.readdirSync(path.join(__dirname, 'cases/html-inside-subfolder/dist/'));
expect(expectedChildFileList.sort()).toEqual(generatedChildFileList.sort());

resolve(true);
});
});

await webpackPromise;
});

it('should inline filename with spacial characters without error', async () => {
const webpackPromise = new Promise((resolve) => {
const compiler = webpack(filenameWithSpecialCharactersConfig);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><meta name="language" content="English"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="minimum-scale=1,initial-scale=1,width=device-width,shrink-to-fit=no"/><title>webpack test</title><script defer="defer">console.log("Hello world");</script></head><body><p>This is minimal code to demonstrate webpack usage</p></body></html>
14 changes: 14 additions & 0 deletions __tests__/cases/html-inside-subfolder/fixtures/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="language" content="English" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" />
<title>webpack test</title>
</head>
<body>
<p>This is minimal code to demonstrate webpack usage</p>
</body>
</html>
2 changes: 2 additions & 0 deletions __tests__/cases/html-inside-subfolder/fixtures/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-console
console.log('Hello world');
22 changes: 22 additions & 0 deletions __tests__/cases/html-inside-subfolder/webpack.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import path from 'path';
import type { Configuration } from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import Self from '../../../dist';

const config: Configuration = {
mode: 'production',
entry: path.join(__dirname, './fixtures/index.js'),
output: {
path: path.join(__dirname, './dist'),
filename: '[name].js'
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, './fixtures/index.html'),
filename: path.join(__dirname, './dist/frontend/index.html')
}),
new Self()
]
};

export default config;
38 changes: 34 additions & 4 deletions src/HtmlInlineScriptPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import path from 'path';
import { Compilation } from 'webpack';
import type { Compiler, WebpackPluginInstance } from 'webpack';
import htmlWebpackPlugin from 'html-webpack-plugin';
Expand Down Expand Up @@ -37,7 +38,7 @@ class HtmlInlineScriptPlugin implements WebpackPluginInstance {
const {
scriptMatchPattern = [/.+[.]js$/],
htmlMatchPattern = [/.+[.]html$/],
assetPreservePattern = [],
assetPreservePattern = []
} = options;

this.scriptMatchPattern = scriptMatchPattern;
Expand All @@ -59,7 +60,6 @@ class HtmlInlineScriptPlugin implements WebpackPluginInstance {
return this.assetPreservePattern.some((test) => assetName.match(test));
}


shouldProcessHtml(
templateName: string
): boolean {
Expand Down Expand Up @@ -102,18 +102,48 @@ class HtmlInlineScriptPlugin implements WebpackPluginInstance {
};
}

apply(compiler: Compiler): void {
let publicPath = compiler.options?.output?.publicPath as string || '';
getPublicPath(
compilation: Compilation,
htmlFileName: string,
customPublicPath: string
): string {
const webpackPublicPath = compilation.getAssetPath(
compilation.outputOptions.publicPath as string,
{ hash: compilation.hash }
);
// Webpack 5 introduced "auto" as default value
const isPublicPathDefined = webpackPublicPath !== 'auto';

let publicPath = '';

if (customPublicPath !== 'auto') {
// If the html-webpack-plugin options contain a custom public path uset it
publicPath = customPublicPath;
} else if (isPublicPathDefined) {
// If a hard coded public path exists in webpack config use it
publicPath = webpackPublicPath;
} else if (compilation.options.output.path) {
// If no public path for webpack and html-webpack-plugin was set get a relative url path
publicPath = path.relative(
path.resolve(compilation.options.output.path, path.dirname(htmlFileName)),
compilation.options.output.path
).split(path.sep).join('/');
}

if (publicPath && !publicPath.endsWith('/')) {
publicPath += '/';
}

return publicPath;
}

apply(compiler: Compiler): void {
compiler.hooks.compilation.tap(`${PLUGIN_PREFIX}_compilation`, (compilation) => {
const hooks = htmlWebpackPlugin.getHooks(compilation);

hooks.alterAssetTags.tap(`${PLUGIN_PREFIX}_alterAssetTags`, (data) => {
const htmlFileName = data.plugin.options?.filename;
const publicPath = this.getPublicPath(compilation, data.outputName, data.publicPath);

if (htmlFileName && !this.shouldProcessHtml(htmlFileName)) {
this.ignoredHtmlFiles.push(htmlFileName);
Expand Down

0 comments on commit c333304

Please sign in to comment.