@next/codemod 15.0.0-rc.0 → 15.0.0-rc.1

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 (33) hide show
  1. package/bin/next-codemod.js +55 -3
  2. package/bin/shared.js +7 -0
  3. package/bin/transform.js +124 -0
  4. package/bin/upgrade.js +390 -0
  5. package/lib/cra-to-next/global-css-transform.js +5 -5
  6. package/lib/cra-to-next/index-to-component.js +5 -5
  7. package/lib/handle-package.js +110 -0
  8. package/lib/install.js +2 -3
  9. package/lib/parser.js +28 -0
  10. package/lib/run-jscodeshift.js +18 -2
  11. package/lib/utils.js +115 -0
  12. package/package.json +13 -6
  13. package/transforms/add-missing-react-import.js +4 -3
  14. package/transforms/app-dir-runtime-config-experimental-edge.js +34 -0
  15. package/transforms/built-in-next-font.js +4 -3
  16. package/transforms/cra-to-next.js +238 -236
  17. package/transforms/lib/async-request-api/index.js +16 -0
  18. package/transforms/lib/async-request-api/next-async-dynamic-api.js +274 -0
  19. package/transforms/lib/async-request-api/next-async-dynamic-prop.js +715 -0
  20. package/transforms/lib/async-request-api/utils.js +374 -0
  21. package/transforms/metadata-to-viewport-export.js +4 -3
  22. package/transforms/name-default-component.js +6 -6
  23. package/transforms/new-link.js +9 -7
  24. package/transforms/next-async-request-api.js +9 -0
  25. package/transforms/next-dynamic-access-named-export.js +66 -0
  26. package/transforms/next-image-experimental.js +12 -15
  27. package/transforms/next-image-to-legacy-image.js +8 -9
  28. package/transforms/next-og-import.js +4 -3
  29. package/transforms/next-request-geo-ip.js +339 -0
  30. package/transforms/url-to-withrouter.js +1 -1
  31. package/transforms/withamp-to-config.js +1 -1
  32. package/bin/cli.js +0 -216
  33. package/lib/uninstall-package.js +0 -32
@@ -1,17 +1,9 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
4
  };
14
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = transformer;
15
7
  const fs_1 = __importDefault(require("fs"));
16
8
  const path_1 = __importDefault(require("path"));
17
9
  const execa_1 = __importDefault(require("execa"));
@@ -32,6 +24,18 @@ const craTransformsPath = path_1.default.join('../lib/cra-to-next');
32
24
  const globalCssTransformPath = require.resolve(path_1.default.join(craTransformsPath, 'global-css-transform.js'));
33
25
  const indexTransformPath = require.resolve(path_1.default.join(craTransformsPath, 'index-to-component.js'));
