@raisenow/tamaro-cli 1.0.5 → 1.0.9

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.
@@ -1,13 +1,15 @@
1
- import {basename, resolve} from 'path'
1
+ import {basename, relative, resolve} from 'path'
2
2
  import {existsSync, realpathSync} from 'fs'
3
3
  import chalk from 'chalk'
4
- import {notify as nodeNotify} from 'node-notifier'
4
+ import notifier from 'node-notifier'
5
5
  import {getIfUtils, IfUtils, IfUtilsFn} from 'webpack-config-utils'
6
6
  import columnify from 'columnify'
7
7
  import boxen from 'boxen'
8
- import dotenvExpand from 'dotenv-expand'
9
- import dotenv from 'dotenv'
8
+ import {expand as dotenvExpand} from 'dotenv-expand'
9
+ import {config as dotenvConfig} from 'dotenv'
10
+ import open from 'open'
10
11
  import stripIndent from 'strip-indent'
12
+ import {commandSync, ExecaSyncReturnValue, SyncOptions} from 'execa'
11
13
 
12
14
  ///////////////////////////////////////////////////////////////////////////////
13
15
 
@@ -21,11 +23,8 @@ export type EnvVars = {
21
23
  // Supported packages
22
24
  ///////////////////////////////////////////////////////////////////////////////
23
25
 
24
- const TAMARO_CORE_PACKAGE_NAMES = ['@raisenow/tamaro-core', 'demo-tamaro-core']
25
- const TAMARO_CONFIGURATIONS_PACKAGE_NAMES = [
26
- '@raisenow/tamaro-configurations',
27
- 'demo-tamaro-configurations',
28
- ]
26
+ const TAMARO_CORE_PACKAGE_NAMES = ['@raisenow/tamaro-core']
27
+ const TAMARO_CONFIGURATIONS_PACKAGE_NAMES = ['@raisenow/tamaro-configurations']
29
28
 
30
29
  ///////////////////////////////////////////////////////////////////////////////
31
30
 
@@ -51,9 +50,8 @@ export const getIfCoreFns = (): IfUtils => {
51
50
  }
52
51
  }
53
52
 
