Skip to content

Commit

Permalink
fix: correct entry script identification and webpack version detect (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
nayonglin authored Dec 14, 2023
1 parent 3e43a11 commit b7ec9e7
Show file tree
Hide file tree
Showing 13 changed files with 13,179 additions and 10,938 deletions.
5 changes: 5 additions & 0 deletions .changeset/serious-nails-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@qiankunjs/webpack-plugin": patch
---

fix: correct entry script identification and webpack version detection in Vue CLI 5
3 changes: 2 additions & 1 deletion packages/webpack-plugin/README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ yarn add @qiankunjs/webpack-plugin --dev
在您的 `webpack.config.js` 或其他配置文件中:

```javascript
const QiankunPlugin = require('@qiankunjs/webpack-plugin');
const { QiankunPlugin } = require('@qiankunjs/webpack-plugin');

module.exports = {
// ... 其他配置
plugins: [
new QiankunPlugin({
packageName: 'optionalPackageName', // 可选,如果不提供,将使用 package.json 中的名称
entrySrcPattern: /index\.js/g, // 可选,用于匹配要添加entry属性的script标签的正则表达式。如果不提供,默认取html最后一个script标签
}),
],
};
Expand Down
3 changes: 2 additions & 1 deletion packages/webpack-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ yarn add @qiankunjs/webpack-plugin --dev
In your `webpack.config.js` or other configuration files:

```javascript
const QiankunPlugin = require('@qiankunjs/webpack-plugin');
const { QiankunPlugin } = require('@qiankunjs/webpack-plugin');

module.exports = {
// ... other configurations
plugins: [
new QiankunPlugin({
packageName: 'optionalPackageName', // Optional, if not provided, the name from package.json will be used
entrySrcPattern: /index\.js/g, // Optional, a regex pattern to match specific script tags for adding the 'entry' attribute. Defaults to the last script tag if not specified.
}),
],
};
Expand Down
11 changes: 7 additions & 4 deletions packages/webpack-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
"module": "./dist/esm/index.js",
"types": "./dist/esm/index.d.ts",
"scripts": {
"build:webpack4": "cd ./tests/webpack4 && npm run build",
"build:webpack5": "cd ./tests/webpack5 && npm run build",
"test:local": "npm run build && npm run build:webpack4 && npm run build:webpack5 && vitest",
"build:webpack4": "cd ./tests/webpack4 && npm install && pnpm run build",
"build:webpack5": "cd ./tests/webpack5 && npm install && pnpm run build",
"test": "pnpm run build && pnpm run build:webpack4 && pnpm run build:webpack5 && vitest --run",
"build": "father build"
},
"files": ["dist"],
"files": [
"dist"
],
"peerDependencies": {
"webpack": "^4.0.0 || ^5.0.0"
},
Expand All @@ -22,6 +24,7 @@
},
"devDependencies": {
"@types/webpack-sources": "^3.2.1",
"cheerio": "1.0.0-rc.12",
"webpack": "^4.0.0 || ^5.0.0"
}
}
59 changes: 38 additions & 21 deletions packages/webpack-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,28 @@ import fs from 'fs';
import path from 'path';
import type { Compiler, Configuration, Compilation } from 'webpack';
import { RawSource } from 'webpack-sources';
import cheerio from 'cheerio';

interface QiankunPluginOptions {
export type QiankunPluginOptions = {
packageName?: string;
}
entrySrcPattern?: RegExp; // 新增可选参数,用于匹配script标签
};

interface PackageJson {
export type PackageJson = {
name?: string;
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
}
};

