balm-core 5.1.0 → 5.2.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/index.d.ts CHANGED
@@ -189,6 +189,8 @@ export interface BalmFtpConfig {
189
189
  username?: string;
190
190
  password?: string;
191
191
  remotePath?: string;
192
+ dirMode?: string;
193
+ fileMode?: string;
192
194
  }
193
195
 
194
196
  export interface BalmConfig {
@@ -1,6 +1,6 @@
1
1
  // Reference `gulp-htmlmin@5.0.1`
2
2
 
3
- import { minify } from 'html-minifier';
3
+ import { minify } from 'html-minifier-terser';
4
4
  const PLUGIN_NAME = 'htmlmin';
5
5
  function gulpHtmlmin(options) {
6
6
  options = BalmJS.utils.deepMerge({}, options);
@@ -9,9 +9,10 @@ function gulpHtmlmin(options) {
9
9
  callback(null, file);
10
10
  return;
11
11
  }
12
- function htmlMinify(buf, enc, cb) {
12
+ async function htmlMinify(buf, enc, cb) {
13
13
  try {
14
- const contents = Buffer.from(minify(buf.toString(), options));
14
+ const minified = await minify(buf.toString(), options);
15
+ const contents = Buffer.from(minified);
15
16
  if (cb === callback) {
16
17
  file.contents = contents;
17
18
  cb(null, file);
@@ -65,7 +65,7 @@ function getKey(options) {
65
65
  function gulpSftp(options) {
66
66
  options = Object.assign({}, options); // Credit sindresorhus
67
67
 
68
- if (options.host === undefined) {
68
+ if (!options.host) {
69
69
  throw new PluginError(PLUGIN_NAME, '`host` required');
70
70
  }
71
71
  let fileCount = 0;
@@ -167,7 +167,8 @@ function gulpSftp(options) {
167
167
  });
168
168
  });
169
169
  conn.on('error', err => {
170
- this.emit('error', new PluginError(PLUGIN_NAME, err));
170
+ const errorMsg = err && (err.message || err.toString()) || 'SFTP connection error';
171
+ this.emit('error', new PluginError(PLUGIN_NAME, errorMsg));
171
172
  });
172
173
  conn.on('end', () => {
173
174
  BalmJS.logger.debug(PLUGIN_NAME, 'Client :: end');
@@ -216,7 +217,6 @@ function gulpSftp(options) {
216
217
  cb => cb(null, fileDirs && fileDirs.length), cb => {
217
218
  let d = fileDirs.pop();
218
219
  mkDirCache[d] = true;
219
- // Mdrake - TODO: use a default file permission instead of defaulting to 755
220
220
  if (remotePlatform && remotePlatform.toLowerCase().indexOf('win') !== -1) {
221
221
  d = d.replace('/', '\\');
222
222
  }
@@ -224,8 +224,9 @@ function gulpSftp(options) {
224
224
  if (exist) {
225
225
  cb();
226
226
  } else {
227
+ const dirMode = options.dirMode || '0755';
227
228
  sftp.mkdir(d, {
228
- mode: '0755'
229
+ mode: dirMode
229
230
  }, err => {
230
231
  // REMOTE PATH
231
232
  if (err) {
@@ -239,10 +240,11 @@ function gulpSftp(options) {
239
240
  }
240
241
  });
241
242
  }, () => {
243
+ const fileMode = options.fileMode || '0666';
242
244
  const stream = sftp.createWriteStream(finalRemotePath, {
243
245
  flags: 'w',
244
246
  encoding: null,
245
- mode: '0666',
247
+ mode: fileMode,
246
248
  autoClose: true
247
249
  });
248
250
 
@@ -49,8 +49,8 @@ class BalmTask {
49
49
  default:
50
50
  }
51
51
  const useAbsPath = !['webpack', 'rollup', 'esbuild', 'sprite'].includes(key);
52
- this.input = useAbsPath ? BalmJS.file.absPaths(input || this.defaultInput) : input || this.defaultInput;
53
- this.output = useAbsPath ? BalmJS.file.absPath(output || this.defaultOutput) : output || this.defaultOutput;
52
+ this.input = useAbsPath && (input || this.defaultInput) ? BalmJS.file.absPaths(input || this.defaultInput) : input || this.defaultInput;
53
+ this.output = useAbsPath && typeof (output || this.defaultOutput) === 'string' ? BalmJS.file.absPath(output || this.defaultOutput) : output || this.defaultOutput;
54
54
  this.customOptions = options[key] || {};
55
55
  const obj = {
56
56
  input: this.input,
@@ -8,7 +8,12 @@ class CacheTask extends BalmJS.BalmTask {
8
8
  super('cache');
9
9
  _defineProperty(this, "fn", () => {
10
10
  this.init();
11
- return this.src.pipe(revAll.revision(BalmJS.config.assets.options)).pipe($.if(/\.html$/, BalmJS.file.setPublicPath())).pipe(gulp.dest(this.output)).pipe($.revDeleteOriginal()).pipe(revAll.manifestFile()).pipe(gulp.dest(this.output));
11
+ this.gulpSrcOptions = {
12
+ base: this.output
13
+ };
14
+ return this.src.pipe(revAll.revision(BalmJS.config.assets.options)).pipe($.if(/\.html$/, BalmJS.file.setPublicPath())).pipe(gulp.dest(this.output)).pipe($.revDeleteOriginal({
15
+ exclude: /\.html$/
16
+ })).pipe(revAll.manifestFile()).pipe(gulp.dest(this.output));
12
17
  });
13
18
  const defaultIncludes = BalmJS.config.scripts.useCache ? ASSETS_TYPES.filter(assetType => assetType !== 'js').map(assetType => BalmJS.file.matchAllFiles(BalmJS.config.dest[assetType])) : ASSETS_TYPES.map(assetType => BalmJS.file.matchAllFiles(BalmJS.config.dest[assetType]));
14
19
  const defaultExcludes = [node.path.join(`!${BalmJS.config.dest.js}`, CHUNK.dir, '*'), node.path.join(`!${BalmJS.config.dest.js}`, ASSET.dir, '*'), node.path.join(`!${BalmJS.config.dest.base}`, BalmJS.config.pwa.manifest)];
@@ -18,6 +23,9 @@ class CacheTask extends BalmJS.BalmTask {
18
23
  });
19
24
  this.defaultInput = [...defaultIncludes, ...defaultExcludes, ...(BalmJS.config.inFrontend ? [node.path.join(BalmJS.config.dest.base, '*.html')] : []), ...customIncludes, ...customExcludes];
20
25
  this.defaultOutput = BalmJS.config.inFrontend ? BalmJS.config.dest.base : BalmJS.config.dest.static;
26
+ this.gulpSrcOptions = {
27
+ base: this.defaultOutput
28
+ };
21
29
  }
22
30
  }
23
31
  export default CacheTask;
@@ -7,6 +7,10 @@ class PwaCacheTask extends BalmJS.BalmTask {
7
7
  super('pwa-cache');
8
8
  _defineProperty(this, "fn", () => {
9
9
  this.init();
10
+ const swDest = typeof this.input === 'string' && this.input ? BalmJS.file.absPath(this.input) : '';
11
+ if (!swDest || !node.fs.existsSync(swDest)) {
12
+ return Promise.resolve();
13
+ }
10
14
  const newVersion = BalmJS.config.pwa.version || Date.now().toString();
11
15
  BalmJS.logger.info('pwa - version', newVersion);
12
16
  const stream = this.src.pipe(BalmJS.plugins.replace('{{ version }}', newVersion)).pipe($.if(BalmJS.config.env.isProd, BalmJS.plugins.jsmin(BalmJS.config.scripts.minifyOptions))).pipe(gulp.dest(this.output));
@@ -17,10 +21,12 @@ class PwaCacheTask extends BalmJS.BalmTask {
17
21
  this.defaultInput = node.path.join(this.defaultOutput, BalmJS.config.pwa.swDestFilename);
18
22
  }
19
23
  clear() {
20
- const swOrigin = BalmJS.file.absPath(node.path.join(BalmJS.config.dest.base, BalmJS.config.pwa.swSrcFilename));
21
- deleteAsync(swOrigin, {
22
- force: true
23
- });
24
+ if (BalmJS.config.pwa.swSrcFilename !== BalmJS.config.pwa.swDestFilename) {
25
+ const swOrigin = BalmJS.file.absPath(node.path.join(BalmJS.config.dest.base, BalmJS.config.pwa.swSrcFilename));
26
+ deleteAsync(swOrigin, {
27
+ force: true
28
+ });
29
+ }
24
30
  }
25
31
  }
26
32
  export default PwaCacheTask;
@@ -8,13 +8,19 @@ class PublishTask extends BalmJS.BalmTask {
8
8
  constructor() {
9
9
  super('publish');
10
10
  _classPrivateFieldInitSpec(this, _release, (input, output, renameOptions = {}) => {
11
+ let srcPath;
12
+ let destPath;
11
13
  if (input && output) {
12
- this.init(node.path.join(BalmJS.config.dest.base, input), node.path.join(BalmJS.config.assets.root, output) // Remote dir
13
- );
14
+ srcPath = BalmJS.file.absPaths(node.path.join(BalmJS.config.dest.base, input));
15
+ destPath = BalmJS.file.absPath(node.path.join(BalmJS.config.assets.root, output));
14
16
  } else {
15
17
  this.init();
18
+ srcPath = this.input;
19
+ destPath = this.output;
16
20
  }
17
- return this.src.pipe($.if(!BalmJS.utils.isArray(this.input), BalmJS.plugins.rename(renameOptions))).pipe(gulp.dest(this.output)); // Absolute path
21
+ return gulp.src(srcPath, {
22
+ allowEmpty: true
23
+ }).pipe($.if(!BalmJS.utils.isArray(srcPath), BalmJS.plugins.rename(renameOptions))).pipe(gulp.dest(destPath));
18
24
  });
19
25
  this.defaultInput = [BalmJS.file.matchAllFiles(BalmJS.config.dest.static),
20
26
  // Assets
@@ -45,15 +45,30 @@ class PwaTask extends BalmJS.BalmTask {
45
45
  pre: true
46
46
  });
47
47
  const workboxBuild = mode === 'generateSW' ? generateSW(options) : injectManifest(options);
48
- await workboxBuild.then(({
49
- count,
50
- size
51
- }) => {
48
+ try {
49
+ const {
50
+ count,
51
+ size
52
+ } = await workboxBuild;
52
53
  BalmJS.logger.info(`pwa - ${mode}`, `Generated '${swDest}', which will precache ${count} files, totaling ${size} bytes`);
53
- gulp.parallel(BalmJS.toNamespace('pwa-cache'))();
54
- }).catch(err => {
54
+ await new Promise(resolve => {
55
+ const pwaCacheTask = BalmJS.tasks.get('pwa-cache');
56
+ if (pwaCacheTask) {
57
+ const stream = pwaCacheTask.fn();
58
+ if (stream && typeof stream.on === 'function') {
59
+ stream.on('finish', resolve).on('error', () => resolve());
60
+ } else if (stream && typeof stream.then === 'function') {
61
+ stream.then(resolve, resolve);
62
+ } else {
63
+ resolve();
64
+ }
65
+ } else {
66
+ resolve();
67
+ }
68
+ });
69
+ } catch (err) {
55
70
  BalmJS.logger.warn(`pwa - ${mode}`, `Service worker generation failed: ${err}`);
56
- });
71
+ }
57
72
  callback();
58
73
  } else {
59
74
  BalmJS.logger.warn('pwa task', 'Invalid PWA mode');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "balm-core",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "BalmJS compiler core",
5
5
  "keywords": [
6
6
  "balm",
@@ -66,7 +66,7 @@
66
66
  "gulp-zip": "^6.1.0",
67
67
  "gulp.spritesmith": "^6.13.1",
68
68
  "html-loader": "^5.1.0",
69
- "html-minifier": "^4.0.0",
69
+ "html-minifier-terser": "^7.2.0",
70
70
  "html-webpack-plugin": "^5.6.7",
71
71
  "http-proxy-middleware": "3",
72
72
  "imagemin": "^9.0.1",
@@ -90,7 +90,7 @@
90
90
  "sass-loader": "^16.0.8",
91
91
  "semver": "^7.8.0",
92
92
  "ssh2": "^1.17.0",
93
- "strip-ansi": "^7.2.0",
93
+ "strip-ansi": "^6.0.1",
94
94
  "style-loader": "^4.0.0",
95
95
  "tailwindcss": "^4.3.0",
96
96
  "terser": "^5.47.1",
@@ -111,7 +111,7 @@
111
111
  "@types/browser-sync": "2",
112
112
  "@types/express": "5",
113
113
  "@types/fancy-log": "2",
114
- "@types/html-minifier": "4",
114
+ "@types/html-minifier-terser": "^7.0.2",
115
115
  "@types/imagemin": "9",
116
116
  "@types/parents": "1",
117
117
  "@types/postcss-flexbugs-fixes": "5",
@@ -130,6 +130,5 @@
130
130
  },
131
131
  "engines": {
132
132
  "node": "^20.19.0 || >=22.0.0"
133
- },
134
- "gitHead": "561aaa5e4a9ad75b5b047ada2d8a66900e1d5431"
133
+ }
135
134
  }
@@ -1,4 +1,4 @@
1
- import { minify } from 'html-minifier';
1
+ import { minify } from 'html-minifier-terser';
2
2
  const PLUGIN_NAME = 'htmlmin';
3
3
  function gulpHtmlmin(options) {
4
4
  options = BalmJS.utils.deepMerge({}, options);
@@ -7,9 +7,10 @@ function gulpHtmlmin(options) {
7
7
  callback(null, file);
8
8
  return;
9
9
  }
10
- function htmlMinify(buf, enc, cb) {
10
+ async function htmlMinify(buf, enc, cb) {
11
11
  try {
12
- const contents = Buffer.from(minify(buf.toString(), options));
12
+ const minified = await minify(buf.toString(), options);
13
+ const contents = Buffer.from(minified);
13
14
  if (cb === callback) {
14
15
  file.contents = contents;
15
16
  cb(null, file);
@@ -71,7 +71,7 @@ function getKey(options) {
71
71
  }
72
72
  function gulpSftp(options) {
73
73
  options = Object.assign({}, options);
74
- if (options.host === undefined) {
74
+ if (!options.host) {
75
75
  throw new PluginError(PLUGIN_NAME, '`host` required');
76
76
  }
77
77
  let fileCount = 0;
@@ -154,7 +154,8 @@ function gulpSftp(options) {
154
154
  });
155
155
  });
156
156
  conn.on('error', (err) => {
157
- this.emit('error', new PluginError(PLUGIN_NAME, err));
157
+ const errorMsg = (err && (err.message || err.toString())) || 'SFTP connection error';
158
+ this.emit('error', new PluginError(PLUGIN_NAME, errorMsg));
158
159
  });
159
160
  conn.on('end', () => {
160
161
  BalmJS.logger.debug(PLUGIN_NAME, 'Client :: end');
@@ -195,7 +196,8 @@ function gulpSftp(options) {
195
196
  cb();
196
197
  }
197
198
  else {
198
- sftp.mkdir(d, { mode: '0755' }, (err) => {
199
+ const dirMode = options.dirMode || '0755';
200
+ sftp.mkdir(d, { mode: dirMode }, (err) => {
199
201
  if (err) {
200
202
  BalmJS.logger.warn(PLUGIN_NAME, `Error or directory exists: ${err} ${d}`);
201
203
  }
@@ -207,10 +209,11 @@ function gulpSftp(options) {
207
209
  }
208
210
  });
209
211
  }, () => {
212
+ const fileMode = options.fileMode || '0666';
210
213
  const stream = sftp.createWriteStream(finalRemotePath, {
211
214
  flags: 'w',
212
215
  encoding: null,
213
- mode: '0666',
216
+ mode: fileMode,
214
217
  autoClose: true
215
218
  });
216
219
  if (file.isStream()) {
@@ -48,10 +48,10 @@ class BalmTask {
48
48
  default:
49
49
  }
50
50
  const useAbsPath = !['webpack', 'rollup', 'esbuild', 'sprite'].includes(key);
51
- this.input = useAbsPath
51
+ this.input = useAbsPath && (input || this.defaultInput)
52
52
  ? BalmJS.file.absPaths(input || this.defaultInput)
53
53
  : input || this.defaultInput;
54
- this.output = useAbsPath
54
+ this.output = useAbsPath && typeof (output || this.defaultOutput) === 'string'
55
55
  ? BalmJS.file.absPath(output || this.defaultOutput)
56
56
  : output || this.defaultOutput;
57
57
  this.customOptions = options[key] || {};
@@ -27,14 +27,20 @@ class CacheTask extends BalmJS.BalmTask {
27
27
  this.defaultOutput = BalmJS.config.inFrontend
28
28
  ? BalmJS.config.dest.base
29
29
  : BalmJS.config.dest.static;
30
+ this.gulpSrcOptions = {
31
+ base: this.defaultOutput
32
+ };
30
33
  }
31
34
  fn = () => {
32
35
  this.init();
36
+ this.gulpSrcOptions = {
37
+ base: this.output
38
+ };
33
39
  return this.src
34
40
  .pipe(revAll.revision(BalmJS.config.assets.options))
35
41
  .pipe($.if(/\.html$/, BalmJS.file.setPublicPath()))
36
42
  .pipe(gulp.dest(this.output))
37
- .pipe($.revDeleteOriginal())
43
+ .pipe($.revDeleteOriginal({ exclude: /\.html$/ }))
38
44
  .pipe(revAll.manifestFile())
39
45
  .pipe(gulp.dest(this.output));
40
46
  };
@@ -6,11 +6,19 @@ class PwaCacheTask extends BalmJS.BalmTask {
6
6
  this.defaultInput = node.path.join(this.defaultOutput, BalmJS.config.pwa.swDestFilename);
7
7
  }
8
8
  clear() {
9
- const swOrigin = BalmJS.file.absPath(node.path.join(BalmJS.config.dest.base, BalmJS.config.pwa.swSrcFilename));
10
- deleteAsync(swOrigin, { force: true });
9
+ if (BalmJS.config.pwa.swSrcFilename !== BalmJS.config.pwa.swDestFilename) {
10
+ const swOrigin = BalmJS.file.absPath(node.path.join(BalmJS.config.dest.base, BalmJS.config.pwa.swSrcFilename));
11
+ deleteAsync(swOrigin, { force: true });
12
+ }
11
13
  }
12
14
  fn = () => {
13
15
  this.init();
16
+ const swDest = typeof this.input === 'string' && this.input
17
+ ? BalmJS.file.absPath(this.input)
18
+ : '';
19
+ if (!swDest || !node.fs.existsSync(swDest)) {
20
+ return Promise.resolve();
21
+ }
14
22
  const newVersion = BalmJS.config.pwa.version || Date.now().toString();
15
23
  BalmJS.logger.info('pwa - version', newVersion);
16
24
  const stream = this.src
@@ -9,15 +9,21 @@ class PublishTask extends BalmJS.BalmTask {
9
9
  this.defaultOutput = BalmJS.config.assets.static;
10
10
  }
11
11
  #release = (input, output, renameOptions = {}) => {
12
+ let srcPath;
13
+ let destPath;
12
14
  if (input && output) {
13
- this.init(node.path.join(BalmJS.config.dest.base, input), node.path.join(BalmJS.config.assets.root, output));
15
+ srcPath = BalmJS.file.absPaths(node.path.join(BalmJS.config.dest.base, input));
16
+ destPath = BalmJS.file.absPath(node.path.join(BalmJS.config.assets.root, output));
14
17
  }
15
18
  else {
16
19
  this.init();
20
+ srcPath = this.input;
21
+ destPath = this.output;
17
22
  }
18
- return this.src
19
- .pipe($.if(!BalmJS.utils.isArray(this.input), BalmJS.plugins.rename(renameOptions)))
20
- .pipe(gulp.dest(this.output));
23
+ return gulp
24
+ .src(srcPath, { allowEmpty: true })
25
+ .pipe($.if(!BalmJS.utils.isArray(srcPath), BalmJS.plugins.rename(renameOptions)))
26
+ .pipe(gulp.dest(destPath));
21
27
  };
22
28
  recipe(input, output, renameOptions) {
23
29
  const balmPublish = (callback) => {
@@ -46,14 +46,31 @@ class PwaTask extends BalmJS.BalmTask {
46
46
  const workboxBuild = mode === 'generateSW'
47
47
  ? generateSW(options)
48
48
  : injectManifest(options);
49
- await workboxBuild
50
- .then(({ count, size }) => {
49
+ try {
50
+ const { count, size } = await workboxBuild;
51
51
  BalmJS.logger.info(`pwa - ${mode}`, `Generated '${swDest}', which will precache ${count} files, totaling ${size} bytes`);
52
- gulp.parallel(BalmJS.toNamespace('pwa-cache'))();
53
- })
54
- .catch((err) => {
52
+ await new Promise((resolve) => {
53
+ const pwaCacheTask = BalmJS.tasks.get('pwa-cache');
54
+ if (pwaCacheTask) {
55
+ const stream = pwaCacheTask.fn();
56
+ if (stream && typeof stream.on === 'function') {
57
+ stream.on('finish', resolve).on('error', () => resolve());
58
+ }
59
+ else if (stream && typeof stream.then === 'function') {
60
+ stream.then(resolve, resolve);
61
+ }
62
+ else {
63
+ resolve();
64
+ }
65
+ }
66
+ else {
67
+ resolve();
68
+ }
69
+ });
70
+ }
71
+ catch (err) {
55
72
  BalmJS.logger.warn(`pwa - ${mode}`, `Service worker generation failed: ${err}`);
56
- });
73
+ }
57
74
  callback();
58
75
  }
59
76
  else {