devextreme-cli 1.11.0-alpha.0 → 1.11.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.
Files changed (100) hide show
  1. package/package.json +10 -9
  2. package/src/application.js +40 -20
  3. package/src/applications/application.angular.js +11 -3
  4. package/src/applications/application.nextjs.js +231 -0
  5. package/src/applications/application.react.js +16 -6
  6. package/src/applications/application.vue.js +6 -11
  7. package/src/templates/nextjs/application/.env +1 -0
  8. package/src/templates/nextjs/application/devextreme.json +63 -0
  9. package/src/templates/nextjs/application/next.config.mjs +32 -0
  10. package/src/templates/nextjs/application/public/logo192.png +0 -0
  11. package/src/templates/nextjs/application/public/logo512.png +0 -0
  12. package/src/templates/nextjs/application/public/manifest.json +25 -0
  13. package/src/templates/nextjs/application/public/robots.txt +3 -0
  14. package/src/templates/nextjs/application/src/app/actions/auth.ts +76 -0
  15. package/src/templates/nextjs/application/src/app/auth/[type]/page.tsx +49 -0
  16. package/src/templates/nextjs/application/src/app/layout.tsx +17 -0
  17. package/src/templates/nextjs/application/src/app/lib/session.ts +47 -0
  18. package/src/templates/nextjs/application/src/app/pages/layout.tsx +18 -0
  19. package/src/templates/nextjs/application/src/app-info.tsx +5 -0
  20. package/src/templates/nextjs/application/src/app-navigation.tsx +21 -0
  21. package/src/templates/nextjs/application/src/components/change-password-form/ChangePasswordForm.tsx +86 -0
  22. package/src/templates/nextjs/application/src/components/create-account-form/CreateAccountForm.scss +19 -0
  23. package/src/templates/nextjs/application/src/components/create-account-form/CreateAccountForm.tsx +107 -0
  24. package/src/templates/nextjs/application/src/components/footer/Footer.scss +12 -0
  25. package/src/templates/nextjs/application/src/components/footer/Footer.tsx +5 -0
  26. package/src/templates/nextjs/application/src/components/header/Header.scss +40 -0
  27. package/src/templates/nextjs/application/src/components/header/Header.tsx +38 -0
  28. package/src/templates/nextjs/application/src/components/index.tsx +7 -0
  29. package/src/templates/nextjs/application/src/components/login-form/LoginForm.scss +12 -0
  30. package/src/templates/nextjs/application/src/components/login-form/LoginForm.tsx +101 -0
  31. package/src/templates/nextjs/application/src/components/reset-password-form/ResetPasswordForm.scss +12 -0
  32. package/src/templates/nextjs/application/src/components/reset-password-form/ResetPasswordForm.tsx +78 -0
  33. package/src/templates/nextjs/application/src/components/side-navigation-menu/SideNavigationMenu.scss +71 -0
  34. package/src/templates/nextjs/application/src/components/side-navigation-menu/SideNavigationMenu.tsx +88 -0
  35. package/src/templates/nextjs/application/src/components/theme-switcher/ThemeSwitcher.tsx +21 -0
  36. package/src/templates/nextjs/application/src/components/user-panel/UserPanel.scss +51 -0
  37. package/src/templates/nextjs/application/src/components/user-panel/UserPanel.tsx +55 -0
  38. package/src/templates/nextjs/application/src/dx-styles.scss +106 -0
  39. package/src/templates/nextjs/application/src/index.css +12 -0
  40. package/src/templates/nextjs/application/src/layouts/index.tsx +3 -0
  41. package/src/templates/nextjs/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.scss +17 -0
  42. package/src/templates/nextjs/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.tsx +133 -0
  43. package/src/templates/nextjs/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.scss +10 -0
  44. package/src/templates/nextjs/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.tsx +119 -0
  45. package/src/templates/nextjs/application/src/layouts/single-card/single-card.scss +42 -0
  46. package/src/templates/nextjs/application/src/layouts/single-card/single-card.tsx +16 -0
  47. package/src/templates/nextjs/application/src/middleware.ts +46 -0
  48. package/src/templates/nextjs/application/src/theme.tsx +66 -0
  49. package/src/templates/nextjs/application/src/themes/metadata.additional.dark.json +11 -0
  50. package/src/templates/nextjs/application/src/themes/metadata.additional.json +11 -0
  51. package/src/templates/nextjs/application/src/themes/metadata.base.dark.json +8 -0
  52. package/src/templates/nextjs/application/src/themes/metadata.base.json +7 -0
  53. package/src/templates/nextjs/application/src/types.tsx +60 -0
  54. package/src/templates/nextjs/application/src/utils/default-user.tsx +7 -0
  55. package/src/templates/nextjs/application/src/utils/media-query.tsx +56 -0
  56. package/src/templates/nextjs/application/src/variables.scss +53 -0
  57. package/src/templates/nextjs/page/page.scss +0 -0
  58. package/src/templates/nextjs/page/page.tsx +13 -0
  59. package/src/templates/nextjs/sample-pages/home/home.scss +37 -0
  60. package/src/templates/nextjs/sample-pages/home/page.tsx +101 -0
  61. package/src/templates/nextjs/sample-pages/profile/page.tsx +61 -0
  62. package/src/templates/nextjs/sample-pages/profile/profile.scss +19 -0
  63. package/src/templates/nextjs/sample-pages/tasks/page.tsx +112 -0
  64. package/src/templates/nextjs/sample-pages/tasks/tasks.scss +3 -0
  65. package/src/templates/react/application/src/App.tsx +2 -1
  66. package/src/templates/react/application/src/Content.tsx +1 -1
  67. package/src/templates/react/application/src/app-routes.tsx +3 -3
  68. package/src/templates/react/application/src/components/change-password-form/ChangePasswordForm.tsx +1 -1
  69. package/src/templates/react/application/src/components/create-account-form/CreateAccountForm.tsx +1 -1
  70. package/src/templates/react/application/src/components/header/Header.scss +1 -1
  71. package/src/templates/react/application/src/components/login-form/LoginForm.tsx +1 -1
  72. package/src/templates/react/application/src/components/side-navigation-menu/SideNavigationMenu.tsx +2 -2
  73. package/src/templates/react/application/src/components/user-panel/UserPanel.tsx +1 -1
  74. package/src/templates/react/application/src/contexts/auth-hooks.ts +8 -0
  75. package/src/templates/react/application/src/contexts/auth.tsx +7 -5
  76. package/src/templates/react/application/src/contexts/navigation-hooks.ts +22 -0
  77. package/src/templates/react/application/src/contexts/navigation.tsx +3 -17
  78. package/src/templates/react/application/src/dx-styles.scss +3 -3
  79. package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.tsx +3 -3
  80. package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.tsx +3 -3
  81. package/src/templates/react/application/src/types.tsx +2 -2
  82. package/src/templates/react/page/page.tsx +1 -1
  83. package/src/templates/react/sample-pages/home/home.tsx +1 -1
  84. package/src/templates/react/sample-pages/index.tsx +3 -3
  85. package/src/templates/react/sample-pages/profile/profile.tsx +1 -1
  86. package/src/templates/react/sample-pages/tasks/tasks.tsx +1 -1
  87. package/src/templates/vue-v3/application/eslint.config.js +32 -0
  88. package/src/templates/vue-v3/application/src/App.vue +1 -1
  89. package/src/templates/vue-v3/application/src/components/header-toolbar.vue +2 -2
  90. package/src/templates/vue-v3/application/src/dx-styles.scss +4 -3
  91. package/src/templates/vue-v3/application/src/layouts/side-nav-inner-toolbar.vue +2 -2
  92. package/src/templates/vue-v3/application/src/layouts/side-nav-outer-toolbar.vue +2 -2
  93. package/src/templates/vue-v3/application/src/main.js +1 -1
  94. package/src/templates/vue-v3/application/src/router.js +5 -5
  95. package/src/utility/latest-versions.js +7 -4
  96. package/src/utility/module.js +13 -5
  97. package/src/utility/prompts/react-app-type.js +17 -0
  98. package/src/utility/run-command.js +10 -2
  99. package/src/utility/template-creator.js +8 -4
  100. package/src/templates/vue-v3/application/vue.config.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devextreme-cli",