34
26
  class CraTransform {
27
+ appDir;
28
+ pagesDir;
29
+ isVite;
30
+ isCra;
31
+ isDryRun;
32
+ indexPage;
33
+ installClient;
34
+ shouldLogInfo;
35
+ packageJsonPath;
36
+ shouldUseTypeScript;
37
+ packageJsonData;
38
+ jscodeShiftFlags;
35
39
  constructor(files, flags) {
36
40
  this.isDryRun = flags.dry;
37
41
  this.jscodeShiftFlags = flags;
@@ -42,7 +46,7 @@ class CraTransform {
42
46
  this.pagesDir = this.getPagesDir();
43
47
  this.installClient = this.checkForYarn() ? 'yarn' : 'npm';
44
48
  const { dependencies, devDependencies } = this.packageJsonData;
45
- const hasDep = (dep) => (dependencies === null || dependencies === void 0 ? void 0 : dependencies[dep]) || (devDependencies === null || devDependencies === void 0 ? void 0 : devDependencies[dep]);
49
+ const hasDep = (dep) => dependencies?.[dep] || devDependencies?.[dep];
46
50
  this.isCra = hasDep('react-scripts');
47
51
  this.isVite = !this.isCra && hasDep('vite');
48
52
  if (!this.isCra && !this.isVite) {
@@ -60,45 +64,43 @@ class CraTransform {
60
64
  fatalMessage('Error: unable to find `src/index`');
61
65
  }
62
66
  }
63
- transform() {
64
- return __awaiter(this, void 0, void 0, function* () {
65
- console.log('Transforming CRA project at:', this.appDir);
66
- // convert src/index.js to a react component to render
67
- // inside of Next.js instead of the custom render root
68
- const indexTransformRes = yield (0, run_jscodeshift_1.default)(indexTransformPath, Object.assign(Object.assign({}, this.jscodeShiftFlags), { silent: true, verbose: 0 }), [path_1.default.join(this.appDir, 'src', this.indexPage)]);
69
- if (indexTransformRes.error > 0) {
70
- fatalMessage(`Error: failed to apply transforms for src/${this.indexPage}, please check for syntax errors to continue`);
71
- }
72
- if (index_to_component_1.indexContext.multipleRenderRoots) {
73
- fatalMessage(`Error: multiple ReactDOM.render roots in src/${this.indexPage}, migrate additional render roots to use portals instead to continue.\n` +
74
- `See here for more info: https://react.dev/reference/react-dom/createPortal`);
75
- }
76
- if (index_to_component_1.indexContext.nestedRender) {
77
- fatalMessage(`Error: nested ReactDOM.render found in src/${this.indexPage}, please migrate this to a top-level render (no wrapping functions) to continue`);
78
- }
79
- // comment out global style imports and collect them
80
- // so that we can add them to _app
81
- const globalCssRes = yield (0, run_jscodeshift_1.default)(globalCssTransformPath, Object.assign({}, this.jscodeShiftFlags), [this.appDir]);
82
- if (globalCssRes.error > 0) {
83
- fatalMessage(`Error: failed to apply transforms for src/${this.indexPage}, please check for syntax errors to continue`);
84
- }
85
- if (!this.isDryRun) {
86
- yield fs_1.default.promises.mkdir(path_1.default.join(this.appDir, this.pagesDir));
87
- }
88
- this.logCreate(this.pagesDir);
89
- if (global_css_transform_1.globalCssContext.reactSvgImports.size > 0) {
90
- // This de-opts webpack 5 since svg/webpack doesn't support webpack 5 yet,
91
- // so we don't support this automatically
92
- fatalMessage(`Error: import {ReactComponent} from './logo.svg' is not supported, please use normal SVG imports to continue.\n` +
93
- `React SVG imports found in:\n${[
94
- ...global_css_transform_1.globalCssContext.reactSvgImports,
95
- ].join('\n')}`);
96
- }
97
- yield this.updatePackageJson();
98
- yield this.createNextConfig();
99
- yield this.updateGitIgnore();
100
- yield this.createPages();
101
- });
67
+ async transform() {
68
+ console.log('Transforming CRA project at:', this.appDir);
69
+ // convert src/index.js to a react component to render
70
+ // inside of Next.js instead of the custom render root
71
+ const indexTransformRes = await (0, run_jscodeshift_1.default)(indexTransformPath, { ...this.jscodeShiftFlags, silent: true, verbose: 0 }, [path_1.default.join(this.appDir, 'src', this.indexPage)]);
72
+ if (indexTransformRes.error > 0) {
73
+ fatalMessage(`Error: failed to apply transforms for src/${this.indexPage}, please check for syntax errors to continue`);
74
+ }
75
+ if (index_to_component_1.indexContext.multipleRenderRoots) {
76
+ fatalMessage(`Error: multiple ReactDOM.render roots in src/${this.indexPage}, migrate additional render roots to use portals instead to continue.\n` +
77
+ `See here for more info: https://react.dev/reference/react-dom/createPortal`);
78
+ }
79
+ if (index_to_component_1.indexContext.nestedRender) {
80
+ fatalMessage(`Error: nested ReactDOM.render found in src/${this.indexPage}, please migrate this to a top-level render (no wrapping functions) to continue`);
81
+ }
82
+ // comment out global style imports and collect them
83
+ // so that we can add them to _app
84
+ const globalCssRes = await (0, run_jscodeshift_1.default)(globalCssTransformPath, { ...this.jscodeShiftFlags }, [this.appDir]);
85
+ if (globalCssRes.error > 0) {
86
+ fatalMessage(`Error: failed to apply transforms for src/${this.indexPage}, please check for syntax errors to continue`);
87
+ }
88
+ if (!this.isDryRun) {
89
+ await fs_1.default.promises.mkdir(path_1.default.join(this.appDir, this.pagesDir));
90
+ }
91
+ this.logCreate(this.pagesDir);
92
+ if (global_css_transform_1.globalCssContext.reactSvgImports.size > 0) {
93
+ // This de-opts webpack 5 since svg/webpack doesn't support webpack 5 yet,
94
+ // so we don't support this automatically
95
+ fatalMessage(`Error: import {ReactComponent} from './logo.svg' is not supported, please use normal SVG imports to continue.\n` +
96
+ `React SVG imports found in:\n${[
97
+ ...global_css_transform_1.globalCssContext.reactSvgImports,
98
+ ].join('\n')}`);
99
+ }
100
+ await this.updatePackageJson();
101
+ await this.createNextConfig();
102
+ await this.updateGitIgnore();
103
+ await this.createPages();
102
104
  }
103
105
  checkForYarn() {
104
106
  try {
@@ -129,112 +131,111 @@ class CraTransform {
129
131
  console.log(...args);
130
132
  }
131
133
  }
132
- createPages() {
133
- return __awaiter(this, void 0, void 0, function* () {
134
- // load public/index.html and add tags to _document
135
- const htmlContent = yield fs_1.default.promises.readFile(path_1.default.join(this.appDir, `${this.isCra ? 'public/' : ''}index.html`), 'utf8');
136
- const $ = cheerio_1.default.load(htmlContent);
137
- // note: title tag and meta[viewport] needs to be placed in _app
138
- // not _document
139
- const titleTag = $('title')[0];
140
- const metaViewport = $('meta[name="viewport"]')[0];
141
- const headTags = $('head').children();
142
- const bodyTags = $('body').children();
143
- const pageExt = this.shouldUseTypeScript ? 'tsx' : 'js';
144
- const appPage = path_1.default.join(this.pagesDir, `_app.${pageExt}`);
145
- const documentPage = path_1.default.join(this.pagesDir, `_document.${pageExt}`);
146
- const catchAllPage = path_1.default.join(this.pagesDir, `[[...slug]].${pageExt}`);
147
- const gatherTextChildren = (children) => {
148
- return children
149
- .map((child) => {
150
- if (child.type === 'text') {
151
- return child.data;
152
- }
153
- return '';
154
- })
155
- .join('');
156
- };
157
- const serializeAttrs = (attrs) => {
158
- const attrStr = Object.keys(attrs || {})
159
- .map((name) => {
160
- const reactName = html_to_react_attributes_1.default[name] || name;
161
- const value = attrs[name];
162
- // allow process.env access to work dynamically still
163
- if (value.match(/%([a-zA-Z0-9_]{0,})%/)) {
164
- return `${reactName}={\`${value.replace(/%([a-zA-Z0-9_]{0,})%/g, (subStr) => {
165
- return `\${process.env.${subStr.slice(1, -1)}}`;
166
- })}\`}`;
167
- }
168
- return `${reactName}="${value}"`;
169
- })
170
- .join(' ');
171
- return attrStr.length > 0 ? ` ${attrStr}` : '';
172
- };
173
- const serializedHeadTags = [];
174
- const serializedBodyTags = [];
175
- headTags.map((_index, element) => {
176
- if (element.tagName === 'title' ||
177
- (element.tagName === 'meta' && element.attribs.name === 'viewport')) {
178
- return element;
134
+ async createPages() {
135
+ // load public/index.html and add tags to _document
136
+ const htmlContent = await fs_1.default.promises.readFile(path_1.default.join(this.appDir, `${this.isCra ? 'public/' : ''}index.html`), 'utf8');
137
+ const $ = cheerio_1.default.load(htmlContent);
138
+ // note: title tag and meta[viewport] needs to be placed in _app
139
+ // not _document
140
+ const titleTag = $('title')[0];
141
+ const metaViewport = $('meta[name="viewport"]')[0];
142
+ const headTags = $('head').children();
143
+ const bodyTags = $('body').children();
144
+ const pageExt = this.shouldUseTypeScript ? 'tsx' : 'js';
145
+ const appPage = path_1.default.join(this.pagesDir, `_app.${pageExt}`);
146
+ const documentPage = path_1.default.join(this.pagesDir, `_document.${pageExt}`);
147
+ const catchAllPage = path_1.default.join(this.pagesDir, `[[...slug]].${pageExt}`);
148
+ const gatherTextChildren = (children) => {
149
+ return children
150
+ .map((child) => {
151
+ if (child.type === 'text') {
152
+ return child.data;
179
153
  }
180
- let hasChildren = element.children.length > 0;
181
- let serializedAttrs = serializeAttrs(element.attribs);
182
- if (element.tagName === 'script' || element.tagName === 'style') {
183
- hasChildren = false;
184
- serializedAttrs += ` dangerouslySetInnerHTML={{ __html: \`${gatherTextChildren(element.children).replace(/`/g, '\\`')}\` }}`;
154
+ return '';
155
+ })
156
+ .join('');
157
+ };
158
+ const serializeAttrs = (attrs) => {
159
+ const attrStr = Object.keys(attrs || {})
160
+ .map((name) => {
161
+ const reactName = html_to_react_attributes_1.default[name] || name;
162
+ const value = attrs[name];
163
+ // allow process.env access to work dynamically still
164
+ if (value.match(/%([a-zA-Z0-9_]{0,})%/)) {
165
+ return `${reactName}={\`${value.replace(/%([a-zA-Z0-9_]{0,})%/g, (subStr) => {
166
+ return `\${process.env.${subStr.slice(1, -1)}}`;
167
+ })}\`}`;
185
168
  }
186
- serializedHeadTags.push(hasChildren
187
- ? `<${element.tagName}${serializedAttrs}>${gatherTextChildren(element.children)}</${element.tagName}>`
188
- : `<${element.tagName}${serializedAttrs} />`);
169
+ return `${reactName}="${value}"`;
170
+ })
171
+ .join(' ');
172
+ return attrStr.length > 0 ? ` ${attrStr}` : '';
173
+ };
174
+ const serializedHeadTags = [];
175
+ const serializedBodyTags = [];
176
+ headTags.map((_index, element) => {
177
+ if (element.tagName === 'title' ||
178
+ (element.tagName === 'meta' && element.attribs.name === 'viewport')) {
189
179
  return element;
190
- });
191
- bodyTags.map((_index, element) => {
192
- if (element.tagName === 'div' && element.attribs.id === 'root') {
193
- return element;
194
- }
195
- let hasChildren = element.children.length > 0;
196
- let serializedAttrs = serializeAttrs(element.attribs);
197
- if (element.tagName === 'script' || element.tagName === 'style') {
198
- hasChildren = false;
199
- serializedAttrs += ` dangerouslySetInnerHTML={{ __html: \`${gatherTextChildren(element.children).replace(/`/g, '\\`')}\` }}`;
200
- }
201
- serializedHeadTags.push(hasChildren
202
- ? `<${element.tagName}${serializedAttrs}>${gatherTextChildren(element.children)}</${element.tagName}>`
203
- : `<${element.tagName}${serializedAttrs} />`);
180
+ }
181
+ let hasChildren = element.children.length > 0;
182
+ let serializedAttrs = serializeAttrs(element.attribs);
183
+ if (element.tagName === 'script' || element.tagName === 'style') {
184
+ hasChildren = false;
185
+ serializedAttrs += ` dangerouslySetInnerHTML={{ __html: \`${gatherTextChildren(element.children).replace(/`/g, '\\`')}\` }}`;
186
+ }
187
+ serializedHeadTags.push(hasChildren
188
+ ? `<${element.tagName}${serializedAttrs}>${gatherTextChildren(element.children)}</${element.tagName}>`
189
+ : `<${element.tagName}${serializedAttrs} />`);
190
+ return element;
191
+ });
192
+ bodyTags.map((_index, element) => {
193
+ if (element.tagName === 'div' && element.attribs.id === 'root') {
204
194
  return element;
205
- });
206
- if (!this.isDryRun) {
207
- yield fs_1.default.promises.writeFile(path_1.default.join(this.appDir, appPage), `${global_css_transform_1.globalCssContext.cssImports.size === 0
208
- ? ''
209
- : [...global_css_transform_1.globalCssContext.cssImports]
210
- .map((file) => {
211
- if (!this.isCra) {
212
- file = file.startsWith('/') ? file.slice(1) : file;
213
- }
214
- return `import '${file.startsWith('/')
215
- ? path_1.default.relative(path_1.default.join(this.appDir, this.pagesDir), file)
216
- : file}'`;
217
- })
218
- .join('\n') + '\n'}${titleTag ? `import Head from 'next/head'` : ''}
195
+ }
196
+ let hasChildren = element.children.length > 0;
197
+ let serializedAttrs = serializeAttrs(element.attribs);
198
+ if (element.tagName === 'script' || element.tagName === 'style') {
199
+ hasChildren = false;
200
+ serializedAttrs += ` dangerouslySetInnerHTML={{ __html: \`${gatherTextChildren(element.children).replace(/`/g, '\\`')}\` }}`;
201
+ }
202
+ serializedHeadTags.push(hasChildren
203
+ ? `<${element.tagName}${serializedAttrs}>${gatherTextChildren(element.children)}</${element.tagName}>`
204
+ : `<${element.tagName}${serializedAttrs} />`);
205
+ return element;
206
+ });
207
+ if (!this.isDryRun) {
208
+ await fs_1.default.promises.writeFile(path_1.default.join(this.appDir, appPage), `${global_css_transform_1.globalCssContext.cssImports.size === 0
209
+ ? ''
210
+ : [...global_css_transform_1.globalCssContext.cssImports]
211
+ .map((file) => {
212
+ if (!this.isCra) {
213
+ file = file.startsWith('/') ? file.slice(1) : file;
214
+ }
215
+ return `import '${file.startsWith('/')
216
+ ? path_1.default.relative(path_1.default.join(this.appDir, this.pagesDir), file)
217
+ : file}'`;
218
+ })
219
+ .join('\n') + '\n'}${titleTag ? `import Head from 'next/head'` : ''}
219
220
 
220
221
  export default function MyApp({ Component, pageProps}) {
221
222
  ${titleTag || metaViewport
222
- ? `return (
223
+ ? `return (
223
224
  <>
224
225
  <Head>
225
226
  ${titleTag
226
- ? `<title${serializeAttrs(titleTag.attribs)}>${gatherTextChildren(titleTag.children)}</title>`
227
- : ''}
227
+ ? `<title${serializeAttrs(titleTag.attribs)}>${gatherTextChildren(titleTag.children)}</title>`
228
+ : ''}
228
229
  ${metaViewport ? `<meta${serializeAttrs(metaViewport.attribs)} />` : ''}
229
230
  </Head>
230
231
 
231
232
  <Component {...pageProps} />
232
233
  </>
233
234
  )`
234
- : 'return <Component {...pageProps} />'}
235
+ : 'return <Component {...pageProps} />'}
235
236
  }
236
237
  `);
237
- yield fs_1.default.promises.writeFile(path_1.default.join(this.appDir, documentPage), `import Document, { Html, Head, Main, NextScript } from 'next/document'
238
+ await fs_1.default.promises.writeFile(path_1.default.join(this.appDir, documentPage), `import Document, { Html, Head, Main, NextScript } from 'next/document'
238
239
 
239
240
  class MyDocument extends Document {
240
241
  render() {
@@ -256,11 +257,11 @@ class MyDocument extends Document {
256
257
 
257
258
  export default MyDocument
258
259
  `);
259
- const relativeIndexPath = path_1.default.relative(path_1.default.join(this.appDir, this.pagesDir), path_1.default.join(this.appDir, 'src', this.isCra ? '' : 'main'));
260
- // TODO: should we default to ssr: true below and recommend they
261
- // set it to false if they encounter errors or prefer the more safe
262
- // option to prevent their first start from having any errors?
263
- yield fs_1.default.promises.writeFile(path_1.default.join(this.appDir, catchAllPage), `// import NextIndexWrapper from '${relativeIndexPath}'
260
+ const relativeIndexPath = path_1.default.relative(path_1.default.join(this.appDir, this.pagesDir), path_1.default.join(this.appDir, 'src', this.isCra ? '' : 'main'));
261
+ // TODO: should we default to ssr: true below and recommend they
262
+ // set it to false if they encounter errors or prefer the more safe
263
+ // option to prevent their first start from having any errors?
264
+ await fs_1.default.promises.writeFile(path_1.default.join(this.appDir, catchAllPage), `// import NextIndexWrapper from '${relativeIndexPath}'
264
265
 
265
266
  // next/dynamic is used to prevent breaking incompatibilities
266
267
  // with SSR from window.SOME_VAR usage, if this is not used
@@ -276,90 +277,95 @@ export default function Page(props) {
276
277
  return <NextIndexWrapper {...props} />
277
278
  }
278
279
  `);
279
- }
280
- this.logCreate(appPage);
281
- this.logCreate(documentPage);
282
- this.logCreate(catchAllPage);
283
- });
280
+ }
281
+ this.logCreate(appPage);
282
+ this.logCreate(documentPage);
283
+ this.logCreate(catchAllPage);
284
284
  }
285
- updatePackageJson() {
286
- return __awaiter(this, void 0, void 0, function* () {
287
- // rename react-scripts -> next and react-scripts test -> jest
288
- // add needed dependencies for webpack compatibility
289
- const newDependencies = [
290
- // TODO: do we want to install jest automatically?
291
- {
292
- name: 'next',
293
- version: 'latest',
294
- },
295
- ];
296
- const packageName = this.isCra ? 'react-scripts' : 'vite';
297
- const packagesToRemove = {
298
- [packageName]: undefined,
299
- };
300
- const neededDependencies = [];
301
- const { devDependencies, dependencies, scripts } = this.packageJsonData;
302
- for (const dep of newDependencies) {
303
- if (!(devDependencies === null || devDependencies === void 0 ? void 0 : devDependencies[dep.name]) && !(dependencies === null || dependencies === void 0 ? void 0 : dependencies[dep.name])) {
304
- neededDependencies.push(`${dep.name}@${dep.version}`);
305
- }
285
+ async updatePackageJson() {
286
+ // rename react-scripts -> next and react-scripts test -> jest
287
+ // add needed dependencies for webpack compatibility
288
+ const newDependencies = [
289
+ // TODO: do we want to install jest automatically?
290
+ {
291
+ name: 'next',
292
+ version: 'latest',
293
+ },
294
+ ];
295
+ const packageName = this.isCra ? 'react-scripts' : 'vite';
296
+ const packagesToRemove = {
297
+ [packageName]: undefined,
298
+ };
299
+ const neededDependencies = [];
300
+ const { devDependencies, dependencies, scripts } = this.packageJsonData;
301
+ for (const dep of newDependencies) {
302
+ if (!devDependencies?.[dep.name] && !dependencies?.[dep.name]) {
303
+ neededDependencies.push(`${dep.name}@${dep.version}`);
306
304
  }
307
- this.logInfo(`Installing ${neededDependencies.join(' ')} with ${this.installClient}`);
308
- if (!this.isDryRun) {
309
- yield fs_1.default.promises.writeFile(this.packageJsonPath, JSON.stringify(Object.assign(Object.assign({}, this.packageJsonData), { scripts: Object.keys(scripts).reduce((prev, cur) => {
310
- const command = scripts[cur];
311
- prev[cur] = command;
312
- if (command === packageName) {
313
- prev[cur] = 'next dev';
314
- }
315
- if (command.includes(`${packageName} `)) {
316
- prev[cur] = command.replace(`${packageName} `, command.includes(`${packageName} test`) ? 'jest ' : 'next ');
317
- }
318
- if (cur === 'eject') {
319
- prev[cur] = undefined;
320
- }
321
- // TODO: do we want to map start -> next start instead of CRA's
322
- // default of mapping starting to dev mode?
323
- if (cur === 'start') {
324
- prev[cur] = prev[cur].replace('next start', 'next dev');
325
- prev['start-production'] = 'next start';
326
- }
327
- return prev;
328
- }, {}), dependencies: Object.assign(Object.assign({}, dependencies), packagesToRemove), devDependencies: Object.assign(Object.assign({}, devDependencies), packagesToRemove) }), null, 2));
329
- yield (0, install_1.install)(this.appDir, neededDependencies, {
330
- useYarn: this.installClient === 'yarn',
331
- // do we want to detect offline as well? they might not
332
- // have next in the local cache already
333
- isOnline: true,
334
- });
335
- }
336
- });
337
- }
338
- updateGitIgnore() {
339
- return __awaiter(this, void 0, void 0, function* () {
340
- // add Next.js specific items to .gitignore e.g. '.next'
341
- const gitignorePath = path_1.default.join(this.appDir, '.gitignore');
342
- let ignoreContent = yield fs_1.default.promises.readFile(gitignorePath, 'utf8');
343
- const nextIgnores = (yield fs_1.default.promises.readFile(path_1.default.join(path_1.default.dirname(globalCssTransformPath), 'gitignore'), 'utf8')).split('\n');
344
- if (!this.isDryRun) {
345
- for (const ignore of nextIgnores) {
346
- if (!ignoreContent.includes(ignore)) {
347
- ignoreContent += `\n${ignore}`;
305
+ }
306
+ this.logInfo(`Installing ${neededDependencies.join(' ')} with ${this.installClient}`);
307
+ if (!this.isDryRun) {
308
+ await fs_1.default.promises.writeFile(this.packageJsonPath, JSON.stringify({
309
+ ...this.packageJsonData,
310
+ scripts: Object.keys(scripts).reduce((prev, cur) => {
311
+ const command = scripts[cur];
312
+ prev[cur] = command;
313
+ if (command === packageName) {
314
+ prev[cur] = 'next dev';
315
+ }
316
+ if (command.includes(`${packageName} `)) {
317
+ prev[cur] = command.replace(`${packageName} `, command.includes(`${packageName} test`) ? 'jest ' : 'next ');
318
+ }
319
+ if (cur === 'eject') {
320
+ prev[cur] = undefined;
348
321
  }
322
+ // TODO: do we want to map start -> next start instead of CRA's
323
+ // default of mapping starting to dev mode?
324
+ if (cur === 'start') {
325
+ prev[cur] = prev[cur].replace('next start', 'next dev');
326
+ prev['start-production'] = 'next start';
327
+ }
328
+ return prev;
329
+ }, {}),
330
+ dependencies: {
331
+ ...dependencies,
332
+ ...packagesToRemove,
333
+ },
334
+ devDependencies: {
335
+ ...devDependencies,
336
+ ...packagesToRemove,
337
+ },
338
+ }, null, 2));
339
+ await (0, install_1.install)(this.appDir, neededDependencies, {
340
+ useYarn: this.installClient === 'yarn',
341
+ // do we want to detect offline as well? they might not
342
+ // have next in the local cache already
343
+ isOnline: true,
344
+ });
345
+ }
346
+ }
347
+ async updateGitIgnore() {
348
+ // add Next.js specific items to .gitignore e.g. '.next'
349
+ const gitignorePath = path_1.default.join(this.appDir, '.gitignore');
350
+ let ignoreContent = await fs_1.default.promises.readFile(gitignorePath, 'utf8');
351
+ const nextIgnores = (await fs_1.default.promises.readFile(path_1.default.join(path_1.default.dirname(globalCssTransformPath), 'gitignore'), 'utf8')).split('\n');
352
+ if (!this.isDryRun) {
353
+ for (const ignore of nextIgnores) {
354
+ if (!ignoreContent.includes(ignore)) {
355
+ ignoreContent += `\n${ignore}`;
349
356
  }
350
- yield fs_1.default.promises.writeFile(gitignorePath, ignoreContent);
351
357
  }
352
- this.logModify('.gitignore');
353
- });
358
+ await fs_1.default.promises.writeFile(gitignorePath, ignoreContent);
359
+ }
360
+ this.logModify('.gitignore');
354
361
  }
355
- createNextConfig() {
356
- return __awaiter(this, void 0, void 0, function* () {
357
- if (!this.isDryRun) {
358
- const { proxy, homepage } = this.packageJsonData;
359
- const homepagePath = new URL(homepage || '/', 'http://example.com')
360
- .pathname;
361
- yield fs_1.default.promises.writeFile(path_1.default.join(this.appDir, 'next.config.js'), `module.exports = {${proxy
362
- ? `
362
+ async createNextConfig() {
363
+ if (!this.isDryRun) {
364
+ const { proxy, homepage } = this.packageJsonData;
365
+ const homepagePath = new URL(homepage || '/', 'http://example.com')
366
+ .pathname;
367
+ await fs_1.default.promises.writeFile(path_1.default.join(this.appDir, 'next.config.js'), `module.exports = {${proxy
368
+ ? `
363
369
  async rewrites() {
364
370
  return {
365
371
  fallback: [
@@ -370,7 +376,7 @@ export default function Page(props) {
370
376
  ]
371
377
  }
372
378
  },`
373
- : ''}
379
+ : ''}
374
380
  env: {
375
381
  PUBLIC_URL: '${homepagePath === '/' ? '' : homepagePath || ''}'
376
382
  },
@@ -384,9 +390,8 @@ export default function Page(props) {
384
390
  }
385
391
  }
386
392
  `);
387
- }
388
- this.logCreate('next.config.js');
389
- });
393
+ }
394
+ this.logCreate('next.config.js');
390
395
  }
391
396
  getPagesDir() {
392
397
  // prefer src/pages as CRA uses the src dir by default
@@ -428,17 +433,14 @@ export default function Page(props) {
428
433
  return appDir;
429
434
  }
430
435
  }
431
- function transformer(files, flags) {
432
- return __awaiter(this, void 0, void 0, function* () {
433
- try {
434
- const craTransform = new CraTransform(files, flags);
435
- yield craTransform.transform();
436
- console.log(`CRA to Next.js migration complete`, `\n${feedbackMessage}`);
437
- }
438
- catch (err) {
439
- fatalMessage(`Error: failed to complete transform`, err);
440
- }
441
- });
436
+ async function transformer(files, flags) {
437
+ try {
438
+ const craTransform = new CraTransform(files, flags);
439
+ await craTransform.transform();
440
+ console.log(`CRA to Next.js migration complete`, `\n${feedbackMessage}`);
441
+ }
442
+ catch (err) {
443
+ fatalMessage(`Error: failed to complete transform`, err);
444
+ }
442
445
  }
443
- exports.default = transformer;
444
446
  //# sourceMappingURL=cra-to-next.js.map
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = transform;
4
+ const next_async_dynamic_prop_1 = require("./next-async-dynamic-prop");
5
+ const next_async_dynamic_api_1 = require("./next-async-dynamic-api");
6
+ function transform(file, api) {
7
+ const transforms = [next_async_dynamic_prop_1.transformDynamicProps, next_async_dynamic_api_1.transformDynamicAPI];
8
+ return transforms.reduce((source, transformFn) => {
9
+ const result = transformFn(source, api, file.path);
10
+ if (!result) {
11
+ return source;
12
+ }
13
+ return result;
14
+ }, file.source);
15
+ }
16
+ //# sourceMappingURL=index.js.map