zmp-cli 3.12.0 → 3.13.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.
@@ -1,21 +1,18 @@
1
1
  {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
- "version": "0.2.0",
6
- "configurations": [
7
- {
8
- "type": "pwa-node",
9
- "request": "launch",
10
- "name": "Launch Program",
11
- "skipFiles": [
12
- "<node_internals>/**"
13
- ],
14
- "program": "${workspaceFolder}/index.js",
15
- "args": [
16
- "init"
17
- ],
18
- "console": "integratedTerminal"
19
- }
20
- ]
21
- }
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "type": "pwa-node",
9
+ "request": "launch",
10
+ "name": "Launch Program",
11
+ "skipFiles": ["<node_internals>/**"],
12
+ "program": "${workspaceFolder}/index.js",
13
+ "args": ["sync-config", "--root-element", "#__next", "out/index.html"],
14
+ "cwd": "${workspaceFolder}/../next-mini-app/",
15
+ "console": "integratedTerminal"
16
+ }
17
+ ]
18
+ }
@@ -1,4 +1,5 @@
1
1
  {
2
2
  "prettier.trailingComma": "none",
3
- "workbench.colorTheme": "GitHub Dark Default"
4
- }
3
+ "workbench.colorTheme": "GitHub Dark Default",
4
+ "editor.formatOnSave": false
5
+ }
package/config/index.js CHANGED
@@ -20,7 +20,6 @@ module.exports = {
20
20
  env: {
21
21
  appId: 'APP_ID',
22
22
  token: 'ZMP_TOKEN',
23
- accessToken: 'VITE_ACCESS_TOKEN',
24
23
  },
25
24
  error_code: {
26
25
  app_config_not_found: -1400,
@@ -2,7 +2,7 @@ const indent = require('../../utils/indent');
2
2
  const stylesExtension = require('../../utils/styles-extension');
3
3
 
4
4
  module.exports = (options) => {
5
- const { cssPreProcessor, includeTailwind } = options;
5
+ const { cssPreProcessor, includeTailwind, framework } = options;
6
6
 
7
7
  let scripts = '';
8
8
 
@@ -30,7 +30,7 @@ module.exports = (options) => {
30
30
  }
31
31
 
32
32
  // Mount React App
33
- const root = createRoot(document.getElementById('app'));
33
+ ${framework === 'react-typescript' ? "const root = createRoot(document.getElementById('app')!);" : "const root = createRoot(document.getElementById('app'));"}
34
34
  root.render(React.createElement(App));
35
35
  `
36
36
  );
@@ -1,17 +1,19 @@
1
- const generateRoutes = require('../templates/generate-routes');
2
-
3
1
  module.exports = function generateAppConfig(options) {
4
2
  const { name } = options;
5
3
 
6
4
  // Window config
7
5
  const appConfig = {
8
6
  title: name,
7
+ headerTitle: name,
9
8
  headerColor: '#1843EF',
10
9
  textColor: 'white',
11
10
  statusBarColor: '#1843EF',
12
11
  leftButton: 'back',
12
+ statusBar: 'normal',
13
+ actionBarHidden: false,
14
+ hideAndroidBottomNavigationBar: false,
15
+ hideIOSSafeAreaBottom: false,
13
16
  };
14
- const routes = generateRoutes(options);
15
17
  // Content
16
18
  const content = JSON.stringify(
17
19
  {
@@ -20,7 +22,6 @@ module.exports = function generateAppConfig(options) {
20
22
  listCSS: [],
21
23
  listSyncJS: [],
22
24
  listAsyncJS: [],
23
- pages: routes,
24
25
  },
25
26
  '',
26
27
  2
@@ -18,7 +18,6 @@ module.exports = function generatePackageJson(options) {
18
18
  : ['zmp-framework', 'zmp-sdk', 'swiper'];
19
19
  const dependenciesVue = ['vue@3', 'zmp-framework'];
20
20
  const dependenciesReact = ['react', 'react-dom', 'prop-types'];
21
- const dependenciesReactTs = ['@types/react', '@types/react-dom'];
22
21
  const tailwindDependencies = [
23
22
  'autoprefixer',
24
23
  'tailwindcss',
@@ -36,17 +35,17 @@ module.exports = function generatePackageJson(options) {
36
35
  }
37
36
  }
38
37
 
39
- if (framework === 'react-typescript') {
40
- dependencies.push(...dependenciesReactTs);
41
- if (package === 'zmp-ui') {
42
- dependencies.push('@types/react-router-dom');
43
- }
44
- }
45
38
  const devDependencies = [
46
39
  'cross-env',
47
40
  'postcss-preset-env@6.7.0',
48
41
  'vite@2.6.14',
49
42
  ];
43
+ if (framework === 'react-typescript') {
44
+ devDependencies.push('@types/react', '@types/react-dom');
45
+ if (package === 'zmp-ui') {
46
+ devDependencies.push('@types/react-router-dom');
47
+ }
48
+ }
50
49
  // CSS PreProcessor
51
50
  if (cssPreProcessor === 'stylus') devDependencies.push(...['stylus']);
52
51
  else if (cssPreProcessor === 'less') devDependencies.push(...['less']);
package/index.js CHANGED
@@ -19,12 +19,14 @@ const createApp = require('./create/index');
19
19
  const startApp = require('./start/index');
20
20
  const buildApp = require('./build/index');
21
21
  const deployApp = require('./deploy/index');
22
+ const syncApp = require('./sync/index');
22
23
  const migrateApp = require('./migrate/index');
23
24
  const os = require('os');
24
25
  // const generateAssets = require('./assets/index');
25
26
  // const server = require('./ui/server');
26
27
  const pkg = require('./package.json');
27
28
  const config = require('./config');
29
+ const { versionStatus } = require('./utils/constants');
28
30
 
29
31
  const cwd = process.cwd();
30
32
 
@@ -191,6 +193,11 @@ program
191
193
  .command('deploy')
192
194
  .option('-D, --dev', 'Deploy in Development server')
193
195
  .option('-M, --mode <m>', 'Env mode')
196
+ .option('-p, --passive', 'Passive mode (non-interactive)')
197
+ .option('-e, --existing', 'Deploy existing project')
198
+ .option('-t, --testing', 'Deploy testing version')
199
+ .option('-m, --desc <message>', 'Version description')
200
+ .option('-o, --outputDir <output>', 'Output folder. Default www')
194
201
  .option(
195
202
  '-P, --port <n>',
196
203
  'Specify UI server port. By default it is 3001',
@@ -199,7 +206,17 @@ program
199
206
  .description('Deploy a ZMP project')
200
207
  .action(async (options) => {
201
208
  const currentProject = getCurrentProject(cwd);
202
- const opts = await getDeployOptions(currentProject);
209
+ let opts = options;
210
+ if (options.existing) {
211
+ opts.customProject = true;
212
+ } else {
213
+ if (!options.passive) {
214
+ opts = await getDeployOptions(currentProject);
215
+ }
216
+ }
217
+ if (options.testing) {
218
+ opts.versionStatus = versionStatus.TESTING;
219
+ }
203
220
  if (opts.quit) process.exit(1);
204
221
  await deployApp(
205
222
  {
@@ -213,6 +230,27 @@ program
213
230
  process.exit(0);
214
231
  });
215
232
 
233
+ program
234
+ .usage('<command> [options]')
235
+ .command('sync-config <source>')
236
+ .option(
237
+ '-r, --root-element <selector>',
238
+ 'Custom entry point, default is #app'
239
+ )
240
+ .description(
241
+ 'Automatically update app-config.json resources list based on index.html'
242
+ )
243
+ .action(async (source, options) => {
244
+ await syncApp(
245
+ {
246
+ source,
247
+ ...options,
248
+ },
249
+ logger
250
+ );
251
+ process.exit(0);
252
+ });
253
+
216
254
  program
217
255
  .usage('<command> [options]')
218
256
  .command('migrate')
package/login/index.js CHANGED
@@ -111,7 +111,6 @@ module.exports = async (options = {}, logger, { exitOnError = true } = {}) => {
111
111
  clearInterval(intervalCheckLogin);
112
112
  const token = resData.data && resData.data.jwt;
113
113
  envUtils.setEnv(config.env.token, token);
114
- envUtils.setEnv(config.env.accessToken, token);
115
114
  logger.statusDone('Login Success!');
116
115
  return resolve();
117
116
  }
@@ -146,7 +145,6 @@ module.exports = async (options = {}, logger, { exitOnError = true } = {}) => {
146
145
  const dataDecoded = jwt.decode(token);
147
146
  envUtils.setEnv(config.env.appId, dataDecoded.appId);
148
147
  envUtils.setEnv(config.env.token, token);
149
- envUtils.setEnv(config.env.accessToken, options.token);
150
148
  } catch (error) {
151
149
  return reject(error);
152
150
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zmp-cli",
3
- "version": "3.12.0",
3
+ "version": "3.13.0",
4
4
  "description": "ZMP command line utility (CLI)",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -56,6 +56,7 @@
56
56
  "copy-webpack-plugin": "^7.0.0",
57
57
  "cpy": "^7.3.0",
58
58
  "css-minimizer-webpack-plugin": "^1.2.0",
59
+ "dom-parser": "^0.1.6",
59
60
  "envfile": "^6.14.0",
60
61
  "exec-sh": "^0.3.2",
61
62
  "express": "^4.17.1",
@@ -0,0 +1,143 @@
1
+ const DomParser = require('dom-parser');
2
+ const fs = require('fs');
3
+ const axios = require('axios');
4
+
5
+ async function generateListResourcesFromIndex(html, { outputDir, rootElement }) {
6
+ const listCSS = [];
7
+ const listSyncJS = [];
8
+ const listAsyncJS = [];
9
+ let inlineJS = '';
10
+ try {
11
+ const parser = new DomParser();
12
+ const doc = parser.parseFromString(html, 'text/html');
13
+ const headInlines = [];
14
+ const bodyInlines = [];
15
+
16
+ const scripts = doc.getElementsByTagName('script');
17
+ for (const script of scripts) {
18
+ const src = script.getAttribute('src');
19
+ const type = script.getAttribute('type');
20
+ const async = script.getAttribute('async');
21
+ const inline = script.innerHTML;
22
+ try {
23
+ if (inline) {
24
+ bodyInlines.push(script.outerHTML);
25
+ } else {
26
+ let scriptName = src;
27
+ if (src.includes('://')) {
28
+ let filename = src.substring(src.lastIndexOf('/') + 1);
29
+ filename = `cdn.` + filename;
30
+ const response = await axios({
31
+ method: 'get',
32
+ url: src,
33
+ responseType: 'stream',
34
+ });
35
+ const fileStream = fs.createWriteStream(`${outputDir}/${filename}`);
36
+ response.data.pipe(fileStream);
37
+
38
+ await new Promise((resolve, reject) => {
39
+ fileStream.on('finish', resolve);
40
+ fileStream.on('error', reject);
41
+ });
42
+ scriptName = filename;
43
+ }
44
+ if (type === 'module' && !scriptName.endsWith('module.js')) {
45
+ const newName = src.slice(0, -3).concat('.module.js');
46
+ fs.rename(scriptName, newName);
47
+ scriptName = newName;
48
+ }
49
+ (async ? listAsyncJS : listSyncJS).push(scriptName);
50
+ }
51
+ } catch (error) {
52
+ console.warn(
53
+ '\n⚠️ Unable to download resource from CDN. Please handle this file manually!',
54
+ src
55
+ );
56
+ console.error(error.message);
57
+ }
58
+ }
59
+
60
+ const styles = doc.getElementsByTagName('style');
61
+ styles.forEach((style) => {
62
+ const inline = style.innerHTML;
63
+ if (inline) {
64
+ headInlines.push(style.outerHTML);
65
+ }
66
+ });
67
+
68
+ const links = doc.getElementsByTagName('link');
69
+ for (const link of links) {
70
+ const rel = link.getAttribute('rel');
71
+ const href = link.getAttribute('href');
72
+ try {
73
+ if (rel === 'stylesheet') {
74
+ let filename = href;
75
+ if (href.includes('://')) {
76
+ filename = href.substring(href.lastIndexOf('/') + 1);
77
+ filename = `cdn.` + filename;
78
+ const response = await axios({
79
+ method: 'get',
80
+ url: href,
81
+ responseType: 'stream',
82
+ });
83
+ const fileStream = fs.createWriteStream(`${outputDir}/${filename}`);
84
+ response.data.pipe(fileStream);
85
+
86
+ await new Promise((resolve, reject) => {
87
+ fileStream.on('finish', resolve);
88
+ fileStream.on('error', reject);
89
+ });
90
+ }
91
+ listCSS.push(filename);
92
+ }
93
+ } catch (error) {
94
+ console.error(
95
+ '\n⚠️ Unable to download resource from CDN. Please handle this file manually!',
96
+ href
97
+ );
98
+ console.error(error.message);
99
+ }
100
+ }
101
+
102
+ const metas = doc.getElementsByTagName('meta');
103
+ metas.forEach((meta) => {
104
+ headInlines.push(meta.outerHTML);
105
+ });
106
+
107
+ if (rootElement && rootElement !== '#app') {
108
+ let html = `<${rootElement} />`;
109
+ if (rootElement.startsWith('#')) {
110
+ html = `<div id="${rootElement.substring(1)}" />`;
111
+ }
112
+ if (rootElement.startsWith('.')) {
113
+ html = `<div class="${rootElement.substring(1)}" />`;
114
+ }
115
+ if (rootElement.startsWith('<')) {
116
+ html = rootElement;
117
+ }
118
+ bodyInlines.unshift(html);
119
+ }
120
+
121
+ inlineJS += headInlines
122
+ .map(
123
+ (inline) =>
124
+ `document.head.innerHTML += \`${inline.replaceAll('`', '\\`')}\`;`
125
+ )
126
+ .join('\n');
127
+ inlineJS += '\n';
128
+ inlineJS += bodyInlines
129
+ .map(
130
+ (inline) =>
131
+ `document.body.innerHTML += \`${inline.replaceAll('`', '\\`')}\`;`
132
+ )
133
+ .join('\n');
134
+ listSyncJS.unshift('inline.js');
135
+ } catch (error) {
136
+ console.error(error.message);
137
+ }
138
+ return { listCSS, listSyncJS, listAsyncJS, inlineJS };
139
+ }
140
+
141
+ module.exports = {
142
+ generateListResourcesFromIndex,
143
+ };
package/sync/index.js ADDED
@@ -0,0 +1,55 @@
1
+ const path = require('path');
2
+ const chalk = require('chalk');
3
+ const fse = require('../utils/fs-extra');
4
+ const config = require('../config');
5
+ const { generateListResourcesFromIndex } = require('./index-to-app-config');
6
+
7
+ const waitText = chalk.gray('(Please wait, it can take a while)');
8
+ const defaultLogger = {
9
+ statusStart() {},
10
+ statusDone() {},
11
+ statusText() {},
12
+ statusError() {},
13
+ text() {},
14
+ error() {},
15
+ showOnUI() {},
16
+ };
17
+
18
+ module.exports = async (options = {}, logger = defaultLogger) => {
19
+ logger.statusStart(`Synchronization configuration ${waitText}`);
20
+ const cwd = process.cwd();
21
+ const { source, rootElement } = options;
22
+ const appConfigFilename = config.filename.appConfig;
23
+ const resolvePath = (dir) => {
24
+ return path.join(cwd, dir);
25
+ };
26
+ function errorExit(err) {
27
+ logger.error(err.stderr || err);
28
+ process.exit(1);
29
+ }
30
+ let appConfigJson;
31
+ try {
32
+ appConfigJson = require(resolvePath(appConfigFilename));
33
+ } catch (err) {
34
+ errorExit(new Error(config.error_msg.app_config_not_found));
35
+ }
36
+
37
+ const html = fse.readFileSync(source).toString();
38
+ const outputDir = path.dirname(source);
39
+ const { listCSS, listSyncJS, listAsyncJS, inlineJS } =
40
+ await generateListResourcesFromIndex(html, { outputDir, rootElement });
41
+ Object.assign(appConfigJson, {
42
+ listCSS,
43
+ listSyncJS,
44
+ listAsyncJS,
45
+ });
46
+ if (inlineJS) {
47
+ fse.writeFileSync(resolvePath(`${outputDir}/inline.js`), inlineJS);
48
+ }
49
+ const output = JSON.stringify(appConfigJson, null, 2);
50
+ fse.writeFileSync(resolvePath(appConfigFilename), output);
51
+ logger.statusDone(
52
+ `${chalk.bold.green('Configuration synchronization completed!')} 💪`
53
+ );
54
+ logger.text({ listCSS, listSyncJS, listAsyncJS });
55
+ };