@nebula.js/cli-build 3.0.0-rc.2 → 3.0.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
@@ -19,7 +19,8 @@ Options:
19
19
  --version Show version number [boolean]
20
20
  --config, -c Path to JSON config file
21
21
  [string] [default: "nebula.config.js"]
22
- --watch, -w Watch source files [boolean] [default: false]
22
+ --watch, -w Watch source files
23
+ [choices: "umd", "systemjs"] [default: "umd"]
23
24
  --sourcemap, -m Generate source map [boolean] [default: true]
24
25
  --mode Explicitly set mode
25
26
  [string] [choices: "production", "development"]
@@ -142,6 +143,15 @@ In the package.json file, the main field makes sure that Node users using requir
142
143
  can be served the umd version. The module field is a common convention to designate
143
144
  how to import an esm version of your code.
144
145
 
146
+ ### SystemJS build
147
+
148
+ You can build a bundle using the SystemJS format by adding a `systemjs` field in the
149
+ package.json which specifies the output file from the build:
150
+
151
+ ```json
152
+ "systemjs": "dist/hello.systemjs.js"
153
+ ```
154
+
145
155
  ### Typescript
146
156
 
147
157
  With this option you can enable typescript bundling of your code. Add a `tsconfig.json`
package/lib/build.js CHANGED
@@ -45,12 +45,40 @@ const setupReactNative = (argv) => {
45
45
  return { reactNative, reactNativePath };
46
46
  };
47
47
 
