This article is part of the Converting Large Codebase Project to Vite series.
All files that contains JSX code and had ".js" extension failed in the browser.
This happened because the react swc vite plugin does not compile ".js" files. Instead it send them to the browser as is.
const transformWithOptions = async (
id: string,
code: string,
target: JscTarget,
options: Options,
reactConfig: ReactConfig,
) => {
const decorators = options?.tsDecorators ?? false;
const parser: ParserConfig | undefined = id.endsWith(".tsx")
? { syntax: "typescript", tsx: true, decorators }
: id.endsWith(".ts")
? { syntax: "typescript", tsx: false, decorators }
: id.endsWith(".jsx")
? { syntax: "ecmascript", jsx: true }
: id.endsWith(".mdx")
? // JSX is required to trigger fast refresh transformations, even if MDX already transforms it
{ syntax: "ecmascript", jsx: true }
: undefined;
if (!parser) return;
let result: Output;
try {
result = await transform(code, {
filename: id,
swcrc: false,
configFile: false,
sourceMaps: true,
jsc: {
target,
parser,
experimental: { plugins: options.plugins },
transform: {
useDefineForClassFields: true,
react: reactConfig,
},
},
});
That is an explicit decision made by the plugin authors.
Chosen Solution
So in order to have the plugin take all those files and transpile them with SWC, we had to change the extension all of "js/ts" files that contains JSX to "jsx/tsx" equivalent extension.
Without a transpiler in the process, the jsx left as is:
https://github.com/vitejs/vite/discussions/3448
The conversion process can be done in several ways. One of them is using a script to go though all project "js/ts" files, detect if they have any JSX syntax and change their extension.
An example of such script taken from comment in one of the issues:
find src -type f | grep "\.[jt]s$" | xargs -n1 grep -HE "(<\/)|(\/>)" | cut -d: -f1 | uniq | awk '{print "mv "$1" "$1"x"}' | sh
Breakdown of Script
list All Files Nested in a Target Folder
find src -type f
find - This command searches for all files (-type f) within the src directory and its subdirectories.
The output is a list of the filenames, include their paths.
./docs/.eslintrc.cjs
./docs/tsconfig.json
./docs/.storybook/main.js
./docs/package.json
./docs/stories/button.stories.ts
Filter Out Only Needed Files By Extension
| grep "\.[jt]s$"
The pipe | takes the output of the find command and passes it to grep.
grep - grep ".[jt]s$" filters the files, keeping only those whose names that end with .js or .ts (JavaScript or TypeScript files). for the grep patterns basic regex can be used as default.
the output is the same format of file paths and names, but filtered only to the files end with js/ts extensions.
./docs/.storybook/main.js
./docs/stories/button.stories.ts
Filter Out Files by Existence of Jsx Content Inside Them
| xargs -n1 grep -HE "(<\/)|(\/>)"
xargs -n1
takes each file name from the previous output one by one and executes the following grep command.
grep -HE "(<\/)|(\/>)"
searches for the pattern </ or /> in each file.
-H
includes the filename of the file grep searched in, in the output,
-E
allows for extended regular expressions syntax.
./docs/stories/button.stories.ts: </Button>
Split the Output and Keep Only the File Names
| cut -d: -f1
cut - remove sections from each line of files
-d:
splits the output by the :
delimiter. The previous grep
output it to separate the file and the content found.
-f1
keeps only the first field, which is the filename.
This removes the line number and matched text from the grep output, leaving only the unique filenames.
./docs/stories/button.stories.ts
Reduce the File List to Unique File Names
| uniq
uniq filters out any duplicate filenames, so each filename appears only once.
./docs/stories/button.stories.ts
Construct a Rename
Command for the Specific File Name
| awk '{print "mv "$1" "$1"x"}'
awk constructs a mv (move) command for each file.
It renames each file by appending an "x" to its name.
mv ./docs/stories/button.stories.ts ./docs/stories/button.stories.tsx
Execute the Rename
Command
| sh
`
The final | sh
executes the constructed mv
commands in the shell, renaming the files.
Process
On a large project, you will want to do this conversion in several PRs and not one big chunk, so not to create large conflicts with other people ongoing work.
Top comments (0)