Skip to content
This repository has been archived by the owner on Jan 16, 2025. It is now read-only.

Commit

Permalink
Merge pull request #19 from kherock/fix-sourcemaps
Browse files Browse the repository at this point in the history
Refactor swc CLI
  • Loading branch information
kdy1 authored Feb 25, 2021
2 parents c456493 + d8baed7 commit bc78609
Show file tree
Hide file tree
Showing 11 changed files with 389 additions and 502 deletions.
3 changes: 2 additions & 1 deletion examples/spack-node-modules/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@swc/cli": "file:../.."
"@swc/cli": "file:../..",
"path": "^0.12.7"
}
}
32 changes: 15 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,34 @@
"url": "https://github.com/swc-project/cli/issues"
},
"homepage": "https://github.com/swc-project/cli#readme",
"engines": {
"node": ">= 12.13"
},
"peerDependencies": {
"@swc/core": "^1.2.4"
"@swc/core": "^1.2.4",
"chokidar": "^3.0.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
},
"devDependencies": {
"@swc/core": "^1.2.4",
"@types/commander": "^2.12.2",
"@types/convert-source-map": "^1.5.1",
"@types/fs-readdir-recursive": "^1.0.0",
"@types/glob": "^7.1.2",
"@types/interpret": "^1.1.1",
"@types/lodash": "^4.14.155",
"@types/mkdirp": "^0.5.2",
"@types/node": "^10.12.18",
"@types/rechoir": "^0.6.1",
"@types/slash": "^2.0.0",
"@types/node": "^12.19.16",
"chokidar": "^3.5.1",
"jest": "^24.1.0",
"typescript": "^3.9.5"
"typescript": "~4.1.5"
},
"dependencies": {
"commander": "^2.19.0",
"commander": "^7.1.0",
"convert-source-map": "^1.6.0",
"fs-readdir-recursive": "^1.1.0",
"glob": "^7.1.3",
"interpret": "^2.2.0",
"lodash": "^4.17.11",
"mkdirp": "^0.5.1",
"output-file-sync": "^2.0.1",
"path": "^0.12.7",
"rechoir": "^0.7.0",
"slash": "^2.0.0",
"slash": "3.0.0",
"source-map": "^0.7.3"
},
"bin": {
Expand Down
6 changes: 0 additions & 6 deletions src/spack/extensions.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/spack/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { bundle } from '@swc/core';
import { mkdir, writeFile } from 'fs';
import { findLastIndex } from 'lodash';
import { basename, dirname, extname, join, relative } from 'path'
import { promisify } from 'util';

Expand Down
4 changes: 0 additions & 4 deletions src/spack/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import { BundleOptions, compileBundleOptions } from "@swc/core/spack";
import commander from "commander";
import * as path from 'path';

import { prepare } from 'rechoir'
import { extensions } from './extensions';

const pkg = require("../../package.json");

export interface SpackCliOptions {
Expand All @@ -20,7 +17,6 @@ commander.option("--mode <development | production | none>", "Mode to use");
commander.option(
'--context [path]', ` The base directory (absolute path!) for resolving the 'entry'`
+ ` option. If 'output.pathinfo' is set, the included pathinfo is shortened to this directory`,
undefined,
'The current directory'
);

Expand Down
268 changes: 91 additions & 177 deletions src/swc/dir.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import * as swc from "@swc/core";
import fs from "fs";
import { ceil } from "lodash";
import defaults from "lodash/defaults";
import { sync as mkdirpSync } from "mkdirp";
// @ts-ignore
import outputFileSync from "output-file-sync";
import path from "path";
import slash from "slash";

Expand All @@ -16,202 +12,120 @@ export default async function ({
swcOptions
}: {
cliOptions: CliOptions;
swcOptions: swc.Config;
swcOptions: swc.Options;
}) {
const filenames = cliOptions.filenames;

/**
* Returns `undefined` if a file is ignored.
* Removes the leading directory, including all parent relative paths
*/
async function write(src: string, base: string): Promise<boolean | undefined> {
let relative = path.relative(base, src);

if (!util.isCompilableExtension(relative, cliOptions.extensions)) {
return undefined;
function stripComponents(filename: string) {
const components = filename.split('/').slice(1);
if (!components.length) {
return filename;
}

// remove extension and then append back on .js
relative = util.adjustRelative(relative, cliOptions.keepFileExtension);

const dest = getDest(relative, base);

try {
const res = await util.compile(
src,
defaults(
{
sourceFileName: slash(path.relative(dest + "/..", src))
},
swcOptions
),
cliOptions.sync
);

if (!res) return false;

let code = res.code;
// we've requested explicit sourcemaps to be written to disk
if (res.map) {
let map = JSON.parse(res.map);

// TODO: Handle inline source map

const mapLoc = dest + ".map";
code = util.addSourceMappingUrl(code, mapLoc);
map.file = path.basename(relative);
outputFileSync(mapLoc, JSON.stringify(map));
}

outputFileSync(dest, code);
util.chmod(src, dest);

if (cliOptions.verbose) {
console.log(src + " -> " + dest);
}

return true;
} catch (err) {
if (cliOptions.watch) {
console.error(err);
return false;
}

throw err;
}
}

function getDest(filename: string, base: string) {
if (cliOptions.relative) {
return path.join(base, cliOptions.outDir, filename);
while (components[0] === '..') {
components.shift();
}
return path.join(cliOptions.outDir, filename);
return components.join('/');
}

/**
* Returns `undefined` if a file is ignored.
*/
async function handleFile(src: string, base: string): Promise<boolean | undefined> {
const written = await write(src, base).catch(e => {
if (e?.toString().includes("ignored by .swcrc")) { return undefined }
throw e;
});

if (written === false && cliOptions.copyFiles) {
const filename = path.relative(base, src);
const dest = getDest(filename, base);
outputFileSync(dest, fs.readFileSync(src));
util.chmod(src, dest);
function getDest(filename: string, ext?: string) {
const relative = slash(path.relative(process.cwd(), filename));
let base = stripComponents(relative);
if (ext) {
base = base.replace(/\.\w*$/, ext);
}
return written;
return path.join(cliOptions.outDir, base);
}

type HandleResult = { succeeded: number; failed: number }

async function handle(filenameOrDir: string): Promise<HandleResult> {
if (!fs.existsSync(filenameOrDir)) return { succeeded: 0, failed: 0 };
const stat = fs.statSync(filenameOrDir);

if (stat.isDirectory()) {
const dirname = filenameOrDir;
async function handle(filename: string) {
if (util.isCompilableExtension(filename, cliOptions.extensions)) {
const dest = getDest(filename, ".js");
const sourceFileName = slash(path.relative(path.dirname(dest), filename));

let succeeded = 0;
let failed = 0;

const files = util.readdir(dirname, cliOptions.includeDotfiles);

await Promise.all(
files.map(async (filename: string) => {
const src = path.join(dirname, filename);
try {
const written = await handleFile(src, dirname);
if (written) {
succeeded += 1;
} else if (written === false) {
failed += 1;
}
} catch (e) {
console.error(e);
failed += 1;
}
})
const result = await util.compile(
filename,
defaults({ sourceFileName }, swcOptions),
cliOptions.sync
);

return { succeeded, failed };
} else {
const filename = filenameOrDir;
const written = await handleFile(filename, path.dirname(filename));

return {
succeeded: written ? 1 : 0,
failed: written === false ? 1 : 0
};

if (result) {
util.outputFile(result, dest, swcOptions.sourceMaps);
util.chmod(filename, dest);
return true;
}
} else if (cliOptions.copyFiles) {
const dest = getDest(filename);
fs.mkdirSync(path.dirname(dest), { recursive: true });
fs.copyFileSync(filename, dest);
return 'copied';
}
return false;
}

if (cliOptions.deleteDirOnStart) {
util.deleteDir(cliOptions.outDir);
fs.rmdirSync(cliOptions.outDir, { recursive: true })
}
mkdirpSync(cliOptions.outDir);

let compiledFiles = 0;
let failedFiles = 0;
fs.mkdirSync(cliOptions.outDir, { recursive: true });

for (const filename of cliOptions.filenames) {
const { succeeded, failed } = await handle(filename);
compiledFiles += succeeded
failedFiles += failed
}

if (!cliOptions.quiet) {
if (compiledFiles > 0) {
console.log(
`Successfully compiled ${compiledFiles} ${compiledFiles !== 1 ? "files" : "file"
} with swc.`
);
}

if (failedFiles > 0) {
const error = `Failed to compile ${failedFiles} ${failedFiles !== 1 ? "files" : "file"
} with swc.`
if (!cliOptions.watch) throw new Error(error)
else console.error(error)
const results = new Map<string, Error | boolean | 'copied'>();
for (const filename of util.globSources(cliOptions.filenames, cliOptions.includeDotfiles)) {
try {
const result = await handle(filename);
if (result !== undefined) {
results.set(filename, result);
}
} catch (err) {
console.error(err.message);
results.set(filename, err);
}
}

if (cliOptions.watch) {
const chokidar = util.requireChokidar();

filenames.forEach(function (filenameOrDir) {
const watcher = chokidar.watch(filenameOrDir, {
persistent: true,
ignoreInitial: true,
awaitWriteFinish: {
stabilityThreshold: 50,
pollInterval: 10
const watcher = util.watchSources(cliOptions.filenames, cliOptions.includeDotfiles);
watcher.on('ready', () => {
try {
util.assertCompilationResult(results, cliOptions.quiet);
if (!cliOptions.quiet) {
console.info('Watching for file changes.')
}
});

["add", "change"].forEach(function (type) {
watcher.on(type, function (filename: string) {
const start = process.hrtime()

handleFile(
filename,
filename === filenameOrDir
? path.dirname(filenameOrDir)
: filenameOrDir
)
.then(ok => {
if (cliOptions.logWatchCompilation && ok) {
const [seconds, nanoseconds] = process.hrtime(start);
const ms = (seconds * 1000000000 + nanoseconds) / 1000000;
const name = path.basename(filename);
console.log(`Compiled ${name} in ${ms.toFixed(2)}ms`);
}
})
.catch(console.error);
});
});
} catch (err) {
console.error(err.message);
}
});
watcher.on('unlink', (filename) => {
try {
if (util.isCompilableExtension(filename, cliOptions.extensions)) {
fs.unlinkSync(getDest(filename, ".js"));
} else if (cliOptions.copyFiles) {
fs.unlinkSync(getDest(filename));
}
} catch (err) {
if (err.code !== 'ENOENT') {
console.error(err.stack);
}
}
});
for (const type of ['add', 'change']) {
watcher.on(type, (filename) => {
const start = process.hrtime()

handle(filename)
.then((result) => {
results.set(filename, result);
if (result && cliOptions.logWatchCompilation) {
const [seconds, nanoseconds] = process.hrtime(start);
const ms = seconds * 1000 + (nanoseconds * 1e-6);
const name = path.basename(filename);
console.log(`${result === "copied" ? "Copied" : "Compiled"} ${name} in ${ms.toFixed(2)}ms`);
}
})
.catch((err) => {
console.error(err.message);
results.set(filename, err);
});
});
}
} else {
util.assertCompilationResult(results, cliOptions.quiet);
}
}
Loading

0 comments on commit bc78609

Please sign in to comment.