hw-weapp-compiler 1.0.6 → 1.0.8

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/README.md CHANGED
@@ -17,12 +17,12 @@ npm i weapp-compiler@2.x -D
17
17
  ```bash
18
18
  # 开发调试
19
19
  npm run dev # 测试环境
20
- npm run dev -s # 预发环境
21
- npm run dev -p # 生产环境
20
+ npm run dev -- -s # 预发环境
21
+ npm run dev -- -p # 生产环境
22
22
 
23
23
  # 生产发布
24
- npm run build -d # 测试环境
25
- npm run build -s # 预发环境
24
+ npm run build -- -d # 测试环境
25
+ npm run build -- -s # 预发环境
26
26
  npm run build # 生产环境
27
27
  ```
28
28
 
@@ -2,7 +2,6 @@ const path = require('path');
2
2
  const fse = require('fs-extra');
3
3
  const { addNodeModulesUsingComponent } = require('../utils/isNodeModulesUsingComponent');
4
4
  const { compatiblePath } = require('../utils/compatiblePath');
5
- const { traverseDir } = require('../utils/traverseDir');
6
5
  const { getAppConfig } = require('./getAppConfig');
7
6
  const { PATTERNS, SRC_DIR } = require('./constants');
8
7
  const appConfig = getAppConfig();
@@ -10,8 +9,17 @@ const appConfig = getAppConfig();
10
9
  const entries = {
11
10
  app: path.resolve(SRC_DIR, 'app'),
12
11
  };