48
+ const getBanner = ({ pkg }) => {
49
+ const { name, author, version, license } = pkg;
50
+ const auth = typeof author === 'object' ? `${author.name} <${author.email}>` : author || '';
51
+
52
+ return `/*
53
+ * ${name} v${version}
54
+ * Copyright (c) ${new Date().getFullYear()} ${auth}
55
+ * Released under the ${license} license.
56
+ */
57
+ `;
58
+ };
59
+
60
+ const getExternalDefault = ({ pkg }) => {
61
+ const peers = pkg.peerDependencies || {};
62
+ return Object.keys(peers);
63
+ };
64
+
65
+ const getOutputFileDefault = ({ pkg }) => pkg.main;
66
+
67
+ const getOutputNameDefault = ({ pkg }) => pkg.name.split('/').reverse()[0];
68
+
48
69
  const config = ({
49
70
  mode = 'production',
50
71
  format = 'umd',
51
72
  cwd = process.cwd(),
52
73
  argv = { sourcemap: true },
53
74
  core,
75
+ behaviours: {
76
+ getExternal = getExternalDefault,
77
+ getOutputFile = getOutputFileDefault,
78
+ getOutputName = getOutputNameDefault,
79
+ // Return false if no build should be done, otherwise true
80
+ enabled = () => true,
81
+ } = {},
54
82
  } = {}) => {
55
83
  const CWD = argv.cwd || cwd;
56
84
  const { reactNative, reactNativePath } = setupReactNative(argv);
@@ -58,8 +86,9 @@ const config = ({
58
86
  let pkg = require(path.resolve(CWD, 'package.json')); // eslint-disable-line
59
87
  const corePkg = core ? require(path.resolve(core, 'package.json')) : null; // eslint-disable-line
60
88
  pkg = reactNative ? require(path.resolve(reactNativePath, 'package.json')) : pkg; // eslint-disable-line
61
- const { name, version, license, author } = pkg;
62
89
  const { sourcemap, replacementStrings = {}, typescript } = argv;
90
+ const banner = getBanner({ pkg });
91
+ const outputName = getOutputName({ pkg, config: argv });
63
92
 
64
93
  if (reactNative) {
65
94
  dir = `${dir}/${reactNativePath}`;
@@ -68,14 +97,11 @@ const config = ({
68
97
  dir = core;
69
98
  }
70
99
 
71
- if (format === 'esm' && !pkg.module) {
100
+ if (!enabled({ pkg })) {
72
101
  return false;
73
102
  }
103
+ const outputFile = getOutputFile({ pkg, config: argv });
74
104
 
75
- const fileTarget = format === 'esm' ? pkg.module : pkg.main;
76
-
77
- const auth = typeof author === 'object' ? `${author.name} <${author.email}>` : author || '';
78
- const moduleName = name.split('/').reverse()[0];
79
105
  const extensions = ['.mjs', '.js', '.jsx', '.json', '.node'];
80
106
 
81
107
  let typescriptPlugin;
@@ -88,21 +114,11 @@ const config = ({
88
114
  }
89
115
  }
90
116
 
91
- const banner = `/*
92
- * ${name} v${version}
93
- * Copyright (c) ${new Date().getFullYear()} ${auth}
94
- * Released under the ${license} license.
95
- */
96
- `;
97
-
98
- const peers = pkg.peerDependencies || {};
99
- const external = Object.keys(peers);
100
-
117
+ const external = getExternal({ pkg, config: argv });
101
118
  // stardust should always be external
102
- if (!peers['@nebula.js/stardust']) {
119
+ if (external.indexOf('@nebula.js/stardust') === -1) {
103
120
  // eslint-disable-next-line no-console
104
121
  console.warn('@nebula.js/stardust should be specified as a peer dependency');
105
- } else if (external.indexOf('@nebula.js/stardust') === -1) {
106
122
  external.push('@nebula.js/stardust');
107
123
  }
108
124
 
@@ -158,8 +174,8 @@ const config = ({
158
174
  output: {
159
175
  banner,
160
176
  format,
161
- file: path.resolve(dir, fileTarget),
162
- name: moduleName,
177
+ file: path.resolve(dir, outputFile),
178
+ name: outputName,
163
179
  sourcemap,
164
180
  globals: {
165
181
  '@nebula.js/stardust': 'stardust',
@@ -168,7 +184,7 @@ const config = ({
168
184
  };
169
185
  };
170
186
 
171
- const minified = async (argv) => {
187
+ const umd = async (argv) => {
172
188
  const c = config({
173
189
  mode: argv.mode || 'production',
174
190
  format: 'umd',
@@ -184,9 +200,38 @@ const esm = async (argv, core) => {
184
200
  format: 'esm',
185
201
  argv,
186
202
  core,
203
+ behaviours: {
204
+ getOutputFile: ({ pkg }) => pkg.module,
205
+ enabled: ({ pkg }) => !!pkg.module,
206
+ },
207
+ });
208
+ if (!c) {
209
+ return undefined;
210
+ }
211
+ const bundle = await rollup.rollup(c.input);
212
+ return bundle.write(c.output);
213
+ };
214
+
215
+ const systemjsBehaviours = {
216
+ getExternal: ({ config: cfg }) => {
217
+ const defaultExternal = ['@nebula.js/stardust', 'picasso.js', 'picasso-plugin-q', 'react', 'react-dom'];
218
+ const { external } = cfg.systemjs || {};
219
+ return Array.isArray(external) ? external : defaultExternal;
220
+ },
221
+ getOutputFile: ({ pkg }) => pkg.systemjs,
222
+ getOutputName: () => undefined,
223
+ enabled: ({ pkg }) => !!pkg.systemjs,
224
+ };
225
+
226
+ const systemjs = async (argv) => {
227
+ const c = config({
228
+ mode: argv.mode || 'production',
229
+ format: 'systemjs',
230
+ argv,
231
+ behaviours: systemjsBehaviours,
187
232
  });
188
233
  if (!c) {
189
- return Promise.resolve();
234
+ return undefined;
190
235
  }
191
236
  const bundle = await rollup.rollup(c.input);
192
237
  return bundle.write(c.output);
@@ -205,12 +250,48 @@ function clearScreen(msg) {
205
250
  }
206
251
  }
207
252
 
208
- const watch = async (argv) => {
209
- const c = config({
253
+ const getPackage = (argv, cwd = process.cwd()) => require(path.resolve(argv.cwd || cwd, 'package.json')); // eslint-disable-line
254
+
255
+ const validateWatchInput = (argv) => {
256
+ if (argv.watch === 'systemjs') {
257
+ const pkg = getPackage(argv);
258
+ if (!pkg.systemjs) {
259
+ console.log(
260
+ `${chalk.white.bgRed(' ERROR ')} ${chalk.red(
261
+ 'No "systemjs" field specifying output file found in package.json'
262
+ )}`
263
+ );
264
+ return false;
265
+ }
266
+ }
267
+ return true;
268
+ };
269
+
270
+ const getWatchConfig = (argv) => {
271
+ const base = {
210
272
  mode: argv.mode || 'development',
211
- format: 'umd',
212
273
  argv,
213
- });
274
+ };
275
+
276
+ let opts;
277
+
278
+ switch (argv.watch) {
279
+ case 'systemjs':
280
+ opts = { ...base, format: 'systemjs', behaviours: systemjsBehaviours };
281
+ break;
282
+ case 'umd':
283
+ default:
284
+ opts = { ...base, format: 'umd' };
285
+ break;
286
+ }
287
+ return config(opts);
288
+ };
289
+
290
+ const watch = async (argv) => {
291
+ if (!validateWatchInput(argv)) {
292
+ return undefined;
293
+ }
294
+ const c = getWatchConfig(argv);
214
295
 
215
296
  let hasWarnings = false;
216
297
 
@@ -275,13 +356,17 @@ async function build(argv = {}) {
275
356
  if (buildConfig.watch) {
276
357
  return watch(buildConfig);
277
358
  }
278
- await minified(buildConfig);
359
+
360
+ await umd(buildConfig);
361
+ await esm(buildConfig);
362
+ await systemjs(buildConfig);
279
363
 
280
364
  if (argv.core) {
281
365
  const core = path.resolve(process.cwd(), argv.core);
282
366
  await esm(buildConfig, core);
283
367
  }
284
- return esm(buildConfig);
368
+
369
+ return undefined;
285
370
  }
286
371
 
287
372
  module.exports = build;
@@ -1,4 +1,4 @@
1
- /* eslint global-require: 0 */
1
+ /* eslint global-require: 0, no-param-reassign: 0 */
2
2
  const fs = require('fs');
3
3
 
4
4
  const defaultFilename = 'nebula.config.js';
@@ -13,9 +13,8 @@ const options = {
13
13
  },
14
14
  watch: {
15
15
  description: 'Rebuild the bundle when its source files change on disk',
16
- type: 'boolean',
17
16
  alias: 'w',
18
- default: false,
17
+ choices: ['umd', 'systemjs', true],
19
18
  },
20
19
  sourcemap: {
21
20
  description: 'Generate source maps',
@@ -40,22 +39,44 @@ const options = {
40
39
  },
41
40
  };
42
41
 
42
+ // nebula build --watch - watch umd bundle
43
+ // nebula build --watch umd - watch umd bundle
44
+ // nebula build --watch systemjs - watch systemjs bundle
45
+ // nebula build - watch disabled
46
+ const watchMiddleware = (argv) => {
47
+ let value = false;
48
+
49
+ if (argv.watch === true) {
50
+ value = 'umd';
51
+ } else if (typeof argv.watch === 'string') {
52
+ value = argv.watch;
53
+ }
54
+
55
+ argv.watch = value;
56
+ argv.w = value;
57
+
58
+ return argv;
59
+ };
60
+
43
61
  module.exports = (yargs) => {
44
62
  yargs.parserConfiguration({
45
63
  'dot-notation': false, // To avoid parsing "replacementStrings" with dot-notation into objects
46
64
  });
47
65
 
48
- return yargs.options(options).config('config', (configPath) => {
49
- if (configPath === null) {
50
- return {};
51
- }
52
- if (!fs.existsSync(configPath)) {
53
- if (RX.test(configPath)) {
54
- // do nothing if default filename doesn't exist
66
+ return yargs
67
+ .options(options)
68
+ .config('config', (configPath) => {
69
+ if (configPath === null) {
55
70
  return {};
56
71
  }
57
- throw new Error(`Config ${configPath} not found`);
58
- }
59
- return require(configPath).build || {};
60
- });
72
+ if (!fs.existsSync(configPath)) {
73
+ if (RX.test(configPath)) {
74
+ // do nothing if default filename doesn't exist
75
+ return {};
76
+ }
77
+ throw new Error(`Config ${configPath} not found`);
78
+ }
79
+ return require(configPath).build || {};
80
+ })
81
+ .middleware(watchMiddleware);
61
82
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nebula.js/cli-build",
3
- "version": "3.0.0-rc.2",
3
+ "version": "3.0.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "QlikTech International AB",
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@babel/cli": "7.18.10",
25
- "@babel/core": "7.18.10",
25
+ "@babel/core": "7.18.13",
26
26
  "@babel/plugin-transform-react-jsx": "7.18.10",
27
27
  "@babel/preset-env": "7.18.10",
28
28
  "@rollup/plugin-commonjs": "22.0.2",
@@ -32,7 +32,7 @@
32
32
  "chalk": "4.1.2",
33
33
  "extend": "3.0.2",
34
34
  "postcss": "^8.4.16",
35
- "rollup": "2.77.2",
35
+ "rollup": "2.79.0",
36
36
  "rollup-plugin-babel": "4.4.0",
37
37
  "rollup-plugin-postcss": "4.0.2",
38
38
  "rollup-plugin-sourcemaps": "0.6.3",
@@ -40,9 +40,9 @@
40
40
  "yargs": "17.5.1"
41
41
  },
42
42
  "devDependencies": {
43
- "@rollup/plugin-typescript": "8.3.4",
43
+ "@rollup/plugin-typescript": "8.4.0",
44
44
  "tslib": "*",
45
- "typescript": ">=4.7.4"
45
+ "typescript": ">=4.8.2"
46
46
  },
47
- "gitHead": "898b5acf0ecf16f2e988a9c01a06f681e0d5bf5e"
47
+ "gitHead": "50254faefff85fa3da57abfa1be1a0f71785ea30"
48
48
  }