3
- "version": "1.11.0-alpha.0",
3
+ "version": "1.11.0",
4
4
  "description": "DevExtreme CLI",
5
5
  "keywords": [
6
6
  "devexpress",
@@ -14,8 +14,8 @@
14
14
  "devextreme": "index.js"
15
15
  },
16
16
  "engines": {
17
- "node": ">12.6.0",
18
- "npm": ">6.2.0",
17
+ "node": ">20.19.0",
18
+ "npm": ">9.6.0",
19
19
  "yarn": ">1.21"
20
20
  },
21
21
  "files": [
@@ -43,7 +43,7 @@
43
43
  "minimist": "^1.2.8",
44
44
  "mustache": "^3.2.1",
45
45
  "prompts": "^2.4.2",
46
- "sass": "^1.85.1",
46
+ "sass": "^1.89.2",
47
47
  "semver": "^5.7.2",
48
48
  "strip-bom": "^4.0.0"
49
49
  },
@@ -51,7 +51,7 @@
51
51
  "@typescript-eslint/eslint-plugin": "^4.33.0",
52
52
  "@typescript-eslint/parser": "^4.33.0",
53
53
  "babel-eslint": "^10.1.0",
54
- "create-vite": "6.3.1",
54
+ "create-vite": "7.0.0",
55
55
  "cross-env": "^5.2.1",
