@polylith/builder 0.0.28 → 0.0.30

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/App.js CHANGED
@@ -13,6 +13,7 @@ import features from './plugin-features.js';
13
13
  import styles from "rollup-plugin-styles";
14
14
 
15
15
  import ConfigFeature from './ConfigFeature.js';
16
+ import Files from './Files.js';
16
17
 
17
18
  /**
18
19
  * call this function to check if the given file exists
@@ -39,11 +40,11 @@ export default class App {
39
40
  *
40
41
  * @param {String} name a name for the app
41
42
  * @param {String} root the root directory of the project. All other
42
- * paths will be relative to this path.
43
+ * paths will be relative to this path.
43
44
  * @param {String} index the path to the main source file for the app. all
44
- * source paths will be assumed to be relative to this path.
45
+ * source paths will be assumed to be relative to this path.
45
46
  * @param {String} dest the path to the destination folder for the
46
- * rolled up files
47
+ * rolled up files
47
48
  */
48
49
 
49
50
  constructor(name, root, index , dest) {
@@ -52,17 +53,19 @@ export default class App {
52
53
 
53
54
  var filename = path.posix.join(root, index);
54
55
  this.sourcePath = path.posix.dirname(filename);
55
- this.destination = path.posix.join(root, dest);
56
+ this.destPath = path.posix.join(root, dest);
56
57
 
57
58
  this.name = name;
58
59
  this.index = index;
59
60
  this.fullIndexPath = path.posix.join(root, index);
60
61
 
61
62
  this.loadables = [];
63
+ this.features = [];
62
64
  this.featureIndexes = [];
63
65
  this.configs = {};
64
66
  this.manualChunkType = 'function';
65
67
  this.manualChunks = [];
68
+ this.files = new Files(sourcePath, destination)
66
69
  }
67
70
 
68
71
  static fileToPath(filename) {
@@ -109,13 +112,53 @@ export default class App {
109
112
  this.configs[root] = config;
110
113
  }
111
114
 
112
- // default implementation, applications will implement this to specify the loadable features to be used
113
- async getFeatures() {
114
- return [];
115
+ /**
116
+ * Call this method to add a list of resources that will be moved to the
117
+ * destination path when the application is built. This will either be a
118
+ * feature root, or the source path
119
+ *
120
+ * @param {Array<import('./Files.js').CopySpec} resourceSpecs the copy specs
121
+ * for all the resources being added.
122
+ * @param {String} root the path to the origin of the caller. Paths in
123
+ * the spec are assumed to be relative to this.
124
+ */
125
+ addResources(resourceSpecs, root) {
126
+ resourceSpecs.forEach(function(spec) {
127
+ this.files.addCopySpec(root, spec);
128
+ }, this)
115
129
  }
116
130
 
117
- addFeatureMain(main) {
118
- this.featureIndexes.push(main);
131
+ /**
132
+ * Call this method to add a feature to the application. This method is
133
+ * given a path to the root of the feature. At build time the builder will
134
+ * look directory for a file named build.js and if found import it and
135
+ * call the default function passing it a pointner to this object.
136
+ *
137
+ * If there is no build.js file the builder will look for a build.json file.
138
+ * If present that json will be loaded and used to build the feature.
139
+ *
140
+ * If that is not found it will look for an index.js file. and if found it
141
+ * will add that to the list on feature index files which will be
142
+ * automatically imported when the built code imports the @polylith/features
143
+ * module
144
+ *
145
+ * @param {String} feature the relative path from the application source
146
+ * directory to the feature root.
147
+ */
148
+ addFeature(feature) {
149
+ this.features.push(feature);
150
+ }
151
+
152
+ /**
153
+ * Call this method to add a feature index file to the application. These
154
+ * features will be imported when the application imports
155
+ * "@polylith/features"
156
+ *
157
+ * @param {String} index the relative path to the feature index file from
158
+ * the application source folder.
159
+ */
160
+ addFeatureIndex(index) {
161
+ this.featureIndexes.push(index);
119
162
  }
120
163
 
121
164
  /**
@@ -157,7 +200,7 @@ export default class App {
157
200
  * default.
158
201
  *
159
202
  * @param {String} id this is the filename of the current file being
160
- * processed by rollup
203
+ * processed by rollup
161
204
  *
162
205
  * @returns {String} the chunk name if there is a match
163
206
  */
@@ -172,9 +215,9 @@ export default class App {
172
215
  * array.
173
216
  *
174
217
  * @param {String} id this is the filename of the current file being
175
- * processed by rollup
218
+ * processed by rollup
176
219
  * @returns {String} the name fo the chunk if there is a matching chunk
177
- * name specifier
220
+ * name specifier
178
221
  */
179
222
  handleManualChunksArray(id) {
180
223
  var fixId = App.fixPath(id);
@@ -191,7 +234,7 @@ export default class App {
191
234
  * added.
192
235
  *
193
236
  * @param {String} id this is the filename of the current file being
194
- * processed by rollup
237
+ * processed by rollup
195
238
  * @returns the chunk name if any of the callbacks return one
196
239
  */
197
240
  handleManualChunksCallbacks(id) {
@@ -224,7 +267,7 @@ export default class App {
224
267
  * pieces of code that are not a direct dependency of the main application.
225
268
  *
226
269
  * @param {String} root path relative to the source directory for the
227
- * feature to load.
270
+ * feature to load.
228
271
  */
229
272
  async loadFeature(root) {
230
273
  var featurePath = path.posix.join(this.sourcePath, root);
@@ -252,7 +295,7 @@ export default class App {
252
295
  try {
253
296
  let content = JSON.parse(await readFile(jsonPath));
254
297
 
255
- let builder = new ConfigFeature(content, featurePath);
298
+ let builder = new ConfigFeature(content, root);
256
299
  await builder.build(this)
257
300
  } catch (e) {
258
301
  console.error(e);
@@ -264,7 +307,7 @@ export default class App {
264
307
  }
265
308
 
266
309
  async buildFeatures() {
267
- var features = await this.getFeatures();
310
+ var features = this.features;
268
311
 
269
312
  for (let feature of features) {
270
313
  await(this.loadFeature(feature));
@@ -274,12 +317,13 @@ export default class App {
274
317
  /**
275
318
  *
276
319
  * @param {String} name unique name of the loadable that will be passed to
277
- * the load method
320
+ * the load method
278
321
  * @param {String} main the relative path from the source folder to the entry
279
- * point of the loadable.
322
+ * point of the loadable.
280
323
  * @param {String} [prefix] if given, the prefix on services created in
281
- * this loadable. When the loadable has been loaded, the start and ready
282
- * methods will be called on all services starting with this prefix.
324
+ * this loadable. When the loadable has been loaded, the start and
325
+ * ready methods will be called on all services starting with this
326
+ * prefix.
283
327
  */
284
328
  addLoadable(name, main, prefix) {
285
329
  var dest = path.posix.join(this.sourcePath, main);
@@ -287,7 +331,8 @@ export default class App {
287
331
  }
288
332
 
289
333
  /**
290
- * build calls this method to create the rollup configuration object
334
+ * The build method calls this method to create the rollup configuration
335
+ * object
291
336
  *
292
337
  * @returns {Object} rollup configuration object
293
338
  */
@@ -315,6 +360,7 @@ export default class App {
315
360
  commonjs(),
316
361
  babel({
317
362
  presets: ['@babel/preset-react'],
363
+ babelHelpers: 'bundled',
318
364
  }),
319
365
  loader(this.loadables),
320
366
  features(this.featureIndexes),
@@ -333,7 +379,7 @@ export default class App {
333
379
  output : {
334
380
  output : {
335
381
  sourcemap: true,
336
- dir : this.destination,
382
+ dir : this.destPath,
337
383
  format: 'es',
338
384
  assetFileNames: function(chunkInfo) {
339
385
  return '[name]-[hash][extname]';
@@ -358,6 +404,7 @@ export default class App {
358
404
  watch: {
359
405
  buildDelay: 250,
360
406
  exclude: 'node_modules/**',
407
+ clearScreen: true,
361
408
  }
362
409
  }
363
410
  };
@@ -377,17 +424,31 @@ export default class App {
377
424
 
378
425
  watch() {
379
426
  var watchConfig = {
380
- input: this.config.input,
381
- output: this.config.output,
382
- watch: this.config.watch,
427
+ ...this.config.input,
428
+ ...this.config.output,
429
+ ...this.config.watch,
383
430
  }
384
431
 
385
432
  const watcher = rollup.watch(watchConfig);
433
+ watcher.on('event', function(event) {
434
+ console.log(event.code);
435
+ if (event.result) {
436
+ event.result.close();
437
+ }
386
438
 
387
- watcher.on('event', function({result}) {
388
- if (result) {
389
- result.close();
390
- }
439
+ if (event.code === 'ERROR') {
440
+ console.error(event.error)
441
+ }
442
+
443
+ if (event.code === 'BUNDLE_START') {
444
+ process.stdout.write("\u001b[2J\u001b[0;0H");
445
+ console.log(event);
446
+ }
447
+
448
+ if (event.code === 'BUNDLE_END') {
449
+ process.stdout.write("\u001b[2J\u001b[0;0H");
450
+ console.log(event);
451
+ }
391
452
  }.bind(this));
392
453
  }
393
454
  }
package/ConfigApp.js CHANGED
@@ -2,25 +2,32 @@ import App from './App';
2
2
  import path from 'node:path/posix';
3
3
 
4
4
  export default class ConfigApp extends App {
5
- constructor (config, root) {
6
- App.fixPath(root);
7
- var name = config.name || 'unnamed';
8
- var index = config.main || path.join(root, 'src', 'index.js');
9
- var dest = config.dest || path.join(root, 'dist');
5
+ constructor (config, root) {
6
+ App.fixPath(root);
7
+ var name = config.name || 'unnamed';
8
+ var index = config.index || path.join(root, 'src', 'index.js');
9
+ var dest = config.dest || path.join(root, 'dist');
10
10
 
11
- super(name, root, index, dest);
12
- this.config = config;
11
+ super(name, root, index, dest);
12
+ this.config = config;
13
13
 
14
- if (!index.template || !index.template.source) throw new Error('html source not defined in config file');
15
- var source = index.template.source;
16
- var sourceFilename = path.basename(source);
17
- var destination = index.template.destination || path.join(dest, sourceFilename)
18
- this.setHtmlTemplate(source, destination);
14
+ if (!index.template || !index.template.source) throw new Error('html source not defined in config file');
15
+ var source = index.template.source;
16
+ var sourceFilename = path.basename(source);
17
+ var destination = index.template.destination || path.join(dest, sourceFilename)
18
+ this.setHtmlTemplate(source, destination);
19
19
 
20
- if (config.manualChunks) this.addManualChunks(config.manualChunks);
21
- }
20
+ if (config.manualChunks) this.addManualChunks(config.manualChunks);
21
+ if (this.config.features) {
22
+ this.config.features.forEach(function(feature) {
23
+ this.addFeature(feature);
24
+ }.bind(this))
25
+ }
22
26
 
23
- async getFeatures() {
24
- return this.config.features || [];
25
- }
27
+ if (config.resources) ;
28
+ }
29
+
30
+ async getFeatures() {
31
+ return this.config.features || [];
32
+ }
26
33
  }
package/ConfigFeature.js CHANGED
@@ -1,23 +1,34 @@
1
1
  import Feature from './Feature.js';
2
2
 
3
3
  export default class ConfigFeature extends Feature {
4
- constructor (config, root) {
5
- super();
6
- this.config = config;
7
- this.root = root;
8
- }
4
+ /**
5
+ * Constrctor for the ConfigFeature class
6
+ *
7
+ * @param {Object} config the contents of the config file
8
+ * @param {String} root the relative path of the feature from the app source directory
9
+ */
10
+ constructor (config, root) {
11
+ super(root);
12
+ this.config = config;
13
+ }
9
14
 
10
- async build(app) {
11
- var config = this.config;
15
+ /**
16
+ * The application calls the method to build the feature.
17
+ * @param {App} app the application for th
18
+ */
19
+ async build(app) {
20
+ var config = this.config;
12
21
 
13
- if (config.loadables && Array.isArray(config.loadables)) {
14
- config.loadables.forEach(function(loadable) {
15
- if (loadable.name && loadable.main) {
16
- app.addLoadable(loadable.name, loadable.main, loadable.prefix);
17
- }
18
- }, this);
19
- }
20
- if (config.main) app.addFeatureMain(config.main);
21
- if (config.config) app.addConfig(config.config, this.root);
22
- }
22
+ if (config.loadables && Array.isArray(config.loadables)) {
23
+ config.loadables.forEach(function(loadable) {
24
+ if (loadable.name && loadable.index) {
25
+ app.addLoadable(loadable.name, loadable.index, loadable.prefix);
26
+ }
27
+ }, this);
28
+ }
29
+
30
+ if (config.index) app.addFeatureIndex(config.index);
31
+ if (config.config) app.addConfig(config.config, this.root);
32
+ if (config.resources && Array.isArray(config.resources)) app.addResources(config.resources, this.root);
33
+ }
23
34
  }
package/Feature.js CHANGED
@@ -1,8 +1,9 @@
1
1
  export default class Feature {
2
- constructor () {
3
- }
2
+ constructor (root) {
3
+ this.root = root;
4
+ }
4
5
 
5
- async build(app) {
6
- this.app = app;
7
- }
6
+ async build(app) {
7
+ this.app = app;
8
+ }
8
9
  }
package/Files.js ADDED
@@ -0,0 +1,156 @@
1
+ import fg from 'fast-glob';
2
+ import path from 'node:path/posix'
3
+ import {ensureDir} from 'fs-extra';
4
+
5
+ /**
6
+ * @typedef {Object} CopySpec
7
+ * @property {String} dest the relative path of the copy destination from the
8
+ * application's destination path.
9
+ * @property {String} cwd the relative path from the spec root to search for
10
+ * files
11
+ * @property {String} glob the search expression for the files to copy, in glob
12
+ * format
13
+ * @property {Boolean} [keepNest] if true then the nesting of the found file
14
+ * relative to the cwd property will be retained when the file is copied.
15
+ * Defaults to false
16
+ */
17
+
18
+ /**
19
+ * @typedef {Object} FileSpec
20
+ * @property {String} name the full path to the file being copied
21
+ * @property {String} searchRoot the absolute path to where the search started
22
+ * @property {CopySpec} spec the specifier for how to find and copy files
23
+ */
24
+
25
+ /**
26
+ * create an instance of this class to specify and and copy files from source
27
+ * to destination.
28
+ */
29
+ export default class Files {
30
+ /**
31
+ * Constructor for the Files class
32
+ *
33
+ * @param {String} dest the absolute filepath to the application's
34
+ * destination directory
35
+ * @param {String} src the abolute path to the applications source
36
+ * directory
37
+ */
38
+ constructor(dest, src) {
39
+ this.dest = dest;
40
+ this.src = src;
41
+ this.files = {};
42
+ this.specs = [];
43
+ }
44
+
45
+ /**
46
+ * Call this method to add a copy specifier for resources to be copied. This
47
+ * will be called from either the application or from a feature build
48
+ * configuration or js file
49
+ *
50
+ * @param {String} root the originating path of the specifier. This is a
51
+ * relative path from the project src path. This is probably the location
52
+ * of the feature, or empty for the src path itself.
53
+ * @param {CopySpec} spec the specification for how to find and copy files
54
+ */
55
+ addCopySpec(root, spec) {
56
+ spec.root = root;
57
+ this.specs.push(spec);
58
+ }
59
+
60
+ /**
61
+ * Call this method once per spec to add a list of files to the complete
62
+ * list of all the files to be copied. If multiple files are found through
63
+ * different specs then the spec with the longest search root will take
64
+ * presidence, since it is the spec with the greatest specificity
65
+ *
66
+ * @param {Array<String>} files absolute filepaths of files that have been found
67
+ * @param {String} searchRoot the absolute path of the spec root
68
+ * @param {CopySpec} spec the spec that was used to find these files.
69
+ */
70
+ addFiles(searchRoot, files, spec) {
71
+ // the rule here is that files that are found by multiple specs will be
72
+ // controlled according to the spec with the deepest nested search path.
73
+ // Since file paths here are absolute tthis will always be based on the
74
+ // string length.
75
+ files.forEach(function(file) {
76
+ // reconcile conflicts
77
+ if (this.files[file]) {
78
+ copyInfo = this.files[file];
79
+ if (copyInfo.searchRoot.length > searchRoot.length) return;
80
+ }
81
+
82
+ this.files[file] = {
83
+ name: file,
84
+ searchRoot: searchRoot,
85
+ spec: spec,
86
+ }
87
+ }, this)
88
+ }
89
+
90
+ /**
91
+ * Call this method to locate all the files to be found from all the copy
92
+ * specs that have been added
93
+ *
94
+ * @returns {Promise<Array<FileSpec>>} the list of all files. This is also
95
+ * stored in the object variable this.files
96
+ */
97
+ async findAllFiles() {
98
+ // using a for loop here because we are making async calls
99
+ for (let idx = 0; idx < this.specs.length; idx++) {
100
+ let spec = this.specs[idx];
101
+ let searchRoot = path.join(this.src, spec.root, spec.cwd);
102
+ let options = {
103
+ cwd: searchRoot,
104
+ ignore: ['**/node_modules'],
105
+ absolute: true,
106
+ onlyFiles: true,
107
+ unique: true,
108
+ dot: true,
109
+ }
110
+ let fullGlob = path.join(searchPath, spec.glob);
111
+ let files = await fg(fullGlob, options);
112
+
113
+ this.addFiles(searchRoot, files, spec);
114
+ }
115
+
116
+ return this.files
117
+ }
118
+
119
+ /**
120
+ * Call this method to copy all the files that have been specified through
121
+ * addCopySpec
122
+ */
123
+ async copyFiles() {
124
+ await this.findAllFiles();
125
+
126
+ var filenames = Object.keys(this.files);
127
+
128
+ // using a for loop because we are making async calls
129
+ for (let idx = 0 ; idx < filenames.length; idx++) {
130
+ let srcFilename = filenames[idx];
131
+ let spec = this.files[srcFilename].spec;
132
+ let relativePath = this.srcFilename.slice(this.files[srcFilename].searchRoot.length);
133
+ let destFilename = '';
134
+
135
+ if (spec.keepNest) {
136
+ destFilename = path.join(this.dest, spec.dest, relativePath);
137
+ } else {
138
+ destFilename = path.join(this.dest, spec.dest, path.basename(srcFilename));
139
+ }
140
+
141
+ // we will override existing destination files. This could have
142
+ // unintended consequences
143
+ try {
144
+ console.log(`copying ${srcFilename} to ${destFilename}`);
145
+ /*
146
+ await ensureDir(path.dirname(destinationFilePath));
147
+ await fs.copyFiles(srcFilename, destFilename);
148
+ */
149
+ } catch (e) {
150
+ console.error(`Error copying file ${srcFilename} to ${destFilename}`);
151
+ throw e;
152
+ }
153
+ }
154
+ }
155
+
156
+ }
package/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import App from './App.js'
2
2
  import Feature from './Feature.js';
3
+ import ConfigApp from './ConfigApp.js';
4
+ import ConfigFeature from './ConfigFeature.js';
3
5
 
4
- export {App as App, Feature as Feature};
6
+ export {App, Feature, ConfigApp, ConfigFeature};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polylith/builder",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
4
4
  "description": "The polylith builder",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -17,6 +17,7 @@
17
17
  "@rollup/plugin-node-resolve": "^13.0.5",
18
18
  "babel": "^6.23.0",
19
19
  "escape-string-regexp": "^5.0.0",
20
+ "fast-glob": "^3.2.12",
20
21
  "fs-extra": "^10.0.0",
21
22
  "less": "^4.1.2",
22
23
  "rollup": "^2.58.0",
@@ -0,0 +1,22 @@
1
+ /**
2
+ *
3
+ * @param {Files} files the files object that specifies the resource files to
4
+ * copy
5
+ * @returns {Object} the plugin
6
+ */
7
+ export default function(files) {
8
+ return {
9
+ name: "main-html-template",
10
+
11
+ async generateBundle(outputOptions, bundleInfo) {
12
+ return new Promise(async function (resolve, reject) {
13
+ try {
14
+ await files.copyFiles();
15
+ resolve(true)
16
+ } catch (e) {
17
+ reject(e)
18
+ }
19
+ })
20
+ }
21
+ }
22
+ }
@@ -1,9 +1,9 @@
1
1
  function makeSource(features) {
2
2
 
3
- var importStatements = '';
3
+ var importStatements = '';
4
4
  features.forEach(function(feature) {
5
- importStatements += `import '${feature}'\n`;
6
- })
5
+ importStatements += `import '${feature}'\n`;
6
+ })
7
7
 
8
8
  var source = `${importStatements}`
9
9
 
@@ -13,7 +13,7 @@ function makeSource(features) {
13
13
 
14
14
  export default function features(features) {
15
15
  return {
16
- name: 'features',
16
+ name: 'features',
17
17
 
18
18
  resolveId (source, _, third) {
19
19
  if (source === '@polylith/features') {
@@ -30,4 +30,3 @@ export default function features(features) {
30
30
  }
31
31
  };
32
32
  }
33
-
@@ -15,7 +15,7 @@ const INVALID_ARGS_ERROR =
15
15
  function createScriptTags(scripts) {
16
16
  var tags = '';
17
17
  scripts.forEach(function(script) {
18
- var oneTag = `<script type="module" src="${script}"></script>`;
18
+ var oneTag = `<script type="module" src="${script}"></script>\n`;
19
19
  tags += oneTag;
20
20
  });
21
21
 
@@ -24,7 +24,7 @@ function createScriptTags(scripts) {
24
24
 
25
25
  export default function(options = {}) {
26
26
  var { root, source, destination, replaceVars } = options;
27
-
27
+
28
28
  return {
29
29
  name: "main-html-template",
30
30
 
@@ -34,7 +34,7 @@ export default function(options = {}) {
34
34
  var includes = [];
35
35
  var names = Object.keys(bundleInfo);
36
36
  var scripts;
37
-
37
+
38
38
  if (!destination && !source) throw new Error(INVALID_ARGS_ERROR);
39
39
 
40
40
  names.forEach(function(name) {
@@ -73,5 +73,3 @@ export default function(options = {}) {
73
73
  },
74
74
  };
75
75
  }
76
-
77
-