@taro-minify-pack/plugin-async-pack 0.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.js ADDED
@@ -0,0 +1,21 @@
1
+ module.exports = {
2
+ env: {
3
+ node: true,
4
+ es6: true
5
+ },
6
+ extends: [
7
+ 'standard',
8
+ 'plugin:@typescript-eslint/recommended'
9
+ ],
10
+ parser: '@typescript-eslint/parser',
11
+ plugins: ['@typescript-eslint'],
12
+ rules: {
13
+ '@typescript-eslint/no-empty-function': 'off',
14
+ '@typescript-eslint/no-explicit-any': 'off',
15
+ '@typescript-eslint/no-var-requires': 'off',
16
+ '@typescript-eslint/no-non-null-assertion': 'off',
17
+ '@typescript-eslint/ban-ts-comment': 'off',
18
+ '@typescript-eslint/no-unused-vars': 'off',
19
+ 'no-use-before-define': 'off'
20
+ }
21
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 yu.pan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ import type { IPluginContext } from '@tarojs/service';
2
+ import { AsyncPackOpts } from './types';
3
+ export { AsyncPackOpts } from './types';
4
+ declare const _default: (ctx: IPluginContext, pluginOpts: AsyncPackOpts) => void;
5
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const webpack_sources_1 = require("webpack-sources");
7
+ const transform_webpack_runtime_1 = require("./transform-webpack-runtime");
8
+ const transform_before_compression_plugin_1 = require("./transform-before-compression-plugin");
9
+ const merge_output_1 = require("./merge-output");
10
+ const transform_app_stylesheet_1 = require("./transform-app-stylesheet");
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const dynamicPackOptsDefaultOpt = {
14
+ dynamicModuleJsDir: 'dynamic-common',
15
+ dynamicModuleStyleFile: 'dynamic-common'
16
+ };
17
+ exports.default = (ctx, pluginOpts) => {
18
+ const finalOpts = Object.assign(Object.assign({}, dynamicPackOptsDefaultOpt), pluginOpts);
19
+ if (process.env.TARO_ENV !== 'weapp')
20
+ return;
21
+ ctx.modifyWebpackChain(({ chain }) => {
22
+ // 动态获取现有的 splitChunks 配置
23
+ const existingSplitChunks = chain.optimization.get('splitChunks') || {};
24
+ const { common, vendors } = existingSplitChunks.cacheGroups;
25
+ const newCommonChunks = common ? Object.assign(Object.assign({}, common), { chunks: 'initial' }) : common;
26
+ const newVendorsChunks = vendors ? Object.assign(Object.assign({}, vendors), { chunks: 'initial' }) : vendors;
27
+ chain.optimization.merge({
28
+ splitChunks: Object.assign(Object.assign({}, existingSplitChunks), { cacheGroups: Object.assign(Object.assign({}, existingSplitChunks.cacheGroups), { common: newCommonChunks, vendors: newVendorsChunks }) })
29
+ });
30
+ chain.merge({
31
+ output: {
32
+ chunkFilename: `${finalOpts.dynamicModuleJsDir}/[chunkhash].js`, // 异步模块输出路径
33
+ path: ctx.paths.outputPath,
34
+ clean: true
35
+ }
36
+ });
37
+ chain.plugin('miniCssExtractPlugin')
38
+ .tap((args) => {
39
+ const [options] = args;
40
+ const finalOption = Object.assign(Object.assign({}, options), { chunkFilename: `${finalOpts.dynamicModuleStyleFile}/[chunkhash].wxss` });
41
+ return [finalOption];
42
+ });
43
+ chain.plugin(transform_before_compression_plugin_1.PLUGIN_NAME).use(transform_before_compression_plugin_1.TransformBeforeCompressionPlugin, [{
44
+ test: /^(runtime\.js|app\.wxss)$/,
45
+ transform: (opt) => {
46
+ const { source, assetName, assets } = opt;
47
+ const transformOpts = Object.assign(Object.assign({}, finalOpts), { assets });
48
+ if (/^app\.wxss$/.test(assetName))
49
+ return (0, transform_app_stylesheet_1.transformAppStylesheet)(source, transformOpts);
50
+ if (/^runtime\.js$/.test(assetName))
51
+ return (0, transform_webpack_runtime_1.transformWebpackRuntime)(source, transformOpts);
52
+ return source;
53
+ }
54
+ }]);
55
+ chain.plugin(merge_output_1.PLUGIN_NAME).use(merge_output_1.MergeOutputPlugin, [{
56
+ test: new RegExp(`^${finalOpts.dynamicModuleStyleFile}\\/.*\\.wxss$`),
57
+ outputFile: `${finalOpts.dynamicModuleStyleFile}.wxss`
58
+ }]);
59
+ });
60
+ ctx.modifyBuildAssets(({ assets }) => {
61
+ const curAppJSON = assets['app.json'];
62
+ if (!curAppJSON)
63
+ return;
64
+ const curAppJSONContent = JSON.parse(curAppJSON.source());
65
+ const dynamicPackagesConfig = { root: finalOpts.dynamicModuleJsDir, pages: [] };
66
+ const hasDynamicModule = (() => {
67
+ const isDynamicModuleDirExist = fs_1.default.existsSync(path_1.default.join(ctx.paths.outputPath, finalOpts.dynamicModuleJsDir));
68
+ return isDynamicModuleDirExist && fs_1.default.readdirSync(path_1.default.join(ctx.paths.outputPath, finalOpts.dynamicModuleJsDir)).length > 0;
69
+ })();
70
+ const { resolveAlias = {}, subpackages = [] } = curAppJSONContent;
71
+ const newAppJSONContent = Object.assign(Object.assign({}, curAppJSONContent), { subpackages: hasDynamicModule ? [...subpackages, dynamicPackagesConfig] : subpackages, resolveAlias: Object.assign(Object.assign({}, resolveAlias), { [`${finalOpts.dynamicModuleJsDir}/*`]: `/${finalOpts.dynamicModuleJsDir}/*` }) });
72
+ assets['app.json'] = new webpack_sources_1.RawSource(JSON.stringify(newAppJSONContent, null, 2));
73
+ });
74
+ };
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { Compiler } from 'webpack';
2
+ export declare const PLUGIN_NAME = "MergeOutput";
3
+ interface MergeOutputOpt {
4
+ test: RegExp;
5
+ outputFile: string;
6
+ }
7
+ export declare class MergeOutputPlugin {
8
+ private readonly opts;
9
+ constructor(opts: MergeOutputOpt);
10
+ apply(compiler: Compiler): void;
11
+ }
12
+ export {};
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MergeOutputPlugin = exports.PLUGIN_NAME = void 0;
4
+ exports.PLUGIN_NAME = 'MergeOutput';
5
+ class MergeOutputPlugin {
6
+ constructor(opts) {
7
+ this.opts = opts;
8
+ }
9
+ apply(compiler) {
10
+ compiler.hooks.compilation.tap(exports.PLUGIN_NAME, (compilation) => {
11
+ const stage = compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL; // 最早阶段,在优化前
12
+ compilation.hooks.processAssets.tap({ name: exports.PLUGIN_NAME, stage }, (assets) => {
13
+ const mergedResult = Object.keys(assets).reduce((result, item) => {
14
+ if (!this.opts.test.test(item))
15
+ return result;
16
+ const code = assets[item].source().toString();
17
+ delete assets[item];
18
+ return result + code + '\n';
19
+ }, '');
20
+ compilation.assets[this.opts.outputFile] = new compiler.webpack.sources.RawSource(mergedResult);
21
+ });
22
+ });
23
+ }
24
+ }
25
+ exports.MergeOutputPlugin = MergeOutputPlugin;
26
+ //# sourceMappingURL=merge-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-output.js","sourceRoot":"","sources":["../src/merge-output.ts"],"names":[],"mappings":";;;AAEa,QAAA,WAAW,GAAG,aAAa,CAAA;AAOxC,MAAa,iBAAiB;IAG5B,YAAa,IAAoB;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;IAED,KAAK,CAAE,QAAkB;QACvB,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,mBAAW,EAAE,CAAC,WAAwB,EAAE,EAAE;YACvE,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,+BAA+B,CAAA,CAAC,YAAY;YAEvF,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,mBAAW,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE;gBAC3E,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;oBAC/D,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;wBAAE,OAAO,MAAM,CAAA;oBAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAA;oBAC7C,OAAO,MAAM,CAAC,IAAI,CAAC,CAAA;oBACnB,OAAO,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;gBAC7B,CAAC,EAAE,EAAE,CAAC,CAAA;gBAEN,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAW,CAAC,GAAG,IAAI,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;YAClG,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAvBD,8CAuBC"}
@@ -0,0 +1,6 @@
1
+ import type { CompilationAssets, AsyncPackOpts } from './types';
2
+ interface Opts extends AsyncPackOpts {
3
+ assets: CompilationAssets;
4
+ }
5
+ export declare const transformAppStylesheet: (code: string, opts: Opts) => string;
6
+ export {};
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformAppStylesheet = void 0;
4
+ const transformAppStylesheet = (code, opts) => {
5
+ const { dynamicModuleStyleFile, assets } = opts;
6
+ const isDynamicModuleStyleFileExist = Object.keys(assets).some(assetName => {
7
+ return new RegExp(`${dynamicModuleStyleFile}\\.wxss`).test(assetName);
8
+ });
9
+ if (!isDynamicModuleStyleFileExist)
10
+ return code;
11
+ return code.concat(`@import './${dynamicModuleStyleFile}.wxss';`);
12
+ };
13
+ exports.transformAppStylesheet = transformAppStylesheet;
14
+ //# sourceMappingURL=transform-app-stylesheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-app-stylesheet.js","sourceRoot":"","sources":["../src/transform-app-stylesheet.ts"],"names":[],"mappings":";;;AAMO,MAAM,sBAAsB,GAAG,CAAC,IAAY,EAAE,IAAU,EAAE,EAAE;IACjE,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IAE/C,MAAM,6BAA6B,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;QACzE,OAAO,IAAI,MAAM,CAAC,GAAG,sBAAsB,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACvE,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,6BAA6B;QAAE,OAAO,IAAI,CAAA;IAE/C,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,sBAAsB,SAAS,CAAC,CAAA;AACnE,CAAC,CAAA;AAVY,QAAA,sBAAsB,0BAUlC"}
@@ -0,0 +1,17 @@
1
+ import webpack from 'webpack';
2
+ import { CompilationAssets } from './types';
3
+ export interface TransformOpt {
4
+ assetName: string;
5
+ source: string | Buffer;
6
+ assets: CompilationAssets;
7
+ }
8
+ export interface PluginOpt {
9
+ test?: RegExp;
10
+ transform: (opt: TransformOpt) => string;
11
+ }
12
+ export declare const PLUGIN_NAME = "TransformBeforeCompression";
13
+ export declare class TransformBeforeCompressionPlugin {
14
+ private readonly opt;
15
+ constructor(opt: PluginOpt);
16
+ apply(compiler: webpack.Compiler): void;
17
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TransformBeforeCompressionPlugin = exports.PLUGIN_NAME = void 0;
7
+ const webpack_1 = __importDefault(require("webpack"));
8
+ exports.PLUGIN_NAME = 'TransformBeforeCompression';
9
+ class TransformBeforeCompressionPlugin {
10
+ constructor(opt) {
11
+ this.opt = opt;
12
+ }
13
+ apply(compiler) {
14
+ compiler.hooks.compilation.tap(exports.PLUGIN_NAME, (compilation) => {
15
+ const stage = webpack_1.default.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE; // 压缩前
16
+ compilation.hooks.processAssets.tap({ name: exports.PLUGIN_NAME, stage }, (assets) => {
17
+ const { test, transform } = this.opt;
18
+ const assetNames = Object.keys(assets);
19
+ assetNames.forEach((assetName) => {
20
+ if (!test || !test.test(assetName))
21
+ return;
22
+ const source = assets[assetName].source();
23
+ const transformResult = transform({ assetName, source, assets });
24
+ compilation.updateAsset(assetName, new webpack_1.default.sources.RawSource(transformResult));
25
+ });
26
+ });
27
+ });
28
+ }
29
+ }
30
+ exports.TransformBeforeCompressionPlugin = TransformBeforeCompressionPlugin;
31
+ //# sourceMappingURL=transform-before-compression-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-before-compression-plugin.js","sourceRoot":"","sources":["../src/transform-before-compression-plugin.ts"],"names":[],"mappings":";;;;;;AAAA,sDAA6B;AAchB,QAAA,WAAW,GAAG,4BAA4B,CAAA;AAEvD,MAAa,gCAAgC;IAG3C,YAAa,GAAc;QACzB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;IAChB,CAAC;IAED,KAAK,CAAE,QAA0B;QAC/B,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,mBAAW,EAAE,CAAC,WAAgC,EAAE,EAAE;YAC/E,MAAM,KAAK,GAAG,iBAAO,CAAC,WAAW,CAAC,6BAA6B,CAAA,CAAC,MAAM;YAEtE,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,mBAAW,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE;gBAC3E,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,GAAG,CAAA;gBAEpC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBAEtC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;oBAC/B,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;wBAAE,OAAM;oBAE1C,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,CAAA;oBAEzC,MAAM,eAAe,GAAG,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAkB,CAAC,CAAA;oBAEhF,WAAW,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,iBAAO,CAAC,OAAO,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAA;gBACpF,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AA5BD,4EA4BC"}
@@ -0,0 +1,6 @@
1
+ import type { CompilationAssets, AsyncPackOpts } from './types';
2
+ interface Opts extends AsyncPackOpts {
3
+ assets: CompilationAssets;
4
+ }
5
+ export declare const transformWebpackRuntime: (code: string, opts: Opts) => string;
6
+ export {};
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.transformWebpackRuntime = void 0;
40
+ const core_1 = require("@babel/core");
41
+ const generator_1 = __importDefault(require("@babel/generator"));
42
+ const parser = __importStar(require("@babel/parser"));
43
+ const traverse_1 = __importDefault(require("@babel/traverse"));
44
+ const types = __importStar(require("@babel/types"));
45
+ const webpackLoadDynamicModuleTemplateDep = `
46
+ var loadedDynamicModules = {};
47
+ var loadDynamicModule = function (dynamicModulePath) {
48
+ var loadDynamicModuleFn = loadDynamicModuleFnMap[dynamicModulePath];
49
+ return loadDynamicModuleFn ? loadDynamicModuleFn() : Promise.reject();
50
+ };
51
+ var promiseRetry = function (apply,retries = 6,delay = 500) {
52
+ return apply().catch(function (error) {
53
+ if (retries <= 0) return Promise.reject(error);
54
+ return new Promise(function (resolve) {
55
+ setTimeout(resolve, delay);
56
+ })
57
+ .then(function () {
58
+ return promiseRetry(apply, retries - 1, delay)
59
+ });
60
+ })
61
+ }
62
+ `;
63
+ const webpackLoadDynamicModuleTemplate = `
64
+ __webpack_require__.l = function (dynamicModulePath, done, key, chunkId) {
65
+ if (inProgress[dynamicModulePath]) {
66
+ inProgress[dynamicModulePath].push(done);
67
+ return;
68
+ }
69
+
70
+ const target = { src: dynamicModulePath };
71
+
72
+ if (loadedDynamicModules[dynamicModulePath]) return done({ type: 'loaded', target });
73
+
74
+ promiseRetry(function () {
75
+ return loadDynamicModule(dynamicModulePath)
76
+ })
77
+ .then(function () {
78
+ return done({ type: 'loaded', target })
79
+ }).catch(function () {
80
+ return done({ type:'error', target })
81
+ });
82
+ };
83
+ `;
84
+ const replaceWebpackLoadScriptFn = (assignmentExpressionNodePath, opts) => {
85
+ const { left, right } = assignmentExpressionNodePath.node || {};
86
+ if (!types.isMemberExpression(left))
87
+ return;
88
+ if (!types.isFunctionExpression(right))
89
+ return;
90
+ if (!types.isIdentifier(left.object, { name: '__webpack_require__' }))
91
+ return;
92
+ if (!types.isIdentifier(left.property, { name: 'l' }))
93
+ return;
94
+ const isProcessed = right.params.some((item) => {
95
+ return types.isIdentifier(item, { name: 'dynamicModulePath' });
96
+ });
97
+ if (isProcessed)
98
+ return;
99
+ const { assets, dynamicModuleJsDir } = opts;
100
+ const dynamicAssets = Object.keys(assets).filter((assetName) => {
101
+ return new RegExp(`^${dynamicModuleJsDir}/.`).test(assetName);
102
+ });
103
+ const loadDynamicModuleFnMapCode = (() => {
104
+ const tempCode = dynamicAssets.map((dynamicAsset) => {
105
+ return `'/${dynamicAsset}':function (){ return require.async('${dynamicAsset}'); }`;
106
+ });
107
+ return `var loadDynamicModuleFnMap = {${tempCode.join(',')}}`;
108
+ })();
109
+ const templateCodeAst = core_1.template.ast(webpackLoadDynamicModuleTemplate);
110
+ const templateCodeDepAst = core_1.template.ast(webpackLoadDynamicModuleTemplateDep);
111
+ const loadDynamicModuleFnMapAst = core_1.template.ast(loadDynamicModuleFnMapCode);
112
+ assignmentExpressionNodePath.replaceWith(templateCodeAst);
113
+ assignmentExpressionNodePath.insertBefore(templateCodeDepAst);
114
+ assignmentExpressionNodePath.insertBefore(loadDynamicModuleFnMapAst);
115
+ };
116
+ const webpackLoadDynamicModuleStylesheetTemplate = `
117
+ loadStylesheet = function () {
118
+ return Promise.resolve()
119
+ }
120
+ `;
121
+ const replaceLoadStylesheetFn = (nodePath) => {
122
+ const { id, init } = nodePath.node || {};
123
+ if (!types.isIdentifier(id, { name: 'loadStylesheet' }))
124
+ return;
125
+ if (!types.isFunctionExpression(init))
126
+ return;
127
+ const isProcessed = !init.params.length;
128
+ if (isProcessed)
129
+ return;
130
+ const templateCodeAst = core_1.template.expression(webpackLoadDynamicModuleStylesheetTemplate)();
131
+ nodePath.replaceWith(templateCodeAst);
132
+ };
133
+ const removeCreateStylesheetFn = (nodePath) => {
134
+ const { id } = nodePath.node || {};
135
+ if (!types.isIdentifier(id, { name: 'createStylesheet' }))
136
+ return;
137
+ nodePath.remove();
138
+ };
139
+ const removeFindStylesheetFn = (nodePath) => {
140
+ const { id } = nodePath.node || {};
141
+ if (!types.isIdentifier(id, { name: 'findStylesheet' }))
142
+ return;
143
+ nodePath.remove();
144
+ };
145
+ const transformWebpackRuntime = (code, opts) => {
146
+ const ast = parser.parse(code); // 将代码解析为 AST
147
+ (0, traverse_1.default)(ast, {
148
+ AssignmentExpression: (nodePath) => {
149
+ replaceWebpackLoadScriptFn(nodePath, opts);
150
+ },
151
+ VariableDeclarator(nodePath) {
152
+ replaceLoadStylesheetFn(nodePath);
153
+ removeCreateStylesheetFn(nodePath);
154
+ removeFindStylesheetFn(nodePath);
155
+ }
156
+ });
157
+ return (0, generator_1.default)(ast).code;
158
+ };
159
+ exports.transformWebpackRuntime = transformWebpackRuntime;
160
+ //# sourceMappingURL=transform-webpack-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-webpack-runtime.js","sourceRoot":"","sources":["../src/transform-webpack-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { Source } from 'webpack-sources';
2
+ export interface AsyncPackOpts {
3
+ dynamicModuleJsDir: string;
4
+ dynamicModuleStyleFile: string;
5
+ }
6
+ export type CompilationAssets = Record<string, Source>;
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@taro-minify-pack/plugin-async-pack",
3
+ "version": "0.0.1-alpha.0",
4
+ "description": "",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "homepage": "https://github.com/panyu97py/taro-minify-pack",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/panyu97py/taro-minify-pack.git"
14
+ },
15
+ "author": "yu.pan",
16
+ "license": "ISC",
17
+ "peerDependencies": {
18
+ "@tarojs/service": "^3.0.0"
19
+ },
20
+ "dependencies": {
21
+ "@babel/core": "^7.26.10",
22
+ "@babel/generator": "^7.26.10",
23
+ "@babel/parser": "^7.26.10",
24
+ "@babel/template": "^7.26.9",
25
+ "@babel/traverse": "^7.26.10",
26
+ "@babel/types": "^7.26.10",
27
+ "webpack": "^5.98.0",
28
+ "webpack-sources": "^3.2.3"
29
+ },
30
+ "devDependencies": {
31
+ "@tarojs/service": "^4.0.9",
32
+ "@types/babel__core": "^7.20.5",
33
+ "@types/babel__generator": "^7.6.8",
34
+ "@types/babel__template": "^7.4.4",
35
+ "@types/babel__traverse": "^7.20.6",
36
+ "@types/md5": "^2.3.5",
37
+ "@types/node": "^18.19.130",
38
+ "@types/webpack-sources": "^3.2.3",
39
+ "@typescript-eslint/eslint-plugin": "^8.26.1",
40
+ "@typescript-eslint/parser": "^8.26.1",
41
+ "eslint": "^8.19.0",
42
+ "eslint-config-standard": "^17.0.0",
43
+ "eslint-plugin-import": "^2.26.0",
44
+ "eslint-plugin-n": "^15.2.3",
45
+ "eslint-plugin-promise": "^6.0.0",
46
+ "typescript": "^5.8.2"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc"
50
+ }
51
+ }
package/src/index.ts ADDED
@@ -0,0 +1,107 @@
1
+ import type { IPluginContext } from '@tarojs/service'
2
+ import { RawSource } from 'webpack-sources'
3
+ import { transformWebpackRuntime } from './transform-webpack-runtime'
4
+ import {
5
+ TransformOpt,
6
+ TransformBeforeCompressionPlugin,
7
+ PLUGIN_NAME as TransformBeforeCompressionPluginName
8
+ } from './transform-before-compression-plugin'
9
+ import { MergeOutputPlugin, PLUGIN_NAME as MergeOutputPluginName } from './merge-output'
10
+ import { AsyncPackOpts } from './types'
11
+ import { transformAppStylesheet } from './transform-app-stylesheet'
12
+ import fs from 'fs'
13
+ import path from 'path'
14
+
15
+ export { AsyncPackOpts } from './types'
16
+
17
+ const dynamicPackOptsDefaultOpt: AsyncPackOpts = {
18
+ dynamicModuleJsDir: 'dynamic-common',
19
+ dynamicModuleStyleFile: 'dynamic-common'
20
+ }
21
+
22
+ export default (ctx: IPluginContext, pluginOpts: AsyncPackOpts) => {
23
+ const finalOpts = { ...dynamicPackOptsDefaultOpt, ...pluginOpts }
24
+
25
+ if (process.env.TARO_ENV !== 'weapp') return
26
+
27
+ ctx.modifyWebpackChain(({ chain }) => {
28
+ // 动态获取现有的 splitChunks 配置
29
+ const existingSplitChunks = chain.optimization.get('splitChunks') || {}
30
+
31
+ const { common, vendors } = existingSplitChunks.cacheGroups
32
+
33
+ const newCommonChunks = common ? { ...common, chunks: 'initial' } : common
34
+
35
+ const newVendorsChunks = vendors ? { ...vendors, chunks: 'initial' } : vendors
36
+
37
+ chain.optimization.merge({
38
+ splitChunks: {
39
+ ...existingSplitChunks,
40
+ cacheGroups: {
41
+ ...existingSplitChunks.cacheGroups,
42
+ common: newCommonChunks,
43
+ vendors: newVendorsChunks
44
+ }
45
+ }
46
+ })
47
+
48
+ chain.merge({
49
+ output: {
50
+ chunkFilename: `${finalOpts.dynamicModuleJsDir}/[chunkhash].js`, // 异步模块输出路径
51
+ path: ctx.paths.outputPath,
52
+ clean: true
53
+ }
54
+ })
55
+
56
+ chain.plugin('miniCssExtractPlugin')
57
+ .tap((args) => {
58
+ const [options] = args
59
+ const finalOption = { ...options, chunkFilename: `${finalOpts.dynamicModuleStyleFile}/[chunkhash].wxss` }
60
+ return [finalOption]
61
+ })
62
+
63
+ chain.plugin(TransformBeforeCompressionPluginName).use(TransformBeforeCompressionPlugin, [{
64
+ test: /^(runtime\.js|app\.wxss)$/,
65
+ transform: (opt: TransformOpt) => {
66
+ const { source, assetName, assets } = opt
67
+ const transformOpts = { ...finalOpts, assets }
68
+ if (/^app\.wxss$/.test(assetName)) return transformAppStylesheet(source as string, transformOpts)
69
+ if (/^runtime\.js$/.test(assetName)) return transformWebpackRuntime(source as string, transformOpts)
70
+ return source as string
71
+ }
72
+ }])
73
+
74
+ chain.plugin(MergeOutputPluginName).use(MergeOutputPlugin, [{
75
+ test: new RegExp(`^${finalOpts.dynamicModuleStyleFile}\\/.*\\.wxss$`),
76
+ outputFile: `${finalOpts.dynamicModuleStyleFile}.wxss`
77
+ }])
78
+ })
79
+
80
+ ctx.modifyBuildAssets(({ assets }) => {
81
+ const curAppJSON = assets['app.json']
82
+
83
+ if (!curAppJSON) return
84
+
85
+ const curAppJSONContent = JSON.parse(curAppJSON.source())
86
+
87
+ const dynamicPackagesConfig = { root: finalOpts.dynamicModuleJsDir, pages: [] }
88
+
89
+ const hasDynamicModule = (() => {
90
+ const isDynamicModuleDirExist = fs.existsSync(path.join(ctx.paths.outputPath, finalOpts.dynamicModuleJsDir))
91
+ return isDynamicModuleDirExist && fs.readdirSync(path.join(ctx.paths.outputPath, finalOpts.dynamicModuleJsDir)).length > 0
92
+ })()
93
+
94
+ const { resolveAlias = {}, subpackages = [] } = curAppJSONContent
95
+
96
+ const newAppJSONContent = {
97
+ ...curAppJSONContent,
98
+ subpackages: hasDynamicModule ? [...subpackages, dynamicPackagesConfig] : subpackages,
99
+ resolveAlias: {
100
+ ...resolveAlias,
101
+ [`${finalOpts.dynamicModuleJsDir}/*`]: `/${finalOpts.dynamicModuleJsDir}/*`
102
+ }
103
+ }
104
+
105
+ assets['app.json'] = new RawSource(JSON.stringify(newAppJSONContent, null, 2))
106
+ })
107
+ }
@@ -0,0 +1,33 @@
1
+ import { Compiler, Compilation } from 'webpack'
2
+
3
+ export const PLUGIN_NAME = 'MergeOutput'
4
+
5
+ interface MergeOutputOpt {
6
+ test: RegExp,
7
+ outputFile: string,
8
+ }
9
+
10
+ export class MergeOutputPlugin {
11
+ private readonly opts: MergeOutputOpt
12
+
13
+ constructor (opts: MergeOutputOpt) {
14
+ this.opts = opts
15
+ }
16
+
17
+ apply (compiler: Compiler) {
18
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation: Compilation) => {
19
+ const stage = compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL // 最早阶段,在优化前
20
+
21
+ compilation.hooks.processAssets.tap({ name: PLUGIN_NAME, stage }, (assets) => {
22
+ const mergedResult = Object.keys(assets).reduce((result, item) => {
23
+ if (!this.opts.test.test(item)) return result
24
+ const code = assets[item].source().toString()
25
+ delete assets[item]
26
+ return result + code + '\n'
27
+ }, '')
28
+
29
+ compilation.assets[this.opts.outputFile!] = new compiler.webpack.sources.RawSource(mergedResult)
30
+ })
31
+ })
32
+ }
33
+ }
@@ -0,0 +1,17 @@
1
+ import type { CompilationAssets, AsyncPackOpts } from './types'
2
+
3
+ interface Opts extends AsyncPackOpts {
4
+ assets: CompilationAssets;
5
+ }
6
+
7
+ export const transformAppStylesheet = (code: string, opts: Opts) => {
8
+ const { dynamicModuleStyleFile, assets } = opts
9
+
10
+ const isDynamicModuleStyleFileExist = Object.keys(assets).some(assetName => {
11
+ return new RegExp(`${dynamicModuleStyleFile}\\.wxss`).test(assetName)
12
+ })
13
+
14
+ if (!isDynamicModuleStyleFileExist) return code
15
+
16
+ return code.concat(`@import './${dynamicModuleStyleFile}.wxss';`)
17
+ }
@@ -0,0 +1,45 @@
1
+ import webpack from 'webpack'
2
+ import { CompilationAssets } from './types'
3
+
4
+ export interface TransformOpt {
5
+ assetName: string
6
+ source: string | Buffer
7
+ assets: CompilationAssets
8
+ }
9
+
10
+ export interface PluginOpt {
11
+ test?: RegExp;
12
+ transform: (opt: TransformOpt) => string;
13
+ }
14
+
15
+ export const PLUGIN_NAME = 'TransformBeforeCompression'
16
+
17
+ export class TransformBeforeCompressionPlugin {
18
+ private readonly opt: PluginOpt
19
+
20
+ constructor (opt: PluginOpt) {
21
+ this.opt = opt
22
+ }
23
+
24
+ apply (compiler: webpack.Compiler) {
25
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation: webpack.Compilation) => {
26
+ const stage = webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE // 压缩前
27
+
28
+ compilation.hooks.processAssets.tap({ name: PLUGIN_NAME, stage }, (assets) => {
29
+ const { test, transform } = this.opt
30
+
31
+ const assetNames = Object.keys(assets)
32
+
33
+ assetNames.forEach((assetName) => {
34
+ if (!test || !test.test(assetName)) return
35
+
36
+ const source = assets[assetName].source()
37
+
38
+ const transformResult = transform({ assetName, source, assets } as TransformOpt)
39
+
40
+ compilation.updateAsset(assetName, new webpack.sources.RawSource(transformResult))
41
+ })
42
+ })
43
+ })
44
+ }
45
+ }
@@ -0,0 +1,138 @@
1
+ import { NodePath, template } from '@babel/core'
2
+ import generator from '@babel/generator'
3
+ import * as parser from '@babel/parser'
4
+ import traverse, { Node } from '@babel/traverse'
5
+ import * as types from '@babel/types'
6
+ import type { AssignmentExpression, VariableDeclarator } from '@babel/types'
7
+ import type { CompilationAssets, AsyncPackOpts } from './types'
8
+
9
+ interface Opts extends AsyncPackOpts {
10
+ assets: CompilationAssets;
11
+ }
12
+
13
+ const webpackLoadDynamicModuleTemplateDep = `
14
+ var loadedDynamicModules = {};
15
+ var loadDynamicModule = function (dynamicModulePath) {
16
+ var loadDynamicModuleFn = loadDynamicModuleFnMap[dynamicModulePath];
17
+ return loadDynamicModuleFn ? loadDynamicModuleFn() : Promise.reject();
18
+ };
19
+ var promiseRetry = function (apply,retries = 6,delay = 500) {
20
+ return apply().catch(function (error) {
21
+ if (retries <= 0) return Promise.reject(error);
22
+ return new Promise(function (resolve) {
23
+ setTimeout(resolve, delay);
24
+ })
25
+ .then(function () {
26
+ return promiseRetry(apply, retries - 1, delay)
27
+ });
28
+ })
29
+ }
30
+ `
31
+
32
+ const webpackLoadDynamicModuleTemplate = `
33
+ __webpack_require__.l = function (dynamicModulePath, done, key, chunkId) {
34
+ if (inProgress[dynamicModulePath]) {
35
+ inProgress[dynamicModulePath].push(done);
36
+ return;
37
+ }
38
+
39
+ const target = { src: dynamicModulePath };
40
+
41
+ if (loadedDynamicModules[dynamicModulePath]) return done({ type: 'loaded', target });
42
+
43
+ promiseRetry(function () {
44
+ return loadDynamicModule(dynamicModulePath)
45
+ })
46
+ .then(function () {
47
+ return done({ type: 'loaded', target })
48
+ }).catch(function () {
49
+ return done({ type:'error', target })
50
+ });
51
+ };
52
+ `
53
+
54
+ const replaceWebpackLoadScriptFn = (assignmentExpressionNodePath: NodePath<AssignmentExpression>, opts: Opts) => {
55
+ const { left, right } = assignmentExpressionNodePath.node || {}
56
+
57
+ if (!types.isMemberExpression(left)) return
58
+
59
+ if (!types.isFunctionExpression(right)) return
60
+
61
+ if (!types.isIdentifier(left.object, { name: '__webpack_require__' })) return
62
+
63
+ if (!types.isIdentifier(left.property, { name: 'l' })) return
64
+
65
+ const isProcessed = right.params.some((item) => {
66
+ return types.isIdentifier(item, { name: 'dynamicModulePath' })
67
+ })
68
+
69
+ if (isProcessed) return
70
+
71
+ const { assets, dynamicModuleJsDir } = opts
72
+
73
+ const dynamicAssets = Object.keys(assets).filter((assetName) => {
74
+ return new RegExp(`^${dynamicModuleJsDir}/.`).test(assetName)
75
+ })
76
+
77
+ const loadDynamicModuleFnMapCode = (() => {
78
+ const tempCode = dynamicAssets.map((dynamicAsset) => {
79
+ return `'/${dynamicAsset}':function (){ return require.async('${dynamicAsset}'); }`
80
+ })
81
+ return `var loadDynamicModuleFnMap = {${tempCode.join(',')}}`
82
+ })()
83
+
84
+ const templateCodeAst = template.ast(webpackLoadDynamicModuleTemplate)
85
+
86
+ const templateCodeDepAst = template.ast(webpackLoadDynamicModuleTemplateDep)
87
+
88
+ const loadDynamicModuleFnMapAst = template.ast(loadDynamicModuleFnMapCode)
89
+
90
+ assignmentExpressionNodePath.replaceWith(templateCodeAst as Node)
91
+
92
+ assignmentExpressionNodePath.insertBefore(templateCodeDepAst)
93
+
94
+ assignmentExpressionNodePath.insertBefore(loadDynamicModuleFnMapAst)
95
+ }
96
+
97
+ const webpackLoadDynamicModuleStylesheetTemplate = `
98
+ loadStylesheet = function () {
99
+ return Promise.resolve()
100
+ }
101
+ `
102
+
103
+ const replaceLoadStylesheetFn = (nodePath: NodePath<VariableDeclarator>) => {
104
+ const { id, init } = nodePath.node || {}
105
+ if (!types.isIdentifier(id, { name: 'loadStylesheet' })) return
106
+ if (!types.isFunctionExpression(init)) return
107
+ const isProcessed = !init.params.length
108
+ if (isProcessed) return
109
+ const templateCodeAst = template.expression(webpackLoadDynamicModuleStylesheetTemplate)()
110
+ nodePath.replaceWith(templateCodeAst)
111
+ }
112
+
113
+ const removeCreateStylesheetFn = (nodePath: NodePath<VariableDeclarator>) => {
114
+ const { id } = nodePath.node || {}
115
+ if (!types.isIdentifier(id, { name: 'createStylesheet' })) return
116
+ nodePath.remove()
117
+ }
118
+
119
+ const removeFindStylesheetFn = (nodePath: NodePath<VariableDeclarator>) => {
120
+ const { id } = nodePath.node || {}
121
+ if (!types.isIdentifier(id, { name: 'findStylesheet' })) return
122
+ nodePath.remove()
123
+ }
124
+
125
+ export const transformWebpackRuntime = (code: string, opts: Opts) => {
126
+ const ast = parser.parse(code) // 将代码解析为 AST
127
+ traverse(ast, {
128
+ AssignmentExpression: (nodePath: NodePath<AssignmentExpression>) => {
129
+ replaceWebpackLoadScriptFn(nodePath, opts)
130
+ },
131
+ VariableDeclarator (nodePath: NodePath<VariableDeclarator>) {
132
+ replaceLoadStylesheetFn(nodePath)
133
+ removeCreateStylesheetFn(nodePath)
134
+ removeFindStylesheetFn(nodePath)
135
+ }
136
+ })
137
+ return generator(ast).code
138
+ }
package/src/types.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { Source } from 'webpack-sources'
2
+
3
+ export interface AsyncPackOpts {
4
+ dynamicModuleJsDir: string;
5
+ dynamicModuleStyleFile: string;
6
+ }
7
+
8
+ export type CompilationAssets = Record<string, Source>;
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2015",
4
+ "module": "commonjs",
5
+ "strict": true,
6
+ "sourceMap": true,
7
+ "declaration": true,
8
+ "esModuleInterop": true,
9
+ "moduleResolution": "node",
10
+ // 声明文件生成到的文件目录
11
+ "outDir": "./dist/",
12
+ "skipLibCheck": true,
13
+ /* Skip type checking of declaration files. */
14
+ "forceConsistentCasingInFileNames": true,
15
+ "jsx": "react",
16
+ "lib": ["esnext", "dom"],
17
+ "types": ["@types/node"]
18
+ },
19
+ "include": ["src"]
20
+ }