jizy-packer 2.0.5 → 2.1.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/README.md CHANGED
@@ -1,2 +1,120 @@
1
+
1
2
  # jizy-packer
2
- Build a CLI app to generate optimized builds.
3
+
4
+ A CLI tool and Node.js library to generate optimized builds for your projects. It provides utilities for configuration management, build orchestration, and file operations.
5
+
6
+ ## Features
7
+
8
+ - Command-line interface for building projects
9
+ - Configurable via JSON and programmatic API
10
+ - Utilities for cleaning build folders and managing configs
11
+ - Rollup-based build process with plugin support
12
+
13
+ ## Quick Usage
14
+
15
+ ### CLI
16
+
17
+ ```sh
18
+ node lib/Cli.js
19
+ node lib/Cli.js --action build --name perso --config { "key": "value" }
20
+ node lib/Cli.js --action build --name perso --config ABSOLUTE_PATH_TO_JSON_FILE
21
+ ```
22
+
23
+ Options:
24
+ - `--action, -a` Build action (dist|build)
25
+ - `--name, -n` Name of the build
26
+ - `--config, -c` Path to the custom config file or JSON string
27
+ - `--debug, -d` Enable debug mode
28
+
29
+ ### Programmatic
30
+
31
+ ```js
32
+ import jPackBuild from './lib/Build.js';
33
+
34
+ await jPackBuild({
35
+ action: 'build',
36
+ name: 'perso',
37
+ config: 'PATH_TO_JSON_FILE',
38
+ debug: true
39
+ });
40
+ ```
41
+
42
+ ### Create a jPacker
43
+
44
+ Example from the "jizy-browser" extension.
45
+
46
+ ***First for the default dist build***
47
+
48
+ #### ./config/config.json
49
+ ```json
50
+ {
51
+ "desktopBreakpoint": "900px"
52
+ }
53
+ ```
54
+
55
+ #### ./config/jpack.js
56
+ ```js
57
+ import fs from 'fs';
58
+ import path from 'path';
59
+ import { LogMe, jPackConfig } from 'jizy-packer';
60
+
61
+ const jPackData = {
62
+ name: 'BrowserCompat',
63
+ alias: 'jizy-browser',
64
+
65
+ onCheckConfig: () => {
66
+ // add some config validation
67
+ const desktopBreakpoint = jPackConfig.get('desktopBreakpoint');
68
+ if (!desktopBreakpoint) {
69
+ LogMe.error('Missing desktopBreakpoint in config');
70
+ process.exit(1);
71
+ }
72
+ },
73
+
74
+ // generate config.less
75
+ onGenerateBuildJs: (code) => {
76
+ LogMe.log('Generate config.less');
77
+ const desktopBreakpoint = jPackConfig.get('desktopBreakpoint') ?? '768px';
78
+ let lessContent = `@desktop-breakpoint: ${desktopBreakpoint};\n`;
79
+ lessContent += `@mobile-breakpoint: @desktop-breakpoint - 1px;`;
80
+ fs.writeFileSync(path.join(jPackConfig.get('targetPath'), 'config.less'), lessContent);
81
+ return code;
82
+ },
83
+
84
+ // parse wrapped js
85
+ onGenerateWrappedJs: (wrapped) => wrapped,
86
+
87
+ // after packing
88
+ onPacked: () => { }
89
+ };
90
+
91
+ export default jPackData;
92
+ ```
93
+
94
+ #### ./config/jpack.template
95
+ ```js
96
+ import BrowserCompat from '{{PREFIX}}lib/js/browsercompat.js';
97
+ import '{{PREFIX}}lib/browsercompat.less';
98
+ export default BrowserCompat;
99
+ ```
100
+
101
+ #### ./config/jpack.wrapper.js
102
+ ```js
103
+ /*! BrowserCompat v@VERSION | @DATE | [@BUNDLE] */
104
+ (function (global) {
105
+ "use strict";
106
+
107
+ if (typeof global !== "object" || !global || !global.document) {
108
+ throw new Error("BrowserCompat requires a window and a document");
109
+ }
110
+
111
+ if (typeof global.BrowserCompat !== "undefined") {
112
+ throw new Error("BrowserCompat is already defined");
113
+ }
114
+
115
+ // @CODE
116
+
117
+ global.BrowserCompat = BrowserCompat;
118
+
119
+ })(typeof window !== "undefined" ? window : this);
120
+ ```
package/lib/Build.js CHANGED
@@ -5,187 +5,151 @@ import { rollup } from 'rollup';
5
5
  import LogMe from "./LogMe.js";