56
56
  "eslint": "^7.32.0",
57
57
  "eslint-config-angular": "^0.5.0",
@@ -59,19 +59,20 @@
59
59
  "eslint-plugin-angular": "^4.1.0",
60
60
  "eslint-plugin-jest": "^22.21.0",
61
61
  "eslint-plugin-prettier": "^4.2.1",
62
- "eslint-plugin-react": "^7.37.4",
62
+ "eslint-plugin-react": "^7.37.5",
63
63
  "eslint-plugin-react-hooks": "^4.6.2",
64
64
  "eslint-plugin-unused-imports": "^1.1.5",
65
65
  "eslint-plugin-vue": "^7.20.0",
66
66
  "eslint-stylish": "^0.2.0",
67
67
  "jest": "^29.7.0",
68
- "jest-image-snapshot": "^6.4.0",
68
+ "jest-image-snapshot": "^6.5.1",
69
69
  "prettier": "^2.8.8",
70
70
  "rimraf": "^2.7.1",
71
71
  "tree-kill": "^1.2.2",
72
72
  "tree-kill-promise": "^1.0.12",
73
73
  "typescript": "^4.0.2",
74
- "typescript-eslint-parser": "^22.0.0"
74
+ "typescript-eslint-parser": "^22.0.0",
75
+ "wait-on": "8.0.3"
75
76
  },
76
- "gitHead": "4c13206f0278c88053f62682fd2a6ca0a8ea5866"
77
+ "gitHead": "16351e5d8d9dceee7d826668231c3e047d4df3fc"
77
78
  }
@@ -1,12 +1,34 @@
1
1
  const angularApplication = require('./applications/application.angular');
2
2
  const reactApplication = require('./applications/application.react');
3
+ const nextjsApplication = require('./applications/application.nextjs');
3
4
  const vueApplication = require('./applications/application.vue');
5
+ const getReactAppType = require('./utility/prompts/react-app-type');
4
6
  const printHelp = require('./help').printHelp;
5
7
 
6
8
  const isApplicationCommand = (command) => {
7
9
  return [ 'new', 'add' ].includes(command);
8
10
  };
9
11
 