54
- console.error(
55
- chalk.red(
56
- stripIndent(`\
53
+ logError(
54
+ stripIndent(`\
57
55
  You must run "npx @raisenow/tamaro-cli" commands from:
58
56
  1. Root of "${chalk.bold(TAMARO_CORE_PACKAGE_NAMES[0])}" package folder.
59
57
  2. Root of particular customer configuration folder of "${chalk.bold(
@@ -61,9 +59,8 @@ export const getIfCoreFns = (): IfUtils => {
61
59
  )}" package.
62
60
  You are currently in "${chalk.bold(realpathSync(process.cwd()))}".
63
61
  `),
64
- ),
65
62
  )
66
- process.exit(0)
63
+ process.exit(1)
67
64
  }
68
65
 
69
66
  ///////////////////////////////////////////////////////////////////////////////
@@ -131,6 +128,24 @@ export const getPaths = (ifCore: IfUtilsFn) => {
131
128
  )
132
129
  }
133
130
 
131
+ ///////////////////////////////////////////////////////////////////////////////
132
+
133
+ type Paths = {
134
+ [key: string]: string | undefined
135
+ }
136
+
137
+ export const getRelativePaths = (paths: Paths): Paths => {
138
+ const relativePaths: Paths = {}
139
+
140
+ for (const [type, absPath] of Object.entries(paths)) {
141
+ if (absPath) {
142
+ relativePaths[type] = relative('./', absPath) || '.'
143
+ }
144
+ }
145
+
146
+ return relativePaths
147
+ }
148
+
134
149
  ///////////////////////////////////////////////////////////////////////////////
135
150
  // Env vars
136
151
  ///////////////////////////////////////////////////////////////////////////////
@@ -141,7 +156,7 @@ export const getEnvVars = (
141
156
  ifCore: IfUtilsFn,
142
157
  ifLocalCore: IfUtilsFn,
143
158
  ) => {
144
- dotenvExpand(dotenv.config({path: filePath}))
159
+ dotenvExpand(dotenvConfig({path: filePath}))
145
160
 
146
161
  process.env.NODE_ENV ??= ifMin('production', 'development')
147
162
  process.env.BABEL_ENV ??= ifMin('production', 'development')
@@ -170,7 +185,7 @@ export const getEnvVars = (
170
185
  process.env.WIDGET_UUID = getWidgetUuid()
171
186
 
172
187
  if (ifLocalCore()) {
173
- process.env.CORE_URL = `http://0.0.0.0:8080/index.js`
188
+ process.env.CORE_URL = `http://0.0.0.0:1234/index.js`
174
189
  } else {
175
190
  let version = process.env.CORE_VERSION
176
191
  version = version ? `@${version}` : ''
@@ -231,23 +246,77 @@ export const getEnvVars = (
231
246
  // Other
232
247
  ///////////////////////////////////////////////////////////////////////////////
233
248
 
234
- export const logCommand = (...args: any[]): void => {
235
- console.log(chalk.dim(...args))
249
+ export const delay = (ms: number) =>
250
+ new Promise((resolve) => setTimeout(resolve, ms))
251
+
252
+ ///////////////////////////////////////////////////////////////////////////////
253
+
254
+ export const logTitle = (title: string) => {
255
+ console.log(`\n${chalk.bold(title)}`)
256
+ }
257
+
258
+ ///////////////////////////////////////////////////////////////////////////////
259
+
260
+ export const logError = (message?: string) => {
261
+ if (message) {
262
+ console.log(chalk.red(message))
263
+ }
264
+ }
265
+
266
+ ///////////////////////////////////////////////////////////////////////////////
267
+
268
+ export const fail = (message?: string) => {
269
+ logError(message)
270
+ process.exit(1)
271
+ }
272
+
273
+ ///////////////////////////////////////////////////////////////////////////////
274
+
275
+ export const logCommand = (command: string): void => {
276
+ console.log(chalk.dim(stripIndent(command)))
277
+ }
278
+
279
+ ///////////////////////////////////////////////////////////////////////////////
280
+
281
+ export const prepareCommand = (command: string): string => {
282
+ return command
283
+ .replace(/\n/gm, ' ')
284
+ .replace(/[ \t]{2,}/gm, ' ')
285
+ .trim()
286
+ }
287
+
288
+ ///////////////////////////////////////////////////////////////////////////////
289
+
290
+ export const runCommandSync = (
291
+ command: string,
292
+ options?: SyncOptions,
293
+ ): ExecaSyncReturnValue => {
294
+ return commandSync(prepareCommand(command), options)
236
295
  }
237
296
 
238
297
  ///////////////////////////////////////////////////////////////////////////////
239
298
 
240
- // Log data into console as a table
241
299
  export const logDataTable = (
242
300
  vars: {[key: string]: string | undefined},
243
- title: string,
301
+ title?: string,
244
302
  ): void => {
245
- const boxTitle = chalk.bold(`${title}:\n`)
246
- const boxTable = columnify(vars, {showHeaders: false})
303
+ logTable(columnify(vars, {showHeaders: false}), title)
304
+ }
305
+
306
+ ///////////////////////////////////////////////////////////////////////////////
307
+
308
+ export const logTable = (text: string, title?: string): void => {
309
+ let out = ''
310
+ const boxTitle = title ? chalk.bold(`${title}`) : undefined
311
+
312
+ if (boxTitle) {
313
+ out += `${boxTitle}\n`
314
+ }
315
+
316
+ out += text
247
317
 
248
- // eslint-disable-next-line no-console
249
318
  console.log(
250
- boxen(`${boxTitle}\n${boxTable}`, {
319
+ boxen(out, {
251
320
  margin: 0,
252
321
  padding: {
253
322
  top: 0,
@@ -265,15 +334,23 @@ export const logDataTable = (
265
334
  export type NotifyArgs = {
266
335
  title: string
267
336
  message: string
337
+ target?: string
268
338
  }
269
339
 
270
340
  export const notify = (args: NotifyArgs): void => {
271
- const {title, message} = args
341
+ const {title, message, target} = args
272
342
 
273
- nodeNotify({
343
+ notifier.notify({
274
344
  title,
275
345
  message,
276
- contentImage: resolveOwn('src/assets/rnw-logo.png'),
346
+ contentImage: 'https://assets.raisenow.io/favicon.png',
277
347
  sound: 'Funk',
348
+ timeout: 30,
278
349
  })
350
+
351
+ if (target) {
352
+ notifier.on('click', () => {
353
+ open(target)
354
+ })
355
+ }
279
356
  }
@@ -1,4 +1,5 @@
1
1
  import {basename, dirname} from 'path'
2
+ import {existsSync} from 'fs'
2
3
  import glob from 'glob'
3
4
  import {getIfUtils, removeEmpty} from 'webpack-config-utils'
4
5
  import webpack, {
@@ -8,6 +9,7 @@ import webpack, {
8
9
  ProgressPlugin,
9
10
  RuleSetUseItem,
10
11
  } from 'webpack'
12
+ import {getPortPromise} from 'portfinder'
11
13
  import {TsconfigPathsPlugin} from 'tsconfig-paths-webpack-plugin'
12
14
  import {CleanWebpackPlugin} from 'clean-webpack-plugin'
13
15
  import HtmlWebpackPlugin from 'html-webpack-plugin'
@@ -26,8 +28,10 @@ import {
26
28
  getEnvVars,
27
29
  getIfCoreFns,
28
30
  getPaths,
31
+ getRelativePaths,
29
32
  logDataTable,
30
33
  moduleFileExtensions,
34
+ resolveApp,
31
35
  resolveOwn,
32
36
  } from 'lib/helpers'
33
37
 
@@ -47,8 +51,11 @@ const getWebpackConfig = async (env: any): Promise<Configuration> => {
47
51
  const appHtmlFiles = glob.sync(paths.appHtml)
48
52
  const envVars = getEnvVars(paths.appEnv, ifMin, ifCore, ifLocalCore)
49
53
  const {ifHmr} = getIfUtils({hmr: process.env.HMR_ENABLED === 'true'}, ['hmr'])
54
+ const port = await getPortPromise({port: 1234})
55
+ const useTailwind =
56
+ ifCore() && paths.appTailwindConfig && existsSync(paths.appTailwindConfig)
50
57
 
51
- logDataTable(paths, 'Paths')
58
+ logDataTable(getRelativePaths(paths), 'Paths')
52
59
  logDataTable(envVars.raw, 'Environment variables')
53
60
 
54
61
  const getCssLoaders = (cssOptions: any = {}): RuleSetUseItem[] => {
@@ -67,7 +74,6 @@ const getWebpackConfig = async (env: any): Promise<Configuration> => {
67
74
  options: {
68
75
  sourceMap: ifNotMin(),
69
76
  importLoaders: 3,
70
- esModule: false,
71
77
  ...cssOptions,
72
78
  },
73
79
  },
@@ -76,7 +82,15 @@ const getWebpackConfig = async (env: any): Promise<Configuration> => {
76
82
  options: {
77
83
  postcssOptions: {
78
84
  plugins: removeEmpty([
79
- ifCore([require.resolve('tailwindcss'), paths.appTailwindConfig]),
85
+ useTailwind
86
+ ? [
87
+ // eslint-disable-next-line node/no-missing-require
88
+ require.resolve('tailwindcss', {
89
+ paths: [paths.appNodeModules],
90
+ }),
91
+ paths.appTailwindConfig,
92
+ ]
93
+ : undefined,
80
94
  require.resolve('postcss-custom-properties'),
81
95
  require.resolve('autoprefixer'),
82
96
  ]),
@@ -114,7 +128,6 @@ const getWebpackConfig = async (env: any): Promise<Configuration> => {
114
128
  pathinfo: false,
115
129
  filename: ifCore('index.js', 'widget.js'),
116
130
  chunkFilename: ifMin('[name]-[contenthash:16].js', '[name].js'),
117
- // assetModuleFilename: ifMin('assets/[name]-[contenthash:16][ext]', 'assets/[name][ext]'),
118
131
  assetModuleFilename: 'assets/[name]-[contenthash:16][ext]',
119
132
  crossOriginLoading: 'anonymous',
120
133
  uniqueName: process.env.WEBPACK_UNIQUE_NAME,
@@ -142,151 +155,173 @@ const getWebpackConfig = async (env: any): Promise<Configuration> => {
142
155
  use: require.resolve('source-map-loader'),
143
156
  }),
144
157
 
145
- // Javascript and Typescript (Babel)
146
158
  {
147
- test: /\.(js|ts)x?$/,
148
- exclude: /node_modules/,
149
- loader: require.resolve('babel-loader'),
150
- options: {
151
- babelrc: false,
152
- configFile: false,
153
- sourceMaps: ifNotMin(),
154
- inputSourceMap: ifNotMin(),
155
- presets: removeEmpty([
156
- require.resolve('@babel/preset-env'),
157
- [
158
- require.resolve('@babel/preset-typescript'),
159
- {
160
- allowDeclareFields: true,
159
+ oneOf: [
160
+ // App Javascript and Typescript (Babel)
161
+ // and some dependencies distributed in a non-es5 formats
162
+ {
163
+ test: /\.(js|ts)x?$/,
164
+ include: ifCore(
165
+ [
166
+ resolveApp('src'),
167
+ resolveApp('node_modules/micromark'),
168
+ resolveApp('node_modules/decode-named-character-reference'),
169
+ ],
170
+ [resolveApp('.'), resolveApp('../../src')],
171
+ ),
172
+
173
+ loader: require.resolve('babel-loader'),
174
+ options: {
175
+ babelrc: false,
176
+ configFile: false,
177
+ sourceMaps: ifNotMin(),
178
+ inputSourceMap: ifNotMin(),
179
+ presets: [
180
+ require.resolve('@babel/preset-env'),
181
+ [
182
+ require.resolve('@babel/preset-typescript'),
183
+ {
184
+ allowDeclareFields: true,
185
+ },
186
+ ],
187
+ require.resolve('@babel/preset-react'),
188
+ ],
189
+ plugins: removeEmpty([
190
+ [
191
+ require.resolve('@babel/plugin-transform-runtime'),
192
+ {
193
+ corejs: {
194
+ version: 3,
195
+ proposals: true,
196
+ },
197
+ absoluteRuntime: dirname(
198
+ require.resolve('@babel/runtime-corejs3/package.json'),
199
+ ),
200
+ },
201
+ ],
202
+ [
203
+ require.resolve('@babel/plugin-proposal-decorators'),
204
+ {
205
+ legacy: true,
206
+ },
207
+ ],
208
+ require.resolve('@babel/plugin-syntax-dynamic-import'),
209
+ require.resolve('babel-plugin-lodash'),
210
+ ifHmr(require.resolve('react-refresh/babel')),
211
+ ]),
212
+ },
213
+ },
214
+
215
+ // Other Javascript (not in app) - no transformation
216
+ {
217
+ test: /\.(js|mjs)$/,
218
+ },
219
+
220
+ // Styles (not modules)
221
+ {
222
+ test: /\.s?css$/,
223
+ exclude: /\.module\.s?css$/,
224
+ use: getCssLoaders({
225
+ modules: false,
226
+ }),
227
+ },
228
+
229
+ // Styles (modules)
230
+ {
231
+ test: /\.module\.s?css$/,
232
+ use: getCssLoaders({
233
+ modules: {localIdentName: '[local]__[hash:base64]'},
234
+ }),
235
+ },
236
+
237
+ // SVG (in HTML and styles)
238
+ {
239
+ test: /\.svg$/,
240
+ issuer: [/\.html$/, /\.s?css$/],
241
+ type: 'asset',
242
+ parser: {
243
+ dataUrlCondition: {
244
+ maxSize: imageInlineSizeLimit,
161
245
  },
162
- ],
163
- require.resolve('@babel/preset-react'),
164
- ]),
165
- plugins: removeEmpty([
166
- [
167
- require.resolve('@babel/plugin-transform-runtime'),
246
+ },
247
+ },
248
+
249
+ // SVG (in components)
250
+ {
251
+ test: /\.svg$/,
252
+ issuer: [/\.(ts|tsx|js|jsx|md|mdx)$/],
253
+ use: [
168
254
  {
169
- corejs: {
170
- version: 3,
171
- proposals: true,
255
+ loader: require.resolve('@svgr/webpack'),
256
+ options: {
257
+ svgoConfig: {
258
+ plugins: [
259
+ {
260
+ removeHiddenElems: false,
261
+ moveGroupAttrsToElems: false,
262
+ collapseGroups: false,
263
+ },
264
+ ],
265
+ },
266
+ prettier: false,
267
+ titleProp: true,
268
+ ref: true,
172
269
  },
173
- absoluteRuntime: dirname(
174
- require.resolve('@babel/runtime-corejs3/package.json'),
175
- ),
176
270
  },
177
- ],
178
- [
179
- require.resolve('@babel/plugin-proposal-decorators'),
180
271
  {
181
- legacy: true,
272
+ loader: require.resolve('url-loader'),
273
+ options: {
274
+ name: 'assets/[name]-[contenthash:16].[ext]',
275
+ limit: imageInlineSizeLimit,
276
+ },
182
277
  },
183
278
  ],
184
- require.resolve('@babel/plugin-syntax-dynamic-import'),
185
- require.resolve('babel-plugin-lodash'),
186
- ifHmr(require.resolve('react-refresh/babel')),
187
- ]),
188
- },
189
- },
190
-
191
- // Styles (not modules)
192
- {
193
- test: /\.s?css$/,
194
- exclude: /\.module\.s?css$/,
195
- use: getCssLoaders({
196
- modules: false,
197
- }),
198
- },
199
-
200
- // Styles (modules)
201
- {
202
- test: /\.module\.s?css$/,
203
- use: getCssLoaders({
204
- modules: {localIdentName: '[local]__[hash:base64]'},
205
- }),
206
- },
207
-
208
- // SVG (in HTML)
209
- {
210
- test: /\.svg$/,
211
- issuer: /\.html$/,
212
- type: 'asset',
213
- parser: {
214
- dataUrlCondition: {
215
- maxSize: imageInlineSizeLimit,
216
279
  },
217
- },
218
- },
219
280
 
220
- // SVG (in components)
221
- {
222
- test: /\.svg$/,
223
- issuer: {
224
- not: [/\.html$/],
225
- },
226
- use: [
281
+ // Images and fonts
227
282
  {
228
- loader: require.resolve('@svgr/webpack'),
229
- options: {
230
- svgoConfig: {
231
- plugins: [
232
- {
233
- removeHiddenElems: false,
234
- moveGroupAttrsToElems: false,
235
- collapseGroups: false,
236
- },
237
- ],
283
+ test: /\.(png|jpe?g|webp|gif|ico|ttf|eot|woff2?)$/,
284
+ type: 'asset',
285
+ parser: {
286
+ dataUrlCondition: {
287
+ maxSize: imageInlineSizeLimit,
238
288
  },
239
289
  },
240
290
  },
291
+
292
+ // YML
241
293
  {
242
- loader: require.resolve('url-loader'),
294
+ test: /\.ya?ml$/,
295
+ use: [
296
+ {loader: require.resolve('json-loader')},
297
+ {loader: require.resolve('yaml-loader')},
298
+ ],
299
+ },
300
+
301
+ // HTML
302
+ {
303
+ test: /\.html$/,
304
+ loader: require.resolve('html-loader'),
243
305
  options: {
244
- // name: ifMin(
245
- // 'assets/[name]-[contenthash:16].[ext]',
246
- // 'assets/[name].[ext]'
247
- // ),
248
- name: 'assets/[name]-[contenthash:16].[ext]',
249
- limit: imageInlineSizeLimit,
306
+ minimize: false,
250
307
  },
251
308
  },
252
- ],
253
- },
254
309
 
255
- // Images and fonts
256
- {
257
- test: /\.(png|jpe?g|webp|gif|ico|ttf|eot|woff2?)$/,
258
- type: 'asset',
259
- parser: {
260
- dataUrlCondition: {
261
- maxSize: imageInlineSizeLimit,
310
+ // All other files - fallback
311
+ // This must be the latest rule!
312
+ {
313
+ exclude: [/^$/, /\.(js|jsx|ts|tsx|mjs)$/, /\.html$/, /\.json$/],
314
+ type: 'asset/resource',
262
315
  },
263
- },
264
- },
265
-
266
- // YML
267
- {
268
- test: /\.ya?ml$/,
269
- use: [
270
- {loader: require.resolve('json-loader')},
271
- {loader: require.resolve('yaml-loader')},
272
316
  ],
273
317
  },
274
-
275
- // HTML
276
- {
277
- test: /\.html$/,
278
- loader: require.resolve('html-loader'),
279
- options: {
280
- esModule: false,
281
- minimize: false,
282
- },
283
- },
284
318
  ]),
285
319
  },
286
320
 
287
321
  devtool: ifMin(false, 'cheap-module-source-map'),
288
322
 
289
323
  devServer: {
324
+ port,
290
325
  static: false,
291
326
  historyApiFallback: {
292
327
  disableDotRule: true,
Binary file
@@ -1,41 +0,0 @@
1
- import {commandSync} from 'execa'
2
- import {logCommand, notify, resolveOwn} from 'lib/helpers'
3
- import resolveBin from 'resolve-bin'
4
-
5
- ///////////////////////////////////////////////////////////////////////////////
6
-
7
- export type BuildOptions = {
8
- analyze?: boolean
9
- deploy?: boolean
10
- latest?: boolean
11
- tag?: string
12
- serve?: boolean
13
- }
14
-
15
- ///////////////////////////////////////////////////////////////////////////////
16
-
17
- const prepareBuildFlags = (options: BuildOptions): string => {
18
- const {analyze} = options
19
- let flags: string[] = []
20
-
21
- flags = analyze ? [...flags, '--env analyze'] : flags
22
-
23
- return flags.join(' ')
24
- }
25
-
26
- ///////////////////////////////////////////////////////////////////////////////
27
-
28
- export const build = async (options: BuildOptions): Promise<void> => {
29
- const flags = prepareBuildFlags(options)
30
-
31
- const wpBin = resolveBin.sync('webpack')
32
- const wpConfig = resolveOwn('dist/webpack.config.js')
33
- const cmd = `${wpBin} --config ${wpConfig} --env min ${flags}`
34
- logCommand(cmd)
35
- commandSync(cmd, {stdio: 'inherit'})
36
-
37
- notify({
38
- title: '"build" command',
39
- message: 'Process is done',
40
- })
41
- }
@@ -1,25 +0,0 @@
1
- import {commandSync} from 'execa'
2
- import {getIfCoreFns, getPaths, logCommand} from 'lib/helpers'
3
-
4
- ///////////////////////////////////////////////////////////////////////////////
5
-
6
- export type DeployOptions = {
7
- latest?: boolean
8
- tag?: string
9
- }
10
-
11
- ///////////////////////////////////////////////////////////////////////////////
12
-
13
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
14
- export const deploy = async (options: DeployOptions): Promise<void> => {
15
- // todo: ensure build exists
16
- // todo: handle "tag" and "latest" options
17
- // todo: implement
18
- const {ifCore} = getIfCoreFns()
19
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
20
- const paths = getPaths(ifCore)
21
-
22
- const cmd = `echo Deploying to AWS is not implemented yet`
23
- logCommand(cmd)
24
- commandSync(cmd, {stdio: 'inherit'})
25
- }