class QiankunPlugin {
export class QiankunPlugin {
private packageName: string;
private entrySrcPattern: RegExp | null; // 用户提供的正则表达式

private static packageJson: PackageJson = QiankunPlugin.readPackageJson();

constructor(options: QiankunPluginOptions = {}) {
this.packageName = options.packageName || QiankunPlugin.packageJson.name || '';
this.entrySrcPattern = options.entrySrcPattern ? new RegExp(options.entrySrcPattern.source, 'g') : null; // 默认值
}

private static readPackageJson(): PackageJson {
Expand All @@ -27,10 +32,6 @@ class QiankunPlugin {
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) as PackageJson;
}

private static getWebpackVersion(): string {
return QiankunPlugin.packageJson.dependencies?.webpack || QiankunPlugin.packageJson.devDependencies?.webpack || '';
}

apply(compiler: Compiler): void {
this.configureWebpackOutput(compiler);
compiler.hooks.emit.tapAsync('QiankunPlugin', (compilation: Compilation, callback: () => void) => {
Expand All @@ -40,16 +41,17 @@ class QiankunPlugin {
}

private configureWebpackOutput(compiler: Compiler): void {
const webpackVersion = QiankunPlugin.getWebpackVersion();
const webpackCompilerOptions = compiler.options as Configuration & { output: { jsonpFunction?: string } };
if (webpackVersion.startsWith('4')) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const version = compiler.webpack?.version || '4';
if (version.startsWith('4')) {
// webpack 4
webpackCompilerOptions.output.library = `${this.packageName}`;
webpackCompilerOptions.output.libraryTarget = 'window';
webpackCompilerOptions.output.jsonpFunction = `webpackJsonp_${this.packageName}`;
webpackCompilerOptions.output.globalObject = 'window';
webpackCompilerOptions.output.chunkLoadingGlobal = `webpackJsonp_${this.packageName}`;
} else if (webpackVersion.startsWith('5')) {
} else if (version.startsWith('5')) {
// webpack 5
webpackCompilerOptions.output.library = {
name: `${this.packageName}`,
Expand All @@ -76,16 +78,31 @@ class QiankunPlugin {
}

private addEntryAttributeToScripts(htmlString: string): string {
const scriptTags = htmlString.match(/<script[^>]*src="[^"]+"[^>]*><\/script>/g) || [];
const nonAsyncOrDeferScripts = scriptTags.filter((tag) => !/defer|async/.test(tag));
const $ = cheerio.load(htmlString);

if (nonAsyncOrDeferScripts.length) {
const lastScriptTag = nonAsyncOrDeferScripts[nonAsyncOrDeferScripts.length - 1];
const modifiedScriptTag = lastScriptTag.replace('<script', '<script entry');
return htmlString.replace(lastScriptTag, modifiedScriptTag);
const alreadyHasEntry = $('script[entry]').length > 0;
if (!alreadyHasEntry) {
if (!this.entrySrcPattern) {
// 如果没有提供正则表达式,则选择最后一个 script 标签
$('script').last().attr('entry', '');
} else {
// 使用提供的正则表达式过滤 script 标签
const matchingScriptTags = $('script').filter((_, el) => {
const src = $(el).attr('src');
// 确保 this.entrySrcPattern 不是 null 再调用 test 方法
return src && this.entrySrcPattern ? this.entrySrcPattern.test(src) : false;
});

if (matchingScriptTags.length > 1) {
throw new Error('The regular expression matched multiple script tags, please check your regex.');
} else if (matchingScriptTags.length === 1) {
matchingScriptTags.first().attr('entry', '');
} else {
throw new Error('The provided regular expression did not match any scripts.');
}
}
}
return htmlString;

return $.html();
}
}

module.exports = QiankunPlugin;
31 changes: 23 additions & 8 deletions packages/webpack-plugin/tests/plugin.test.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
import fs from 'fs';
import path from 'path';
import { describe, expect, it } from 'vitest';
import webpack4PackageJson from './webpack4/package.json';
import webpack5PackageJson from './webpack5/package.json';
import cheerio from 'cheerio';

describe('QiankunPlugin', () => {
// webpack4
it('should work with webpack 4', async () => {
// 获取包名
const packageName4 = webpack4PackageJson.name;

// 检查产物
const htmlContent = fs.readFileSync(path.join(__dirname, 'tests/webpack4/dist/index.html'), 'utf-8');
expect(htmlContent).toContain('<script entry'); // 检查是否正确标记了 entry js
const htmlContent4 = fs.readFileSync(path.join(__dirname, 'webpack4/dist/index.html'), 'utf-8');
const $4 = cheerio.load(htmlContent4);
const hasEntryAttribute4 = $4('script[entry]').length > 0;
expect(hasEntryAttribute4).toBe(true); // 检查是否正确标记了 entry js

const jsChunkContent = fs.readFileSync(path.join(__dirname, 'tests/webpack4/dist/bundle.js'), 'utf-8');
expect(jsChunkContent).toContain('window.'); // 检查是否包含了 window. 关键字
const jsChunkContent4 = fs.readFileSync(path.join(__dirname, 'webpack4/dist/bundle.js'), 'utf-8');
const regex4 = new RegExp(`window(\\.\\${packageName4}|\\["${packageName4}"\\])`);
expect(jsChunkContent4).toMatch(regex4); // 检查是否包含了 window.${packageName} 或 window["${packageName}"]
});

// webpack5
it('should work with webpack 5', async () => {
// 获取包名
const packageName5 = webpack5PackageJson.name;

// 检查产物
const htmlContent = fs.readFileSync(path.join(__dirname, 'tests/webpack5/dist/index.html'), 'utf-8');
expect(htmlContent).toContain('<script entry'); // 检查是否正确标记了 entry js
const htmlContent5 = fs.readFileSync(path.join(__dirname, 'webpack5/dist/index.html'), 'utf-8');
const $5 = cheerio.load(htmlContent5);
const hasEntryAttribute5 = $5('script[entry]').length > 0;
expect(hasEntryAttribute5).toBe(true); // 检查是否正确标记了 entry js

const jsChunkContent = fs.readFileSync(path.join(__dirname, 'tests/webpack5/dist/bundle.js'), 'utf-8');
expect(jsChunkContent).toContain('window.'); // 检查是否包含了 window. 关键字
const jsChunkContent5 = fs.readFileSync(path.join(__dirname, 'webpack5/dist/bundle.js'), 'utf-8');
const regex5 = new RegExp(`window(\\.\\${packageName5}|\\["${packageName5}"\\])`);
expect(jsChunkContent5).toMatch(regex5); // 检查是否包含了 window.${packageName} 或 window["${packageName}"]
});
});
1 change: 1 addition & 0 deletions packages/webpack-plugin/tests/webpack4/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
</head>
<body>
<div id="app"></div>
<script src="/js/app.12.js"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion packages/webpack-plugin/tests/webpack4/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
"devDependencies": {
"html-webpack-plugin": "^4.5.2",
"webpack": "4",
"webpack-cli": "3"
"webpack-cli": "4"
}
}
7 changes: 5 additions & 2 deletions packages/webpack-plugin/tests/webpack4/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const path = require('path');
const QiankunPlugin = require('../../dist/cjs');
const { QiankunPlugin } = require('../../dist/cjs');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
Expand All @@ -8,11 +8,14 @@ module.exports = {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
mode: 'development',
plugins: [
new HtmlWebpackPlugin({
template: './index.html', // 指定模板文件路径
filename: 'index.html', // 输出的HTML文件名(默认为index.html)
}),
new QiankunPlugin(),
new QiankunPlugin({
entrySrcPattern: /app\.12\.js/,
}),
],
};
1 change: 1 addition & 0 deletions packages/webpack-plugin/tests/webpack5/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
</head>
<body>
<div id="app"></div>
<script entry src="a.js"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion packages/webpack-plugin/tests/webpack5/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
"devDependencies": {
"html-webpack-plugin": "^5.5.3",
"webpack": "5",
"webpack-cli": "4"
"webpack-cli": "5"
}
}
3 changes: 2 additions & 1 deletion packages/webpack-plugin/tests/webpack5/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const path = require('path');
const QiankunPlugin = require('../../dist/cjs');
const { QiankunPlugin } = require('../../dist/cjs');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
Expand All @@ -8,6 +8,7 @@ module.exports = {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
mode: 'development',
plugins: [
new HtmlWebpackPlugin({
template: './index.html', // 指定模板文件路径
Expand Down
Loading

0 comments on commit b7ec9e7

Please sign in to comment.