6
6
  import jPackConfig from "./Config.js";
7
7
  import jPackRollup from "./Rollup.js";
8
- import { cleanBuildFolder } from './utils.js';
8
+ import { emptyTargetPath, loadJson } from "./utils.js";
9
+
10
+ /**
11
+ * @param {string} action the build action (dist|build) defaults to dist
12
+ * @param {string} name the name of the build ([a-z0-9\-\_])
13
+ * @param {string } config the path to the custom config.json file
14
+ * @param {boolean} debug for verbose logging
15
+ *
16
+ * 1. build dist default export
17
+ * no params
18
+ * default package config
19
+ * use ./config/jpack.js
20
+ * use ./config/config.json
21
+ * 2. build custom config
22
+ * name (default to custom)
23
+ * default package config
24
+ * use ./config/jpack.js
25
+ * use ./config/config.json
26
+ * custom package config
27
+ * use [ABS_PATH_TO_CONFIG].json or json string
28
+ */
9
29
 
10
30
  export default async function jPackBuild({
11
- target = null,
31
+ action = null,
12
32
  name = null,
13
- zip = false,
33
+ config = null,
14
34
  debug = false
15
35
  } = {}) {
16
36
 
17
- LogMe.log('---');
18
-
19
37
  if (debug) {
20
38
  process.env.DEBUG = true;
21
39
  }
22
40
 
23
- LogMe.log('Build project...');
24
-
25
- if (!target || target === 'dist') {
26
- target = '';
27
- name = '';
28
- zip = false;
41
+ if (!action || action !== 'build') {
42
+ action = 'dist';
29
43
  }
30
44
 
31
- if (zip && !name) {
32
- name = 'zip';
45
+ if (config) {
46
+ action = 'build';
33
47
  }
34
48
 
35
- if (target && !name) {
36
- name = target;
37
- }
38
-
39
- if (!name) {
49
+ if (action === 'dist') {
40
50
  name = 'default';
51
+ config = null;
52
+ } else {
53
+ // Sanitize the build folder name
54
+ if (name) {
55
+ name = name.replace(/[^a-zA-Z0-9\-\_]/g, '');
56
+ name = name.toLowerCase();
57
+ }
58
+
59
+ if (!name) {
60
+ name = 'custom';
61
+ }
41
62
  }
42
63
 
43
- LogMe.log(' Target: ' + target);
44
- LogMe.log(' Name: ' + name);
45
- LogMe.log(' Zip: ' + (zip ? 'enabled' : 'disabled'));
46
- LogMe.log(' Debug: ' + (debug ? 'enabled' : 'disabled'));
64
+ LogMe.log('---');
65
+ LogMe.log('action: ' + action);
66
+ LogMe.log('name: ' + name);
67
+ LogMe.log('config: ' + (config ? 'yes' : 'no'));
68
+ LogMe.log('debug: ' + (debug ? 'enabled' : 'disabled'));
47
69
  LogMe.log('---');
48
70
 
49
- jPackConfig.set('buildZip', zip);
50
71
  jPackConfig.set('buildName', name);
72
+ jPackConfig.set('action', action);
73
+ jPackConfig.set('debug', debug);
51
74
 
52
- if (target) {
53
- jPackConfig.set('buildTarget', jPackConfig.get('basePath') + '/build/' + target);
54
- if (!fs.existsSync(jPackConfig.get('buildTarget'))) {
55
- fs.mkdirSync(jPackConfig.get('buildTarget'), { recursive: true });
56
- }
57
- } else {
58
- LogMe.log('Empty or create dist directory');
59
- const targetPath = path.join(jPackConfig.get('basePath'), 'dist');
60
- jPackConfig.set('buildTarget', targetPath);
61
- cleanBuildFolder(targetPath);
62
-
63
- const targetCfgPath = path.join(targetPath, 'config.json');
64
- if (!fs.existsSync(targetCfgPath)) {
65
- const defaultCfgPath = path.join(jPackConfig.get('basePath'), 'config', 'config.json');
66
- if (fs.existsSync(defaultCfgPath)) {
67
- LogMe.log('Copy default config.json file');
68
- fs.copyFileSync(defaultCfgPath, targetCfgPath);
69
- }
70
- }
71
- }
75
+ try {
76
+ LogMe.log('Load jPack config');
72
77
 
73
- const defaultCfgPath = path.join(jPackConfig.get('basePath'), 'config', 'config.json');
74
- const targetCfgPath = path.join(jPackConfig.get('buildTarget'), 'config.json');
75
- if (!fs.existsSync(targetCfgPath)) {
76
- if (fs.existsSync(defaultCfgPath)) {
77
- LogMe.log('Copy default config.json file');
78
- fs.copyFileSync(defaultCfgPath, targetCfgPath);
78
+ const jpack = path.join(jPackConfig.get('basePath'), 'config', 'jpack.js');
79
+ if (!fs.existsSync(jpack)) {
80
+ throw new Error('Default jPack config not found in ' + jpack);
79
81
  }
80
- }
81
-
82
- if (fs.existsSync(defaultCfgPath)) {
83
- LogMe.log('Load default config file');
84
- LogMe.log(defaultCfgPath);
85
- jPackConfig.loadFromJson(defaultCfgPath);
86
- }
87
82
 
88
- const cfgPath = checkTargetDirectory(jPackConfig.get('buildTarget'));
89
- if (fs.existsSync(cfgPath)) {
90
- LogMe.log(`Load client config file`);
91
- LogMe.log(cfgPath);
92
- jPackConfig.loadFromJson(cfgPath);
93
- }
83
+ require(jpack);
94
84
 
95
- try {
96
85
  jPackConfig.setPackageVersion();
97
- checkConfig();
98
- await doBuild();
99
86
  } catch (error) {
100
- LogMe.error(`Failed to load configuration file: ${cfgPath}`);
101
87
  LogMe.error(error.message);
102
88
  process.exit(1);
103
89
  }
104
- };
105
-
106
- async function doBuild() {
107
- LogMe.log('---');
108
- LogMe.dir(jPackConfig.all());
109
- LogMe.log('---');
110
90
 
111
- const inputOptions = {
112
- input: jPackConfig.get('buildJsFilePath'),
113
- plugins: jPackRollup(),
114
- };
91
+ if (config) {
92
+ LogMe.log('Load the build config');
93
+ try {
94
+ if (config.substr(0, 1) === '{') {
95
+ LogMe.log(' JSON string');
96
+ jPackConfig.sets(JSON.parse(config));
97
+ } else {
98
+ LogMe.log(' JSON file');
99
+ jPackConfig.sets(loadJson(config));
100
+ }
101
+ } catch (error) {
102
+ LogMe.error(' ' + error.message);
103
+ process.exit(1);
104
+ }
105
+ }
115
106
 
116
- const outputOptions = {
117
- file: jPackConfig.get('assetsPath') + '/js/' + jPackConfig.get('alias') + '.min.js',
118
- format: "iife",
119
- name: jPackConfig.get('name'),
120
- sourcemap: false,
121
- };
107
+ jPackConfig.validate();
122
108
 
123
109
  try {
124
- LogMe.log('Starting Rollup build...');
125
- const bundle = await rollup(inputOptions);
126
- await bundle.write(outputOptions);
127
- LogMe.log('Rollup build completed successfully.');
110
+ LogMe.log('Empty the target directory');
111
+ LogMe.log(' TargetPath: ' + jPackConfig.get('targetPath'));
112
+ emptyTargetPath(jPackConfig.get('targetPath'));
128
113
  } catch (error) {
129
- console.error('Error during Rollup build:', error);
114
+ LogMe.error(' ' + error.message);
130
115
  process.exit(1);
131
116
  }
132
- }
133
117
 
134
- function checkTargetDirectory(targetPath) {
135
- LogMe.log('checkTargetDirectory()');
118
+ LogMe.log('Launch build ...');
136
119
 
137
- if (!fs.existsSync(targetPath)) {
138
- LogMe.error(`Does not exist: ${targetPath}`);
139
- process.exit(1);
140
- }
120
+ try {
121
+ LogMe.log('---');
122
+ LogMe.dir(jPackConfig.all());
123
+ LogMe.log('---');
124
+
125
+ const inputOptions = {
126
+ input: jPackConfig.get('buildJsFilePath'),
127
+ plugins: jPackRollup(),
128
+ };
129
+
130
+ const outputOptions = {
131
+ file: jPackConfig.get('targetRelativePath') + '/js/' + jPackConfig.get('alias') + '.min.js',
132
+ format: "iife",
133
+ name: jPackConfig.get('name'),
134
+ sourcemap: false,
135
+ };
136
+
137
+ try {
138
+ LogMe.log('Starting Rollup build...');
139
+ const bundle = await rollup(inputOptions);
140
+ await bundle.write(outputOptions);
141
+ LogMe.log('Rollup build completed successfully.');
142
+ } catch (error) {
143
+ console.error('Error during Rollup build:', error);
144
+ process.exit(1);
145
+ }
141
146
 
142
- if (!fs.lstatSync(targetPath).isDirectory()) {
143
- LogMe.error(`Is not a directory: ${targetPath}`);
147
+ LogMe.log('---');
148
+ LogMe.log('Build completed successfully');
149
+ LogMe.log('---');
144
150
  process.exit(1);
145
- }
146
-
147
- const cfgPath = path.join(targetPath, 'config.json');
148
-
149
- if (!fs.existsSync(cfgPath)) {
150
- LogMe.warn(' config.json not found in target path');
151
- return null;
152
- }
153
-
154
- const files = fs.readdirSync(targetPath)
155
- .filter(file => file !== 'config.json');
156
-
157
- if (files.length > 0) {
158
- LogMe.error('Build target can only contain config.json');
151
+ } catch (error) {
152
+ LogMe.error(error.message);
159
153
  process.exit(1);
160
154
  }
161
-
162
- return cfgPath;
163
- }
164
-
165
- function checkConfig() {
166
- const basePath = jPackConfig.get('basePath');
167
-
168
- const buildName = jPackConfig.get('buildName')
169
- .replace(/[^a-zA-Z0-9]/g, ''); // Sanitize the build folder name
170
-
171
- jPackConfig.set('buildName', buildName);
172
-
173
- if (buildName === 'default') {
174
- jPackConfig.set('assetsPath', 'dist');
175
- jPackConfig.set('importPrefix', '../');
176
- }
177
- else {
178
- jPackConfig.set('assetsPath', 'build/' + buildName);
179
- jPackConfig.set('importPrefix', '../../');
180
- }
181
-
182
- jPackConfig.set('assetsFullpath', path.join(basePath, jPackConfig.get('assetsPath')));
183
- jPackConfig.set('buildJsFilePath', path.join(basePath, jPackConfig.get('assetsPath'), 'build.js'));
184
- jPackConfig.set('buildTemplatePath', path.join(basePath, 'config', 'jpack.template'));
185
- jPackConfig.set('wrapperPath', path.join(basePath, 'config', 'jpack.wrapper.js'));
186
-
187
- const onCheckConfig = jPackConfig.get('onCheckConfig');
188
- if (typeof onCheckConfig === 'function') {
189
- onCheckConfig();
190
- }
191
- }
155
+ };
package/lib/Cli.js CHANGED
@@ -3,17 +3,16 @@ import { hideBin } from 'yargs/helpers';
3
3
  import jPackBuild from "./Build.js";
4
4
  import jPackConfig from "./Config.js";
5
5
 
6
- const jPackCli = function (cfg) {
6
+ const jPackCli = function () {
7
7
  jPackConfig.set('basePath', process.cwd());
8
- jPackConfig.sets(cfg);
9
8
 
10
9
  const command = yargs(hideBin(process.argv))
11
10
  .usage('Usage: $0 <command> [options]')
12
- .option('target', {
13
- alias: 't',
11
+ .option('action', {
12
+ alias: 'a',
14
13
  type: 'string',
15
- description: 'Target path',
16
- default: '',
14
+ description: 'Set the build action (dist or build)',
15
+ default: 'dist',
17
16
  })
18
17
  .option('name', {
19
18
  alias: 'n',
@@ -21,11 +20,11 @@ const jPackCli = function (cfg) {
21
20
  description: 'Set the build name',
22
21
  default: '',
23
22
  })
24
- .option('zip', {
25
- alias: 'z',
26
- type: 'boolean',
27
- description: 'Create a zip file',
28
- default: false,
23
+ .option('config', {
24
+ alias: 'c',
25
+ type: 'string',
26
+ description: 'Custom config absolute path or json string',
27
+ default: '',
29
28
  })
30
29
  .option('debug', {
31
30
  alias: 'd',
package/lib/Config.js CHANGED
@@ -4,6 +4,10 @@ import path from 'path';
4
4
  const config = {};
5
5
 
6
6
  const jPackConfig = {
7
+ /**
8
+ * Returns a shallow copy of the current config object
9
+ * replacing functions with 'fn'.
10
+ */
7
11
  all: function () {
8
12
  const result = {};
9
13
  for (const key in config) {
@@ -17,54 +21,90 @@ const jPackConfig = {
17
21
  return result;
18
22
  },
19
23
 
20
- loadFromJson: function (cfgPath) {
21
- if (!fs.existsSync(cfgPath)) {
22
- throw new Error(`Configuration file not found: ${cfgPath}`);
23
- }
24
-
25
- const data = fs.readFileSync(cfgPath, 'utf8');
26
- const json = JSON.parse(data);
27
- this.sets(json);
28
- },
29
-
24
+ /**
25
+ * Loads the version from package.json and sets it in the config under 'version'.
26
+ */
30
27
  setPackageVersion: function () {
31
28
  const pkgPath = path.join(jPackConfig.get('basePath'), 'package.json');
29
+
32
30
  if (fs.existsSync(pkgPath)) {
33
31
  const data = fs.readFileSync(pkgPath, 'utf8');
34
32
  const json = JSON.parse(data);
33
+
35
34
  if (json.version) {
36
35
  this.set('version', json.version);
36
+ return;
37
37
  }
38
38
  }
39
+
40
+ this.set('version', '0.0.1');
39
41
  },
40
42
 
41
- check: function () {
43
+ /**
44
+ * Validates and prepares the config object, setting paths and defaults as needed.
45
+ * Throws if required fields are missing.
46
+ */
47
+ validate: function () {
42
48
  if (!config.basePath) {
43
49
  throw new Error('Invalid configuration: basePath is required.');
44
50
  }
45
51
 
46
- if (!config.name) {
47
- throw new Error('Invalid configuration: name is required.');
52
+ if (!config.buildName) {
53
+ throw new Error('Invalid configuration: buildName is required.');
54
+ }
55
+
56
+ if (config.action === 'dist') {
57
+ config.importPrefix = '../';
58
+ config.targetRelativePath = 'dist';
59
+ config.targetPath = path.join(config.basePath, 'dist');
60
+ }
61
+ else {
62
+ config.importPrefix = '../../';
63
+ config.targetPath = path.join(config.basePath, 'build', config.buildName);
64
+ config.targetRelativePath = 'build/' + config.buildName;
65
+ }
66
+
67
+ config.buildJsFilePath = path.join(config.targetPath, 'build.js');
68
+ config.buildTemplatePath = path.join(config.basePath, 'config', 'jpack.template');
69
+ config.wrapperPath = path.join(config.basePath, 'config', 'jpack.wrapper.js');
70
+
71
+ if (typeof config.onCheckConfig === 'function') {
72
+ config.onCheckConfig();
48
73
  }
49
74
 
50
75
  if (!config.alias) {
51
76
  config.alias = config.name.toLowerCase();
52
77
  config.alias = config.alias.replace(/\s+/g, '-');
53
78
  }
54
-
55
- if (!config.cfg) {
56
- config.cfg = config.alias;
57
- }
58
79
  },
59
80
 
81
+ /**
82
+ * Merges a new config object into the current config.
83
+ * @param {Object} newConfig - The config object to merge.
84
+ */
60
85
  sets: (newConfig) => {
61
- Object.assign(config, newConfig);
86
+ if (typeof newConfig !== 'object' || newConfig === null) {
87
+ throw new Error('Invalid configuration: newConfig must be an object.');
88
+ }
89
+ newConfig.array.forEach(element => {
90
+ this.set(element, newConfig[element]);
91
+ });
62
92
  },
63
93
 
94
+ /**
95
+ * Gets a config value by key, or returns the default if not set.
96
+ * @param {string} key - The config key.
97
+ * @param {*} def - The default value if key is not set.
98
+ */
64
99
  get(key, def) {
65
100
  return config[key] || def;
66
101
  },
67
102
 
103
+ /**
104
+ * Sets a config value by key.
105
+ * @param {string} key - The config key.
106
+ * @param {*} value - The value to set.
107
+ */
68
108
  set(key, value) {
69
109
  config[key] = value;
70
110
  }
package/lib/Rollup.js CHANGED
@@ -6,22 +6,18 @@ import json from "@rollup/plugin-json";
6
6
  import resolve from "@rollup/plugin-node-resolve";
7
7
  import commonjs from "@rollup/plugin-commonjs";
8
8
  import terser from '@rollup/plugin-terser';
9
- import { execSync } from 'child_process';
10
9
 
11
10
  import jPackConfig from "./Config.js";
12
11
  import LogMe from "./LogMe.js";
13
- import { cleanBuildFolder } from "./utils.js";
12
+ import { emptyTargetPath } from './utils.js';
14
13
 
15
14
  export default async function jPackRollup(config) {
16
- const assetsPath = jPackConfig.get('assetsPath');
17
-
18
15
  return [
19
16
  {
20
17
  name: 'beforeBuild',
21
18
  buildStart() {
22
- // target folder exists so empty
23
- // should not happen since it's required to have an empty target folder
24
- cleanBuildFolder(assetsPath);
19
+ LogMe.log('Prepare build folder');
20
+ emptyTargetPath(jPackConfig.get('targetPath'));
25
21
  },
26
22
  },
27
23
 
@@ -44,7 +40,7 @@ export default async function jPackRollup(config) {
44
40
  limit: 0,
45
41
  emitFiles: true,
46
42
  fileName: '[name][extname]',
47
- destDir: assetsPath + '/fonts/',
43
+ destDir: jPackConfig.get('targetRelativePath') + '/fonts/',
48
44
  }),
49
45
 
50
46
  url({
@@ -52,7 +48,7 @@ export default async function jPackRollup(config) {
52
48
  limit: 0,
53
49
  emitFiles: true,
54
50
  fileName: '[name][extname]',
55
- destDir: assetsPath + '/images/',
51
+ destDir: jPackConfig.get('targetRelativePath') + '/images/',
56
52
  }),
57
53
 
58
54
  json(), // Handle JSON imports
@@ -77,6 +73,9 @@ export default async function jPackRollup(config) {
77
73
  ];
78
74
  };
79
75
 
76
+ function cleanBuildFolder() {
77
+ }
78
+
80
79
  function generateBuildJs() {
81
80
  LogMe.log('Generate the build.js file ...');
82
81
 
@@ -154,13 +153,13 @@ function onPacked() {
154
153
 
155
154
  function moveCssFiles() {
156
155
  LogMe.log('Moving CSS files from js/ to css/ ...');
157
- const assetsPath = jPackConfig.get('assetsPath');
156
+ const targetPath = jPackConfig.get('targetPath');
158
157
 
159
- fs.readdirSync(assetsPath + '/js')
158
+ fs.readdirSync(targetRelativePath + '/js')
160
159
  .filter(file => file.endsWith('.css'))
161
160
  .forEach(file => {
162
- const oldPath = path.join(assetsPath + '/js', file);
163
- const newPath = path.join(assetsPath + '/css', file);
161
+ const oldPath = path.join(targetRelativePath + '/js', file);
162
+ const newPath = path.join(targetRelativePath + '/css', file);
164
163
  fs.mkdirSync(path.dirname(newPath), { recursive: true });
165
164
  fs.renameSync(oldPath, newPath);
166
165
  LogMe.log('- ' + file);
@@ -176,83 +175,13 @@ function cleanupBuild() {
176
175
  fs.unlinkSync(jPackConfig.get('buildJsFilePath'));
177
176
  }
178
177
 
179
- let emptyBuildFolder = false;
180
- const ignoreRemove = [];
181
-
182
- if (jPackConfig.get('buildZip')) {
183
- LogMe.log('Creating zip file ...');
184
- const zipFilePath = path.join(jPackConfig.get('assetsFullpath'), jPackConfig.get('buildName') + '.zip');
185
-
186
- execSync(`cd ${jPackConfig.get('assetsFullpath')} && zip -r ${zipFilePath} .`, { stdio: 'inherit' });
187
- LogMe.log('-> ' + zipFilePath);
188
-
189
- if (jPackConfig.get('buildTarget')) {
190
- LogMe.log('Transfer zip file ...');
191
- const zipTargetPath = path.join(jPackConfig.get('buildTarget'), jPackConfig.get('buildName') + '.zip');
192
- fs.copyFileSync(zipFilePath, zipTargetPath);
193
- LogMe.log('-> ' + zipTargetPath);
194
- }
195
-
196
- emptyBuildFolder = true;
197
- ignoreRemove.push(zipFilePath);
198
- }
199
- else if (jPackConfig.get('buildTarget') && jPackConfig.get('assetsPath') !== 'dist') {
200
- LogMe.log('Copy generated build folder ...');
201
-
202
- fs.mkdirSync(jPackConfig.get('buildTarget'), { recursive: true });
203
-
204
- // Iterate over the files and directories in jPackConfig.get('assetsPath')
205
- fs.readdirSync(jPackConfig.get('assetsPath')).forEach(file => {
206
- const sourcePath = path.join(jPackConfig.get('assetsPath'), file);
207
- const destinationPath = path.join(jPackConfig.get('buildTarget'), file);
208
-
209
- if (fs.lstatSync(sourcePath).isDirectory()) {
210
- // Recursively copy directories
211
- fs.mkdirSync(destinationPath, { recursive: true });
212
- fs.readdirSync(sourcePath).forEach(subFile => {
213
- const subSourcePath = path.join(sourcePath, subFile);
214
- const subDestinationPath = path.join(destinationPath, subFile);
215
- fs.copyFileSync(subSourcePath, subDestinationPath);
216
- LogMe.log('- Copied file: ' + subDestinationPath);
217
- });
218
- } else {
219
- // Copy files
220
- fs.copyFileSync(sourcePath, destinationPath);
221
- LogMe.log('- Copied file: ' + destinationPath);
178
+ fs.readdirSync(jPackConfig.get('targetPath')).forEach(file => {
179
+ const filePath = path.join(jPackConfig.get('targetPath'), file);
180
+ if (fs.lstatSync(filePath).isDirectory()) {
181
+ if (fs.readdirSync(filePath).length === 0) {
182
+ fs.rmdirSync(filePath);
183
+ LogMe.log('Removed empty folder: ' + filePath);
222
184
  }
223
- });
224
-
225
- emptyBuildFolder = true;
226
- }
227
-
228
- if (emptyBuildFolder) {
229
- LogMe.log('Cleaning up build folder ...');
230
-
231
- fs.readdirSync(jPackConfig.get('assetsPath')).forEach(file => {
232
- const filePath = path.join(jPackConfig.get('assetsPath'), file);
233
- if (fs.lstatSync(filePath).isDirectory()) {
234
- fs.rmSync(filePath, { recursive: true, force: true });
235
- LogMe.log('Removed folder: ' + filePath);
236
- }
237
- else {
238
- if (filePath.endsWith('.zip')) {
239
- return;
240
- }
241
-
242
- fs.unlinkSync(filePath);
243
- LogMe.log('Removed file: ' + filePath);
244
- }
245
- });
246
- }
247
- else {
248
- fs.readdirSync(jPackConfig.get('assetsPath')).forEach(file => {
249
- const filePath = path.join(jPackConfig.get('assetsPath'), file);
250
- if (fs.lstatSync(filePath).isDirectory()) {
251
- if (fs.readdirSync(filePath).length === 0) {
252
- fs.rmdirSync(filePath);
253
- LogMe.log('Removed empty folder: ' + filePath);
254
- }
255
- }
256
- });
257
- }
185
+ }
186
+ });
258
187
  }
package/lib/index.js CHANGED
@@ -3,14 +3,11 @@ import jPackCli from './Cli.js';
3
3
  import jPackConfig from './Config.js';
4
4
  import LogMe from './LogMe.js';
5
5
  import jPackRollup from './Rollup.js';
6
- import { removeEmptyDirs, cleanBuildFolder } from './utils.js';
7
6
 
8
7
  export {
9
8
  jPackBuild,
10
9
  jPackCli,
11
10
  jPackConfig,
12
11
  LogMe,
13
- jPackRollup,
14
- removeEmptyDirs,
15
- cleanBuildFolder
12
+ jPackRollup
16
13
  }
package/lib/utils.js CHANGED
@@ -1,43 +1,87 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
+
3
4
  import LogMe from './LogMe.js';
4
5
 
5
- export function removeEmptyDirs(dir) {
6
- if (!fs.existsSync(dir)) return;
6
+ export function emptyTargetPath(targetPath) {
7
+ if (!fs.existsSync(targetPath)) {
8
+ fs.mkdirSync(targetPath, { recursive: true });
9
+ }
10
+
11
+ if (!fs.lstatSync(targetPath).isDirectory()) {
12
+ throw new Error(`Target path is not a directory`);
13
+ }
14
+
15
+ let files = fs.readdirSync(targetPath);
7
16
 
8
- const files = fs.readdirSync(dir);
9
- for (const file of files) {
10
- const fullPath = path.join(dir, file);
11
- if (fs.lstatSync(fullPath).isDirectory()) {
12
- removeEmptyDirs(fullPath);
17
+ if (files.length > 0) {
18
+ for (const file of files) {
19
+ const fullPath = path.join(targetPath, file);
20
+ if (fs.lstatSync(fullPath).isDirectory()) {
21
+ try {
22
+ emptyTargetPath(fullPath);
23
+ } catch (error) {
24
+ LogMe.error('Failed to empty directory: ' + fullPath);
25
+ LogMe.error(error.message);
26
+ }
27
+ }
28
+ else {
29
+ fs.unlinkSync(fullPath);
30
+ LogMe.log(' [RM] ' + fullPath);
31
+ }
13
32
  }
33
+
34
+ files = fs.readdirSync(targetPath);
14
35
  }
15
36
 
16
- // After removing subdirs, check if current dir is empty
17
- if (fs.readdirSync(dir).length === 0) {
18
- fs.rmdirSync(dir);
37
+ if (files.length === 0) {
38
+ LogMe.log(' [RM] ' + targetPath);
39
+ fs.rmdirSync(targetPath);
19
40
  }
20
41
  };
21
42
 
22
- export function cleanBuildFolder(buildPath) {
23
- LogMe.log('cleanBuildFolder()');
24
-
25
- if (fs.existsSync(buildPath)) {
26
- LogMe.log(' Cleanup');
27
- fs.readdirSync(buildPath).forEach(file => {
28
- if (file !== 'config.json') {
29
- const filePath = path.join(buildPath, file);
30
- if (fs.lstatSync(filePath).isDirectory()) {
31
- fs.rmSync(filePath, { recursive: true, force: true });
32
- LogMe.log(' - [RM] ' + filePath);
33
- } else {
34
- fs.unlinkSync(filePath);
35
- LogMe.log(' - [RM] ' + filePath);
36
- }
37
- }
38
- });
39
- } else {
40
- fs.mkdirSync(buildPath, { recursive: true });
41
- LogMe.log(' Created target directory');
43
+ export function loadJson(filePath) {
44
+ try {
45
+ if (!fs.existsSync(filePath)) {
46
+ throw new Error('File not found');
47
+ }
48
+
49
+ const data = fs.readFileSync(filePath, 'utf8');
50
+ const json = JSON.parse(data);
51
+ return json;
52
+
53
+ } catch (error) {
54
+ throw new Error(`Failed to load JSON file: ${filePath}\n${error.message}`);
55
+ }
56
+ };
57
+
58
+ export function loadJsonConfigs(...configs) {
59
+ const loadedConfigs = [];
60
+ for (const configPath of configs) {
61
+ if (!fs.existsSync(configPath)) {
62
+ continue;
63
+ }
64
+ loadedConfigs.push(loadJson(configPath));
65
+ }
66
+ let mergedConfig = {};
67
+ for (const conf of loadedConfigs) {
68
+ mergedConfig = deepMerge(mergedConfig, conf);
69
+ }
70
+ return mergedConfig;
71
+ };
72
+
73
+ function isObject(item) {
74
+ return (item && typeof item === 'object' && !Array.isArray(item));
75
+ }
76
+
77
+ function deepMerge(target, source) {
78
+ for (const key in source) {
79
+ if (isObject(source[key])) {
80
+ if (!target[key]) Object.assign(target, { [key]: {} });
81
+ deepMerge(target[key], source[key]);
82
+ } else {
83
+ target[key] = source[key];
84
+ }
42
85
  }
43
- };
86
+ return target;
87
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jizy-packer",
3
- "version": "2.0.5",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "lib/*.js"