xref: /expo/packages/@expo/cli/taskfile-swc.js (revision bb5069cd)
1// Based on Next.js swc taskr file.
2// https://github.com/vercel/next.js/blob/5378db8f807dbb9ff0993662f0a39d0f6cba2452/packages/next/taskfile-swc.js
3
4const path = require('path');
5const assert = require('assert');
6
7const transform = require('@swc/core').transform;
8
9module.exports = function (task) {
10  const ENVIRONMENTS = {
11    // Settings for compiling the CLI code that runs in Node.js environments.
12    cli: {
13      output: 'build',
14      options: {
15        module: {
16          type: 'commonjs',
17        },
18        env: {
19          targets: {
20            node: '12.13.0',
21          },
22        },
23        jsc: {
24          loose: true,
25          parser: {
26            syntax: 'typescript',
27            dynamicImport: true,
28          },
29        },
30      },
31    },
32  };
33  // Like `/^(cli|sdk)$/`
34  const matcher = new RegExp(`^(${Object.keys(ENVIRONMENTS).join('|')})$`);
35
36  task.plugin('swc', {}, function* (file, environment, { stripExtension } = {}) {
37    // Don't compile .d.ts
38    if (file.base.endsWith('.d.ts')) return;
39
40    // Environment assertion
41    assert.match(environment, matcher);
42
43    const setting = ENVIRONMENTS[environment];
44    const filePath = path.join(file.dir, file.base);
45    const inputFilePath = path.join(__dirname, filePath);
46    const outputFilePath = path.dirname(path.join(__dirname, setting.output, filePath));
47
48    const options = {
49      filename: path.join(file.dir, file.base),
50      sourceMaps: true,
51      sourceFileName: path.relative(outputFilePath, inputFilePath),
52      ...setting.options,
53    };
54
55    const output = yield transform(file.data.toString('utf-8'), options);
56    const ext = path.extname(file.base);
57
58    // Replace `.ts|.tsx` with `.js` in files with an extension
59    if (ext) {
60      const extRegex = new RegExp(ext.replace('.', '\\.') + '$', 'i');
61      // Remove the extension if stripExtension is enabled or replace it with `.js`
62      file.base = file.base.replace(extRegex, stripExtension ? '' : '.js');
63    }
64
65    if (output.map) {
66      const map = `${file.base}.map`;
67
68      output.code += Buffer.from(`\n//# sourceMappingURL=${map}`);
69
70      // add sourcemap to `files` array
71      this._.files.push({
72        base: map,
73        dir: file.dir,
74        data: Buffer.from(output.map),
75      });
76    }
77
78    file.data = Buffer.from(setVersionCode(output.code));
79  });
80};
81
82function setVersionCode(code) {
83  return code.replace(/process\.env\.__EXPO_VERSION/g, `"${require('./package.json').version}"`);
84}
85