12
+ const visitedJsonFiles = new Set();
13
+ const entryFiles = [entries.app];
14
+
15
+ const addEntry = (entryKey, filePath) => {
16
+ entries[compatiblePath(entryKey)] = filePath;
17
+ entryFiles.push(filePath);
18
+ };
19
+
13
20
  const addUsingComponents = (components, parent) => {
14
21
  Object.keys(components).forEach((key) => {
22
+ const originalFilePath = components[key];
15
23
  let filePath = components[key];
16
24
 
17
25
  if (!PATTERNS.PLUGIN_PATH.test(filePath)) {
@@ -26,8 +34,9 @@ const addUsingComponents = (components, parent) => {
26
34
  filePath = require.resolve(filePath);
27
35
  filePath = filePath.replace(PATTERNS.JS_EXT, '');
28
36
  } catch (error) {
29
- console.error(error);
30
- return;
37
+ throw new Error(
38
+ `解析 usingComponents "${key}" 的组件路径 "${originalFilePath}" 失败,父级目录:${parent}\n${error.message}`,
39
+ );
31
40
  }
32
41
  }
33
42
 
@@ -53,35 +62,48 @@ const addUsingComponents = (components, parent) => {
53
62
  });
54
63
  };
55
64
  const readUsingComponents = (file) => {
65
+ const jsonFile = path.resolve(file);
66
+
67
+ if (visitedJsonFiles.has(jsonFile)) {
68
+ return;
69
+ }
70
+
71
+ visitedJsonFiles.add(jsonFile);
72
+
56
73
  const json = fse.readJSONSync(file);
57
74
 
58
75
  if (json.usingComponents) {
59
76
  addUsingComponents(json.usingComponents, path.parse(file).dir);
60
77
  }
61
78
  };
79
+ const readEntryUsingComponents = (filePath) => {
80
+ const jsonFile = `${filePath}.json`;
81
+
82
+ if (fse.existsSync(jsonFile)) {
83
+ readUsingComponents(jsonFile);
84
+ }
85
+ };
62
86
 
63
87
  // pages
64
88
  (appConfig.pages || []).forEach((page) => {
65
- entries[page] = path.resolve(SRC_DIR, page);
89
+ addEntry(page, path.resolve(SRC_DIR, page));
66
90
  });
67
91
 
68
92
  // tabbar
69
93
  if (fse.existsSync(path.resolve(SRC_DIR, 'custom-tab-bar/index.js'))) {
70
- entries['custom-tab-bar/index'] = path.resolve(SRC_DIR, 'custom-tab-bar/index');
94
+ addEntry('custom-tab-bar/index', path.resolve(SRC_DIR, 'custom-tab-bar/index'));
71
95
  }
72
96
 
73
97
  // subpackages
74
98
  (appConfig.subpackages || []).forEach((pkg) => {
75
99
  (pkg.pages || []).forEach((page) => {
76
- entries[compatiblePath(path.join(pkg.root, page))] = path.resolve(SRC_DIR, pkg.root, page);
100
+ addEntry(path.join(pkg.root, page), path.resolve(SRC_DIR, pkg.root, page));
77
101
  });
78
102
  });
79
103
 
80
104
  // usingComponents
81
- traverseDir(SRC_DIR).forEach((item) => {
82
- if (PATTERNS.JSON_EXT.test(item)) {
83
- readUsingComponents(item);
84
- }
105
+ entryFiles.forEach((filePath) => {
106
+ readEntryUsingComponents(filePath);
85
107
  });
86
108
 
87
109
  function getEntries() {
package/build/dev.js CHANGED
@@ -10,7 +10,7 @@ module.exports = (opts) => {
10
10
  if (fse.existsSync(DIST_DIR)) {
11
11
  const files = fse.readdirSync(DIST_DIR);
12
12
  files.forEach((item) => {
13
- if (!/project\.config\.json/.test(item)) {
13
+ if (!/^(project\.config\.json|weapp\.env\.json)$/.test(item)) {
14
14
  fse.removeSync(path.resolve(DIST_DIR, item));
15
15
  }
16
16
  });
@@ -38,7 +38,7 @@ module.exports = async function loader(source) {
38
38
  const result = assetResults[index];
39
39
  if (result) {
40
40
  const [attr, src] = result;
41
- content = content.replace(attr, withPublicPath(src));
41
+ content = content.split(attr).join(withPublicPath(src));
42
42
  }
43
43
  }
44
44
 
@@ -2,20 +2,16 @@
2
2
  * WeappPlugin - 微信小程序 webpack 构建插件
3
3
  *
4
4
  * 负责在构建产物中注入公共模块引用、runtime 全局暴露、分包公共模块引用,
5
- * 以及在开发模式下压缩公共模块代码。
5
+ * 确保小程序运行时能正确加载 webpack 产物。
6
6
  */
7
7
  const path = require('path');
8
- const UglifyJS = require('uglify-js');
9
- const hasha = require('hasha');
10
8
  const { RawSource } = require('webpack-sources');
11
9
 
12
- const { isNodeModulesUsingComponent } = require('../utils/isNodeModulesUsingComponent');
13
10
  const { addToUploadQueue } = require('../utils/upload');
14
11
  const { compatiblePath } = require('../utils/compatiblePath');
15
- const { ENV, PATTERNS, ASSET_EXT_PATTERN, ASSETS_DIR } = require('../config/constants');
12
+ const { PATTERNS, ASSET_EXT_PATTERN, ASSETS_DIR } = require('../config/constants');
16
13
 
17
14
  const pluginName = 'WeappCompilerPlugin';
18
- const contentCache = {};
19
15
 
20
16
  /**
21
17
  * 检测产物中存在哪些公共模块和分包模块
@@ -123,6 +119,15 @@ function injectGlobalModules(content, assetName, flags) {
123
119
  return result;
124
120
  }
125
121
 
122
+ function getRelativeModulePath(from, to) {
123
+ const relativePath = compatiblePath(path.relative(from, to));
124
+
125
+ if (/^(\.\/|\.\.\/)/.test(relativePath)) {
126
+ return relativePath;
127
+ }
128
+ return `./${relativePath}`;
129
+ }
130
+
126
131
  /**
127
132
  * 注入分包公共模块引用
128
133
  */
@@ -141,18 +146,14 @@ function injectSubpackageRequires(content, assetName, subpackages) {
141
146
  PATTERNS.JS_EXT.test(assetName) &&
142
147
  !/'subpackage_common\.js'\);/.test(result)
143
148
  ) {
144
- result = `require('${compatiblePath(
145
- path.relative(path.parse(assetName).dir, res.js),
146
- )}');\n${result}`;
149
+ result = `require('${getRelativeModulePath(path.parse(assetName).dir, res.js)}');\n${result}`;
147
150
  }
148
151
  if (
149
152
  res.wxss &&
150
153
  PATTERNS.WXSS_EXT.test(assetName) &&
151
154
  !/'subpackage_common\.wxss';/.test(result)
152
155
  ) {
153
- result = `@import '${compatiblePath(
154
- path.relative(path.parse(assetName).dir, res.wxss),
155
- )}';\n${result}`;
156
+ result = `@import '${getRelativeModulePath(path.parse(assetName).dir, res.wxss)}';\n${result}`;
156
157
  }
157
158
  }
158
159
  });
@@ -160,43 +161,6 @@ function injectSubpackageRequires(content, assetName, subpackages) {
160
161
  return result;
161
162
  }
162
163
 
163
- /**
164
- * 在开发模式下压缩公共模块代码
165
- */
166
- function minifyCommonModules(content, assetName, isJs, isDev) {
167
- if (!isDev) {
168
- return content;
169
- }
170
-
171
- const isCommon = assetName === 'commons.js' || assetName === 'vendors.js';
172
- const isNodeModule = isNodeModulesUsingComponent(assetName);
173
-
174
- if (!isCommon && !isNodeModule) {
175
- return content;
176
- }
177
-
178
- if (!isJs) {
179
- return content;
180
- }
181
-
182
- const hash = hasha(content);
183
- if (contentCache[assetName] && contentCache[assetName].hash === hash) {
184
- return contentCache[assetName].content;
185
- }
186
-
187
- const result = UglifyJS.minify(content, {
188
- mangle: false,
189
- compress: {
190
- drop_console: false,
191
- drop_debugger: false,
192
- },
193
- sourceMap: false,
194
- }).code;
195
-
196
- contentCache[assetName] = { hash, content: result };
197
- return result;
198
- }
199
-
200
164
  class WeappPlugin {
201
165
  constructor() {}
202
166
 
@@ -237,7 +201,6 @@ class WeappPlugin {
237
201
  await Promise.all(
238
202
  items.map(async (asset) => {
239
203
  const assetName = compatiblePath(asset.name);
240
- const isJs = PATTERNS.JS_EXT.test(assetName);
241
204
  let content = asset.source.source();
242
205
 
243
206
  if (content.toString) {
@@ -246,7 +209,6 @@ class WeappPlugin {
246
209
 
247
210
  content = injectGlobalModules(content, assetName, flags);
248
211
  content = injectSubpackageRequires(content, assetName, subpackages);
249
- content = minifyCommonModules(content, assetName, isJs, compiler.options.mode === ENV.DEV);
250
212
 
251
213
  compilation.updateAsset(asset.name, new RawSource(content));
252
214
  }),
package/build/prod.js CHANGED
@@ -15,7 +15,7 @@ module.exports = (opts) => {
15
15
  devtool: false,
16
16
  output: {
17
17
  clean: {
18
- keep: /project\.config\.json/,
18
+ keep: /^(project\.config\.json|weapp\.env\.json)$/,
19
19
  },
20
20
  },
21
21
  optimization: {
@@ -4,11 +4,18 @@ const chalk = require('chalk');
4
4
  * 创建 webpack 编译结果回调处理器
5
5
  * @param {string} label - 构建阶段标签,如 'dev' 或 'build'
6
6
  */
7
- function createCompilerHandler(label) {
7
+ function createCompilerHandler(label, { failOnError = label === 'build' } = {}) {
8
+ const markFailed = () => {
9
+ if (failOnError) {
10
+ process.exitCode = 1;
11
+ }
12
+ };
13
+
8
14
  return (err, stats) => {
9
15
  if (err) {
10
16
  console.error(chalk.red(`${label} failed with fatal error:`));
11
17
  console.error(err);
18
+ markFailed();
12
19
  return;
13
20
  }
14
21
 
@@ -20,6 +27,7 @@ function createCompilerHandler(label) {
20
27
  }),
21
28
  );
22
29
  console.error(chalk.red(`${label} completed with errors`));
30
+ markFailed();
23
31
  return;
24
32
  }
25
33
 
@@ -1,21 +1,22 @@
1
- const { createPool, POOL_SIZE } = require('./loadModule');
2
1
  const htmlparser2 = require('htmlparser2');
3
2
  const path = require('path');
4
3
  const fse = require('fs-extra');
5
4
  const { ASSET_EXT_PATTERN, PATTERNS, SRC_DIR } = require('../config/constants');
6
5
 
7
- const resolvePool = createPool(POOL_SIZE);
8
-
9
6
  function getWxmlAssets(filePath, content) {
10
7
  const resolvePath = (attr, dir) => {
11
- return resolvePool(
12
- () =>
13
- new Promise((resolve) => {
14
- this.resolve(SRC_DIR, attr, async (err, result) => {
8
+ return new Promise((resolve) => {
9
+ const isAbsolutePath = PATTERNS.ABSOLUTE_PATH.test(attr);
10
+ const request = isAbsolutePath ? attr.replace(PATTERNS.ABSOLUTE_PATH, '') : attr;
11
+ const resolveContext = isAbsolutePath ? SRC_DIR : dir;
12
+
13
+ this.resolve(resolveContext, request, async (err, result) => {
15
14
  let res = result;
16
15
  if (err) {
17
- if (await fse.pathExists(path.resolve(dir, attr))) {
18
- res = path.resolve(dir, attr);
16
+ const fallbackPath = path.resolve(resolveContext, request);
17
+
18
+ if (await fse.pathExists(fallbackPath)) {
19
+ res = fallbackPath;
19
20
  resolve(res);
20
21
  } else {
21
22
  this.emitError(err);
@@ -25,8 +26,7 @@ function getWxmlAssets(filePath, content) {
25
26
  resolve(res);
26
27
  }
27
28
  });
28
- }),
29
- );
29
+ });
30
30
  };
31
31
  return new Promise((resolve, reject) => {
32
32
  let allAttrs = [];
@@ -69,7 +69,7 @@ function getWxmlAssets(filePath, content) {
69
69
  .filter((item) => !/\+.*\+/.test(item));
70
70
 
71
71
  const assets = filteredAttrs.filter((item) => ASSET_EXT_PATTERN.test(item));
72
- const wxmls = allAttrs.filter((item) => PATTERNS.WXS_EXT.test(item) || PATTERNS.WXML_EXT.test(item));
72
+ const wxmls = filteredAttrs.filter((item) => PATTERNS.WXS_EXT.test(item) || PATTERNS.WXML_EXT.test(item));
73
73
 
74
74
  const assetsImports = [];
75
75
  const wxmlsImports = [];
@@ -1,55 +1,16 @@
1
- const POOL_SIZE = 16;
2
-
3
- function createPool(limit) {
4
- let active = 0;
5
- const pending = [];
6
- const next = () => {
7
- while (pending.length && active < limit) {
8
- const { fn, resolve, reject } = pending.shift();
9
- active++;
10
- Promise.resolve()
11
- .then(fn)
12
- .then(
13
- (v) => {
14
- active--;
15
- resolve(v);
16
- next();
17
- },
18
- (e) => {
19
- active--;
20
- reject(e);
21
- next();
22
- },
23
- );
24
- }
25
- };
26
- return (fn) =>
27
- new Promise((resolve, reject) => {
28
- pending.push({ fn, resolve, reject });
29
- next();
30
- });
31
- }
32
-
33
- const pool = createPool(POOL_SIZE);
34
-
35
1
  function loadModule(file) {
36
- return pool(
37
- () =>
38
- new Promise((resolve) => {
39
- this.addDependency(file);
40
- this.loadModule(file, (err, src) => {
41
- if (err) {
42
- this.emitError(err);
43
- resolve(null);
44
- } else {
45
- resolve(src);
46
- }
47
- });
48
- }),
49
- );
2
+ return new Promise((resolve, reject) => {
3
+ this.addDependency(file);
4
+ this.loadModule(file, (err, src) => {
5
+ if (err) {
6
+ this.emitError(err);
7
+ reject(err);
8
+ } else {
9
+ resolve(src);
10
+ }
11
+ });
12
+ });
50
13
  }
51
14
  module.exports = {
52
15
  loadModule,
53
- createPool,
54
- POOL_SIZE,
55
16
  };
package/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hw-weapp-compiler",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "基于 webpack5 的小程序构建工具,兼容 Node.js 14~24",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -29,7 +29,6 @@
29
29
  "esdk-obs-nodejs": "^3.21.3",
30
30
  "file-loader": "^6.2.0",
31
31
  "fs-extra": "^9.1.0",
32
- "hasha": "^5.2.2",
33
32
  "htmlparser2": "^6.0.1",
34
33
  "less": "^4.1.1",
35
34
  "less-loader": "^8.0.0",
@@ -40,7 +39,6 @@
40
39
  "progress": "^2.0.3",
41
40
  "terser-webpack-plugin": "^5.6.1",
42
41
  "throttle-debounce": "^3.0.1",
43
- "uglify-js": "^3.14.2",
44
42
  "url-loader": "^4.1.1",
45
43
  "webpack": "^5.61.0",
46
44
  "webpack-bundle-analyzer": "^4.4.0",