12
+ const handleWrongAppType = (appType, command) => {
13
+ console.error(`The '${appType}' application type is not valid`);
14
+ printHelp(command);
15
+ };
16
+
17
+ const createReact = async(appName, options, command) => {
18
+ const reactAppType = await getReactAppType(options['app-type']);
19
+
20
+ switch(reactAppType) {
21
+ case 'vite':
22
+ await reactApplication.create(appName, options);
23
+ return;
24
+ case 'nextjs':
25
+ await nextjsApplication.create(appName, options);
26
+ return;
27
+ default:
28
+ handleWrongAppType(reactAppType, command);
29
+ }
30
+ };
31
+
10
32
  const run = async(commands, options, devextremeConfig) => {
11
33
  if(!commands[1]) {
12
34
  console.error('Command is incomplete. Please specify parameters.');
@@ -23,15 +45,15 @@ const run = async(commands, options, devextremeConfig) => {
23
45
  await angularApplication.create(appName, options);
24
46
  return;
25
47
  case 'react-app':
26
- await reactApplication.create(appName, options);
48
+ await createReact(appName, options, commands[0]);
27
49
  return;
28
50
  case 'vue-app':
29
51
  await vueApplication.create(appName, options);
30
52
  return;
31
53
  default:
32
- console.error(`The '${app}' application type is not valid`);
33
- printHelp(commands[0]);
54
+ handleWrongAppType(app, commands[0]);
34
55
  }
56
+
35
57
  } else {
36
58
  if(commands[0] === 'add') {
37
59
  if(commands[1] === 'devextreme-angular') {
@@ -40,7 +62,12 @@ const run = async(commands, options, devextremeConfig) => {
40
62
  }
41
63
 
42
64
  if(commands[1] === 'devextreme-react') {
43
- reactApplication.install(options);
65
+ if(nextjsApplication.isNextJsApp()) {
66
+ nextjsApplication.install(options);
67
+ } else {
68
+ reactApplication.install(options);
69
+ }
70
+
44
71
  return;
45
72
  }
46
73
 
@@ -54,23 +81,16 @@ const run = async(commands, options, devextremeConfig) => {
54
81
  return;
55
82
  }
56
83
 
57
- if(devextremeConfig.applicationEngine === 'angular') {
58
- if(commands[1] === 'view') {
59
- angularApplication.addView(commands[2], options);
60
- } else {
61
- console.error('Invalid command');
62
- printHelp(commands[0]);
63
- }
64
- } else if(devextremeConfig.applicationEngine === 'react') {
65
- if(commands[1] === 'view') {
66
- reactApplication.addView(commands[2], options);
67
- } else {
68
- console.error('Invalid command');
69
- printHelp(commands[0]);
70
- }
71
- } else if(devextremeConfig.applicationEngine === 'vue') {
84
+ const app = {
85
+ 'angular': angularApplication,
86
+ 'react': reactApplication,
87
+ 'nextjs': nextjsApplication,
88
+ 'vue': vueApplication,
89
+ }[devextremeConfig.applicationEngine];
90
+
91
+ if(app) {
72
92
  if(commands[1] === 'view') {
73
- vueApplication.addView(commands[2], options);
93
+ app.addView(commands[2], options);
74
94
  } else {
75
95
  console.error('Invalid command');
76
96
  printHelp(commands[0]);
@@ -13,6 +13,7 @@ const modifyJson = require('../utility/modify-json-file');
13
13
  const schematicsVersion = latestVersions['devextreme-schematics'] || 'latest';
14
14
 
15
15
  const minNgCliVersion = new semver('17.0.0');
16
+ const ngCliWithZoneless = new semver('20.0.0');
16
17
 
17
18
  async function runSchematicCommand(schematicCommand, options, evaluatingOptions) {
18
19
  const collectionName = 'devextreme-schematics';
@@ -63,6 +64,7 @@ function localPackageExists(packageName) {
63
64
 
64
65
  const hasSutableNgCli = async() => {
65
66
  const localVersion = ngVersion.getLocalNgVersion();
67
+
66
68
  if(!localVersion) {
67
69
  return false;
68
70
  }
@@ -83,6 +85,7 @@ const bumpAngular = (appPath, versionTag) => {
83
85
  for(const depName in section) {
84
86
  section[depName] = depName.startsWith('@angular') ? versionTag : section[depName];
85
87
  }
88
+ return section;
86
89
  };
87
90
 
88
91
  return {
@@ -96,6 +99,7 @@ const bumpAngular = (appPath, versionTag) => {
96
99
 
97
100
  const create = async(appName, options) => {
98
101
  const layout = await getLayoutInfo(options.layout);
102
+ const currentNgVersion = ngVersion.getNgCliVersion().version;
99
103
  const depsVersionTag = extractDepsVersionTag(options);
100
104
 
101
105
  const commandArguments = [
@@ -105,10 +109,14 @@ const create = async(appName, options) => {
105
109
  '--routing=false',
106
110
  '--skip-tests=true',
107
111
  '--skip-install=true',
108
- '--standalone=false',
112
+ '--standalone=true',
109
113
  '--ssr=false'
110
114
  ];
111
115
 
116
+ if(ngCliWithZoneless.compare(currentNgVersion) <= 0) {
117
+ commandArguments.push('--zoneless=false');
118
+ }
119
+
112
120
  await runNgCommand(commandArguments, options);
113
121
 
114
122
  const appPath = path.join(process.cwd(), appName);
@@ -150,9 +158,9 @@ const changeMainTs = (appPath) => {
150
158
  moduleWorker.insertImport(filePath, 'devextreme/ui/themes', 'themes', true);
151
159
 
152
160
  const fileContent = fs.readFileSync(filePath).toString();
153
- const bootstrapPattern = /platformBrowser(?:Dynamic)?\(\)\.bootstrapModule\(\s*AppModule\s*(?:,\s*\{[^}]*\})?\s*\)/;
161
+ const bootstrapPattern = /bootstrapApplication\([^)]+\)/;
154
162
  const firstChaptStr = fileContent.match(bootstrapPattern)[0];
155
- const lastChaptStr = '.catch(err => console.error(err));';
163
+ const lastChaptStr = '.catch((err) => console.error(err));';
156
164
 
157
165
  fs.writeFileSync(
158
166
  filePath,
@@ -0,0 +1,231 @@
1
+ const runCommand = require('../utility/run-command');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const getLayoutInfo = require('../utility/prompts/layout');
5
+ const getTemplateTypeInfo = require('../utility/prompts/typescript');
6
+ const templateCreator = require('../utility/template-creator');
7
+ const packageManager = require('../utility/package-manager');
8
+ const packageJsonUtils = require('../utility/package-json-utils');
9
+ const insertItemToArray = require('../utility/file-content').insertItemToArray;
10
+ const stringUtils = require('../utility/string');
11
+ const typescriptUtils = require('../utility/typescript-extension');
12
+ const removeFile = require('../utility/file-operations').remove;
13
+ const latestVersions = require('../utility/latest-versions');
14
+ const { extractDepsVersionTag } = require('../utility/extract-deps-version-tag');
15
+ const {
16
+ updateJsonPropName,
17
+ bumpReact,
18
+ getCorrectPath,
19
+ addStylesToApp,
20
+ getComponentPageName,
21
+ } = require('./application.react');
22
+
23
+ const defaultStyles = [
24
+ 'devextreme/dist/css/dx.light.css'
25
+ ];
26
+
27
+ const isNextJsApp = () => {
28
+ const appPath = process.cwd();
29
+
30
+ return fs.existsSync(path.join(appPath, 'next.config.ts')) || fs.existsSync(path.join(appPath, 'next.config.mjs'));
31
+ };
32
+
33
+ const isTsApp = (appPath) => {
34
+ return fs.existsSync(path.join(appPath, 'next.config.ts'));
35
+ };
36
+
37
+ const getExtension = (appPath) => {
38
+ return fs.existsSync(path.join(appPath, 'src/app', 'layout.tsx')) ? '.tsx' : '.jsx';
39
+ };
40
+
41
+ const pathToPagesIndex = () => {
42
+ const extension = getExtension(process.cwd());
43
+ return path.join(process.cwd(), 'src', 'views', `index${extension}`);
44
+ };
45
+
46
+ const preparePackageJsonForTemplate = (appPath, appName) => {
47
+ const dependencies = [
48
+ { name: 'devextreme-cli', version: latestVersions['devextreme-cli'], dev: true },
49
+ { name: 'jose', version: latestVersions['jose'] },
50
+ ];
51
+ const scripts = [
52
+ { name: 'build-themes', value: 'devextreme build' },
53
+ { name: 'postinstall', value: 'npm run build-themes' }
54
+ ];
55
+
56
+ packageJsonUtils.addDependencies(appPath, dependencies);
57
+ packageJsonUtils.updateScripts(appPath, scripts);
58
+ packageJsonUtils.updateName(appPath, appName);
59
+ };
60
+
61
+ const create = async(appName, options) => {
62
+ const templateType = await getTemplateTypeInfo(options.template);
63
+ const layoutType = await getLayoutInfo(options.layout);
64
+
65
+ const templateOptions = Object.assign({}, options, {
66
+ project: stringUtils.humanize(appName),
67
+ layout: stringUtils.classify(layoutType),
68
+ isTypeScript: typescriptUtils.isTypeScript(templateType)
69
+ });
70
+ const depsVersionTag = extractDepsVersionTag(options);
71
+
72
+ let commandArguments = [`-p=create-next-app@${depsVersionTag || latestVersions['create-next-app']}`, 'create-next-app', appName];
73
+
74
+ commandArguments = [
75
+ ...commandArguments,
76
+ `${templateOptions.isTypeScript ? '--typescript' : '--javascript'}`,
77
+ '--eslint',
78
+ '--no-tailwind',
79
+ '--src-dir',
80
+ '--app',
81
+ '--no-turbopack',
82
+ '--import-alias "@/*"',
83
+ ];
84
+
85
+ await runCommand('npx', commandArguments);
86
+
87
+ const appPath = path.join(process.cwd(), appName);
88
+
89
+ if(depsVersionTag) {
90
+ bumpReact(appPath, depsVersionTag, templateOptions.isTypeScript);
91
+ }
92
+
93
+ addTemplate(appPath, appName, templateOptions);
94
+ modifyAppFiles(appPath, templateOptions);
95
+ };
96
+
97
+ const modifyAppFiles = (appPath, { project, isTypeScript }) => {
98
+ const entryFilePath = path.join(appPath, `src/app/layout.${isTypeScript ? 'tsx' : 'jsx'}`);
99
+
100
+ let content = fs.readFileSync(entryFilePath).toString();
101
+ content = content.replace(/<title>[^<]+<\/title>/, `<title>${project}<\/title>`);
102
+
103
+ fs.writeFileSync(entryFilePath, content);
104
+ };
105
+
106
+ const addTemplate = (appPath, appName, templateOptions) => {
107
+ const applicationTemplatePath = path.join(
108
+ templateCreator.getTempaltePath('nextjs'),
109
+ 'application'
110
+ );
111
+
112
+ const manifestPath = path.join(appPath, 'public', 'manifest.json');
113
+
114
+ const styles = [
115
+ '../dx-styles.scss',
116
+ '../themes/generated/theme.additional.css',
117
+ '../themes/generated/theme.additional.dark.css',
118
+ '../themes/generated/theme.base.css',
119
+ '../themes/generated/theme.base.dark.css',
120
+ 'devextreme/dist/css/dx.common.css'
121
+ ];
122
+
123
+ templateCreator.moveTemplateFilesToProject(applicationTemplatePath, appPath, templateOptions, getCorrectPath);
124
+
125
+ !templateOptions.isTypeScript && removeFile(path.join(appPath, 'src', 'types.jsx'));
126
+ removeFile(path.join(appPath, 'src/app', 'page.js'));
127
+ removeFile(path.join(appPath, 'src/app', 'layout.js'));
128
+ removeFile(path.join(appPath, 'src/app', 'globals.scss'));
129
+
130
+ if(!templateOptions.empty) {
131
+ addSamplePages(appPath, templateOptions);
132
+ }
133
+
134
+ preparePackageJsonForTemplate(appPath, appName, templateOptions.isTypeScript);
135
+ updateJsonPropName(manifestPath, appName);
136
+ install({ isTypeScript: templateOptions.isTypeScript }, appPath, styles);
137
+ };
138
+
139
+ const getEntryFilePath = (options, appPath) => {
140
+ const extension = options.isTypeScript || isTsApp(appPath) ? 'ts' : 'js';
141
+ const srcFolder = fs.existsSync(path.join(appPath, 'src')) ? 'src' : '';
142
+ const isAppRouterApp = fs.existsSync(path.join(appPath, srcFolder, 'app')) && fs.lstatSync(appPath).isDirectory();
143
+
144
+ const entryFilePath = isAppRouterApp
145
+ ? path.join('app', `layout.${extension}`)
146
+ : path.join('pages', `_app.${extension}`);
147
+
148
+ const jsx = fs.existsSync(path.join(appPath, srcFolder, entryFilePath + 'x')) ? 'x' : '';
149
+
150
+ return path.join(srcFolder, entryFilePath + jsx);
151
+ };
152
+
153
+ const install = (options, appPath, styles) => {
154
+ appPath = appPath ? appPath : process.cwd();
155
+
156
+ const pathToMainComponent = path.join(appPath, getEntryFilePath(options, appPath));
157
+
158
+ addStylesToApp(pathToMainComponent, styles || defaultStyles);
159
+ packageJsonUtils.addDevextreme(appPath, options.dxversion, 'react');
160
+
161
+ packageManager.runInstall({ cwd: appPath });
162
+ };
163
+
164
+ const getNavigationData = (viewName, componentName, icon) => {
165
+ const pagePath = stringUtils.dasherize(viewName);
166
+ return {
167
+ navigation: `\n {\n text: \'${stringUtils.humanize(viewName)}\',\n path: \'/pages/${pagePath}\',\n icon: \'${icon}\'\n }`
168
+ };
169
+ };
170
+
171
+ const createPathToPage = (pageName) => {
172
+ const pagesPath = path.join(process.cwd(), 'src', 'app/pages');
173
+ const newPageFolderPath = path.join(pagesPath, pageName);
174
+
175
+ if(!fs.existsSync(pagesPath)) {
176
+ fs.mkdirSync(pagesPath);
177
+ fs.writeFileSync(pathToPagesIndex(), '');
178
+ }
179
+
180
+ if(!fs.existsSync(newPageFolderPath)) {
181
+ fs.mkdirSync(newPageFolderPath);
182
+ }
183
+
184
+ return newPageFolderPath;
185
+ };
186
+
187
+ const addSamplePages = (appPath, templateOptions) => {
188
+ const samplePageTemplatePath = path.join(
189
+ templateCreator.getTempaltePath('nextjs'),
190
+ 'sample-pages'
191
+ );
192
+
193
+ const pagesPath = path.join(appPath, 'src', 'app/pages');
194
+
195
+ templateCreator.moveTemplateFilesToProject(samplePageTemplatePath, pagesPath, {
196
+ isTypeScript: templateOptions.isTypeScript
197
+ }, getCorrectPath);
198
+ };
199
+
200
+ const addView = (pageName, options) => {
201
+ const pageTemplatePath = path.join(
202
+ templateCreator.getTempaltePath('nextjs'),
203
+ 'page'
204
+ );
205
+ const extension = getExtension(process.cwd());
206
+
207
+ const componentName = getComponentPageName(pageName);
208
+ const pathToPage = createPathToPage(pageName);
209
+ const navigationModulePath = path.join(process.cwd(), 'src', `app-navigation${extension}`);
210
+ const navigationData = getNavigationData(pageName, componentName, options && options.icon || 'folder');
211
+
212
+ const getCorrectExtension = (fileExtension) => {
213
+ return fileExtension === '.tsx' ? extension : fileExtension;
214
+ };
215
+
216
+ const getPageFileName = (pageName, pageItem) => {
217
+ return pageItem === 'page.tsx' ? 'page' : pageName;
218
+ };
219
+
220
+ templateCreator.addPageToApp(pageName, pathToPage, pageTemplatePath, getCorrectExtension, { getPageFileName });
221
+
222
+ insertItemToArray(navigationModulePath, navigationData.navigation);
223
+ };
224
+
225
+ module.exports = {
226
+ isNextJsApp,
227
+ install,
228
+ create,
229
+ addTemplate,
230
+ addView
231
+ };
@@ -52,14 +52,19 @@ const updateJsonPropName = (path, name) => {
52
52
  });
53
53
  };
54
54
 
55
- const bumpReact = (appPath, versionTag) => {
55
+ const bumpReact = (appPath, versionTag, isTypeScript) => {
56
56
  const dependencies = [
57
57
  { name: 'react', version: versionTag },
58
58
  { name: 'react-dom', version: versionTag },
59
- { name: '@types/react', version: versionTag, dev: true },
60
- { name: '@types/react-dom', version: versionTag, dev: true },
61
59
  ];
62
60
 
61
+ if(isTypeScript) {
62
+ dependencies.push(
63
+ { name: '@types/react', version: versionTag, dev: true },
64
+ { name: '@types/react-dom', version: versionTag, dev: true },
65
+ );
66
+ }
67
+
63
68
  packageJsonUtils.addDependencies(appPath, dependencies);
64
69
  };
65
70
 
@@ -86,7 +91,7 @@ const create = async(appName, options) => {
86
91
  modifyIndexHtml(appPath, templateOptions.project);
87
92
 
88
93
  if(depsVersionTag) {
89
- bumpReact(appPath, depsVersionTag);
94
+ bumpReact(appPath, depsVersionTag, templateOptions.isTypeScript);
90
95
  }
91
96
 
92
97
  addTemplate(appPath, appName, templateOptions);
@@ -209,7 +214,7 @@ const addView = (pageName, options) => {
209
214
  return fileExtension === '.tsx' ? extension : fileExtension;
210
215
  };
211
216
  templateCreator.addPageToApp(pageName, pathToPage, pageTemplatePath, getCorrectExtension);
212
- moduleUtils.insertExport(pathToPagesIndex(), componentName, `./${pageName}/${pageName}`);
217
+ moduleUtils.insertExport(pathToPagesIndex(), componentName, `./${pageName}/${pageName}`, 'Page');
213
218
  moduleUtils.insertImport(routingModulePath, './pages', componentName);
214
219
  insertItemToArray(routingModulePath, navigationData.route);
215
220
  insertItemToArray(navigationModulePath, navigationData.navigation);
@@ -219,5 +224,10 @@ module.exports = {
219
224
  install,
220
225
  create,
221
226
  addTemplate,
222
- addView
227
+ addView,
228
+ updateJsonPropName,
229
+ bumpReact,
230
+ getCorrectPath,
231
+ addStylesToApp,
232
+ getComponentPageName,
223
233
  };
@@ -16,10 +16,9 @@ const defaultStyles = [
16
16
 
17
17
  const preparePackageJsonForTemplate = (appPath, appName) => {
18
18
  const dependencies = [
19
- { name: 'sass', version: '^1.34.1' },
19
+ { name: 'sass-embedded', version: '^1.85.1' },
20
20
  { name: 'vue-router', version: '^3.0.1' },
21
- { name: 'devextreme-cli', version: latestVersions['devextreme-cli'], dev: true },
22
- { name: 'sass-loader', version: '^10', dev: true }
21
+ { name: 'devextreme-cli', version: latestVersions['devextreme-cli'], dev: true }
23
22
  ];
24
23
 
25
24
  const nameDepends = dependencies.map(d => d.name);
@@ -38,18 +37,14 @@ const preparePackageJsonForTemplate = (appPath, appName) => {
38
37
  };
39
38
 
40
39
  async function createVueApp(name, depsVersionTag) {
41
- const argList = ['-p', `@vue/cli@${depsVersionTag}`, 'vue', 'create', name, '--registry', 'https://registry.npmjs.org/', '-p "Default (Vue 3)"'];
42
-
43
- return runCommand('npx', argList);
40
+ const argList = ['create', `vue@${depsVersionTag ? depsVersionTag : latestVersions['create-vue']}`, name, '--registry', 'https://registry.npmjs.org/', '--', '--eslint', '--default', '--bare'];
41
+ return runCommand('npm', argList);
44
42
  }
45
43
 
46
44
  const bumpVue = (appPath, versionTag) => {
47
45
  const dependencies = [
48
46
  { name: 'vue', version: versionTag },
49
47
  { name: 'vue-router', version: versionTag },
50
- { name: '@vue/cli-plugin-babel', version: versionTag, dev: true },
51
- { name: '@vue/cli-plugin-eslint', version: versionTag, dev: true },
52
- { name: '@vue/cli-service', version: versionTag, dev: true },
53
48
  ];
54
49
 
55
50
  packageJsonUtils.addDependencies(appPath, dependencies);
@@ -78,7 +73,7 @@ const create = async(appName, options) => {
78
73
  };
79
74
 
80
75
  const modifyIndexHtml = (appPath, appName) => {
81
- const indexHtmlPath = path.join(appPath, 'public', 'index.html');
76
+ const indexHtmlPath = path.join(appPath, 'index.html');
82
77
  let htmlContent = fs.readFileSync(indexHtmlPath).toString();
83
78
 
84
79
  htmlContent = htmlContent.replace(/<title>(\w+\s*)+<\/title>/, `<title>${appName}<\/title>`);
@@ -175,7 +170,7 @@ const addView = (pageName, options) => {
175
170
  const navigationData = getNavigationData(pageName, componentName, options && options.icon || 'folder');
176
171
  const getCorrectExtension = (fileExtension) => fileExtension;
177
172
  templateCreator.addPageToApp(pageName, pathToPage, pageTemplatePath, getCorrectExtension);
178
- moduleUtils.insertImport(routingModulePath, `./views/${pageName}`, componentName, true);
173
+ moduleUtils.insertImport(routingModulePath, `./views/${pageName}.vue`, componentName, true);
179
174
  insertItemToArray(routingModulePath, navigationData.route);
180
175
  insertItemToArray(navigationModulePath, navigationData.navigation);
181
176
  };
@@ -0,0 +1 @@
1
+ SESSION_SECRET=<your_secret_key_goes_here>
@@ -0,0 +1,63 @@
1
+ {
2
+ "applicationEngine": "nextjs",
3
+ "build": {
4
+ "commands": [
5
+ {
6
+ "command": "build-theme",
7
+ "options": {
8
+ "inputFile": "src/themes/metadata.base.json",
9
+ "outputFile": "src/themes/generated/theme.base.css"
10
+ }
11
+ },
12
+ {
13
+ "command": "build-theme",
14
+ "options": {
15
+ "inputFile": "src/themes/metadata.base.dark.json",
16
+ "outputFile": "src/themes/generated/theme.base.dark.css"
17
+ }
18
+ },
19
+ {
20
+ "command": "build-theme",
21
+ "options": {
22
+ "inputFile": "src/themes/metadata.additional.json",
23
+ "outputFile": "src/themes/generated/theme.additional.css"
24
+ }
25
+ },
26
+ {
27
+ "command": "build-theme",
28
+ "options": {
29
+ "inputFile": "src/themes/metadata.additional.dark.json",
30
+ "outputFile": "src/themes/generated/theme.additional.dark.css"
31
+ }
32
+ },
33
+ {
34
+ "command": "export-theme-vars",
35
+ "options": {
36
+ "inputFile": "src/themes/metadata.base.json",
37
+ "outputFile": "src/themes/generated/variables.base.scss"
38
+ }
39
+ },
40
+ {
41
+ "command": "export-theme-vars",
42
+ "options": {
43
+ "inputFile": "src/themes/metadata.base.dark.json",
44
+ "outputFile": "src/themes/generated/variables.base.dark.scss"
45
+ }
46
+ },
47
+ {
48
+ "command": "export-theme-vars",
49
+ "options": {
50
+ "inputFile": "src/themes/metadata.additional.json",
51
+ "outputFile": "src/themes/generated/variables.additional.scss"
52
+ }
53
+ },
54
+ {
55
+ "command": "export-theme-vars",
56
+ "options": {
57
+ "inputFile": "src/themes/metadata.additional.dark.json",
58
+ "outputFile": "src/themes/generated/variables.additional.dark.scss"
59
+ }
60
+ }
61
+ ]
62
+ }
63
+ }
@@ -0,0 +1,32 @@
1
+ /** @type {import('next').NextConfig} */
2
+ const nextConfig = {
3
+ async redirects() {
4
+ return [
5
+ {
6
+ source: '/',
7
+ destination: '/pages/home',
8
+ permanent: true,
9
+ },
10
+ {
11
+ source: '/login',
12
+ destination: '/auth/login',
13
+ permanent: true,
14
+ },
15
+ {
16
+ source: '/reset-password',
17
+ destination: '/auth/reset-password',
18
+ permanent: true,
19
+ },
20
+ {
21
+ source: '/create-account',
22
+ destination: '/auth/create-account',
23
+ permanent: true,
24
+ },
25
+ ]
26
+ },
27
+ images: {
28
+ remotePatterns: [new URL('https://js.devexpress.com/**')]
29
+ },
30
+ }
31
+
32
+ export default nextConfig;