Skip to content

Instantly share code, notes, and snippets.

@benpolinsky
Last active August 12, 2022 16:19
Show Gist options
  • Save benpolinsky/a968b18b82ae2805f742e3cc04cf9417 to your computer and use it in GitHub Desktop.
Save benpolinsky/a968b18b82ae2805f742e3cc04cf9417 to your computer and use it in GitHub Desktop.
this is a really quick way of gaining ts error reporting with parcel
const Asset = require('parcel/src/Asset');
const chalk = require('chalk')
const ts = require('typescript')
const path = require('path');
const localRequire = require('parcel/src/utils/localRequire')
class TypeScriptAssetWithError extends Asset {
constructor(name, options) {
super(name, options);
this.type = 'js';
}
async generate() {
// require typescript, installed locally in the app
let typescript = await localRequire('typescript', this.name);
let transpilerOptions = {
compilerOptions: {
module: this.options.scopeHoist
? typescript.ModuleKind.ESNext
: typescript.ModuleKind.CommonJS,
jsx: typescript.JsxEmit.Preserve,
// it brings the generated output from TypeScript closer to that generated by Babel
// see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html
esModuleInterop: true
},
fileName: this.relativeName
};
let tsconfig = await this.getConfig(['tsconfig.json']);
// Overwrite default if config is found
if (tsconfig) {
transpilerOptions.compilerOptions = Object.assign(
transpilerOptions.compilerOptions,
tsconfig.compilerOptions
);
}
transpilerOptions.compilerOptions.noEmit = false;
transpilerOptions.compilerOptions.sourceMap = this.options.sourceMaps;
if (!this.options.isWarmUp){
let program = ts.createProgram([path.resolve(this.options.rootDir, this.relativeName)], {...transpilerOptions.compilerOptions, noEmit: true})
let emitResult = program.emit();
let allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics)
ts.sortAndDeduplicateDiagnostics(allDiagnostics).forEach(diagnostic => {
if (path.resolve(diagnostic.file.originalFileName) === path.resolve(this.options.rootDir, this.relativeName)){
if (diagnostic.file) {
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(
diagnostic.start
);
let message = typescript.flattenDiagnosticMessageText(
diagnostic.messageText,
"\n"
);
console.error(
chalk.red(`\n${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`)
);
} else {
console.error(`\n` + "NO FILE")
console.error(
chalk.red(`\n${typescript.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`)
);
}
}
});
}
// Transpile Module using TypeScript and parse result as ast format through babylon
let transpiled = typescript.transpileModule(
this.contents,
transpilerOptions
);
let sourceMap = transpiled.sourceMapText;
if (sourceMap) {
sourceMap = JSON.parse(sourceMap);
sourceMap.sources = [this.relativeName];
sourceMap.sourcesContent = [this.contents];
// Remove the source map URL
let content = transpiled.outputText;
transpiled.outputText = content.substring(
0,
content.lastIndexOf('//# sourceMappingURL')
);
}
return [
{
type: 'js',
value: transpiled.outputText,
sourceMap
}
];
}
}
module.exports = TypeScriptAssetWithError;
@tad-lispy
Copy link

Very nice. Thanks @benpolinsky. Perhaps you could publish it as an alternative to the broken TypeScript plugin?

@cmcaine here is one way to use it:

  1. Make a build/ directory at the root of your project

  2. Put the code provided by Ben in build/TypeScriptAssetWithTypeChecking.js (not .ts - I don't think that could work)

  3. Create build/index.js file with the following:

    const Bundler = require("parcel-bundler");
    const TypeScriptAssetWithTypeChecking = require("./TypeScriptAssetWithTypeChecking");
    
    const options = {
      watch: true,
      target: "browser"
    };
    const entries = "./src/index.html";
    
    const bundler = new Bundler(entries, options);
    bundler.addAssetType(
      ".ts",
      require.resolve("./TypeScriptAssetWithTypeChecking")
    );
    bundler.addAssetType(
      ".tsx",
      require.resolve("./TypeScriptAssetWithTypeChecking")
    );
    
    bundler.serve();

    Adjust to your needs. See https://parceljs.org/api.html and https://parceljs.org/asset_types.html for reference

  4. Instead of running parcel src/index.html run node build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment