-
Notifications
You must be signed in to change notification settings - Fork 28.7k
Add experimental cra-to-next transform in codemod cli #24969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
9699ddd
Add initial cra-to-next transform in codemod cli
ijjk f011541
add install, ignores, next.config.js
ijjk db2a91f
ensure file-loader is used for SSR as well
ijjk 03e8efa
enable webpack5 by default
ijjk 6cbb24c
Migrate tags from index.html
ijjk 40b0eff
Add note about webpack5 option
ijjk 7b99f2c
handle cases from testing
ijjk cbb8567
only create babelrc when svgr is used
ijjk c3dffcc
fix file-loader compat with webpack 5
ijjk 6df3ba5
Merge remote-tracking branch 'upstream/canary' into feat/cra-to-next-cli
ijjk 6734c30
fix type
ijjk 7e73ec5
update craCompat require from testing
ijjk c17e219
Merge branch 'canary' into feat/cra-to-next-cli
ijjk ff2b505
Merge remote-tracking branch 'upstream/canary' into feat/cra-to-next-cli
ijjk 6547567
Add nested render error
ijjk 1f95e37
Merge remote-tracking branch 'upstream/canary' into feat/cra-to-next-cli
ijjk bd02321
revert test import change
ijjk 4feec9b
Dont allow import {ReactComponent} from "./svg"
ijjk 0df75b0
Merge remote-tracking branch 'upstream/canary' into feat/cra-to-next-cli
ijjk a39265a
Allow global CSS imports in node_modules for compat
ijjk 70565a6
Merge remote-tracking branch 'upstream/canary' into feat/cra-to-next-cli
ijjk 967f33d
Add feedback link
ijjk 6deba72
Merge remote-tracking branch 'upstream/canary' into feat/cra-to-next-cli
ijjk 761309e
Move CRA compat inside webpack-config
ijjk 8254796
Merge remote-tracking branch 'upstream/canary' into feat/cra-to-next-cli
ijjk 226cc02
Update packages/next-codemod/bin/cli.ts
timneutkens 75069e9
Merge branch 'canary' into feat/cra-to-next-cli
kodiakhq[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env.local | ||
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
|
||
# vercel | ||
.vercel |
65 changes: 65 additions & 0 deletions
65
packages/next-codemod/lib/cra-to-next/global-css-transform.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import nodePath from 'path' | ||
import { API, FileInfo, Options } from 'jscodeshift' | ||
|
||
export const globalCssContext = { | ||
cssImports: new Set<string>(), | ||
reactSvgImports: new Set<string>(), | ||
} | ||
const globalStylesRegex = /(?<!\.module)\.(css|scss|sass)$/i | ||
|
||
export default function transformer( | ||
file: FileInfo, | ||
api: API, | ||
options: Options | ||
) { | ||
const j = api.jscodeshift | ||
const root = j(file.source) | ||
let hasModifications = false | ||
|
||
root | ||
.find(j.ImportDeclaration) | ||
.filter((path) => { | ||
const { | ||
node: { | ||
source: { value }, | ||
}, | ||
} = path | ||
|
||
if (typeof value === 'string') { | ||
if (globalStylesRegex.test(value)) { | ||
let resolvedPath = value | ||
|
||
if (value.startsWith('.')) { | ||
resolvedPath = nodePath.resolve(nodePath.dirname(file.path), value) | ||
} | ||
globalCssContext.cssImports.add(resolvedPath) | ||
|
||
const { start, end } = path.node as any | ||
|
||
if (!path.parentPath.node.comments) { | ||
path.parentPath.node.comments = [] | ||
} | ||
|
||
path.parentPath.node.comments = [ | ||
j.commentLine(' ' + file.source.substring(start, end)), | ||
] | ||
hasModifications = true | ||
return true | ||
} else if (value.endsWith('.svg')) { | ||
const isComponentImport = path.node.specifiers.some((specifier) => { | ||
return (specifier as any).imported?.name === 'ReactComponent' | ||
}) | ||
|
||
if (isComponentImport) { | ||
globalCssContext.reactSvgImports.add(file.path) | ||
} | ||
} | ||
} | ||
return false | ||
}) | ||
.remove() | ||
|
||
return hasModifications && globalCssContext.reactSvgImports.size === 0 | ||
? root.toSource(options) | ||
: null | ||
} |
101 changes: 101 additions & 0 deletions
101
packages/next-codemod/lib/cra-to-next/index-to-component.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import { API, FileInfo, JSXElement, Options } from 'jscodeshift' | ||
|
||
export const indexContext = { | ||
multipleRenderRoots: false, | ||
nestedRender: false, | ||
} | ||
|
||
export default function transformer( | ||
file: FileInfo, | ||
api: API, | ||
options: Options | ||
) { | ||
const j = api.jscodeshift | ||
const root = j(file.source) | ||
let hasModifications = false | ||
let foundReactRender = 0 | ||
let hasRenderImport = false | ||
let defaultReactDomImport: string | undefined | ||
|
||
root.find(j.ImportDeclaration).forEach((path) => { | ||
if (path.node.source.value === 'react-dom') { | ||
return path.node.specifiers.forEach((specifier) => { | ||
if (specifier.local.name === 'render') { | ||
hasRenderImport = true | ||
} | ||
if (specifier.type === 'ImportDefaultSpecifier') { | ||
defaultReactDomImport = specifier.local.name | ||
} | ||
}) | ||
} | ||
return false | ||
}) | ||
|
||
root | ||
.find(j.CallExpression) | ||
.filter((path) => { | ||
const { node } = path | ||
let found = false | ||
|
||
if ( | ||
defaultReactDomImport && | ||
node.callee.type === 'MemberExpression' && | ||
(node.callee.object as any).name === defaultReactDomImport && | ||
(node.callee.property as any).name === 'render' | ||
) { | ||
found = true | ||
} | ||
|
||
if (hasRenderImport && (node.callee as any).name === 'render') { | ||
found = true | ||
} | ||
|
||
if (found) { | ||
foundReactRender++ | ||
hasModifications = true | ||
|
||
if (!Array.isArray(path.parentPath?.parentPath?.value)) { | ||
indexContext.nestedRender = true | ||
return false | ||
} | ||
|
||
const newNode = j.exportDefaultDeclaration( | ||
j.functionDeclaration( | ||
j.identifier('NextIndexWrapper'), | ||
[], | ||
j.blockStatement([ | ||
j.returnStatement( | ||
// TODO: remove React.StrictMode wrapper and use | ||
// next.config.js option instead? | ||
path.node.arguments.find( | ||
(a) => a.type === 'JSXElement' | ||
) as JSXElement | ||
), | ||
]) | ||
) | ||
) | ||
|
||
path.parentPath.insertBefore(newNode) | ||
return true | ||
} | ||
return false | ||
}) | ||
.remove() | ||
|
||
indexContext.multipleRenderRoots = foundReactRender > 1 | ||
hasModifications = | ||
hasModifications && | ||
!indexContext.nestedRender && | ||
!indexContext.multipleRenderRoots | ||
|
||
// TODO: move function passed to reportWebVitals if present to | ||
// _app reportWebVitals and massage values to expected shape | ||
|
||
// root.find(j.CallExpression, { | ||
// callee: { | ||
// name: 'reportWebVitals' | ||
// } | ||
// }).remove() | ||
|
||
return hasModifications ? root.toSource(options) : null | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.