protobuf-ts icon indicating copy to clipboard operation
protobuf-ts copied to clipboard

add enable_import_extensions option

Open nvandamme opened this issue 2 years ago • 13 comments

nvandamme avatar Feb 27 '22 22:02 nvandamme

Thanks for this, Nicolas!

I think that CI fails because the old TypeScript version being used doesn't understand .js extensions in import statements.

If you were to bump TypeScript in packages/test-generated/package.json to a recent version, I think test-generated should pass, which will be a good proof that it works. Would you like to do so?

CI failure log:

@protobuf-ts/test-generated: Error: Cannot find module './google/protobuf/empty.js'
@protobuf-ts/test-generated: Require stack:
@protobuf-ts/test-generated: - /home/circleci/project/packages/test-generated/ts-out/exclude-options.ts
@protobuf-ts/test-generated: - /home/circleci/project/packages/test-generated/spec/exclude-options.spec.ts
@protobuf-ts/test-generated: - /home/circleci/project/packages/test-generated/node_modules/jasmine/lib/jasmine.js
@protobuf-ts/test-generated: - /home/circleci/project/packages/test-generated/node_modules/jasmine/bin/jasmine.js
@protobuf-ts/test-generated:     at Function.Module._resolveFilename (internal/modules/cjs/loader.js:1030:15)
@protobuf-ts/test-generated:     at Function.Module._resolveFilename (/home/circleci/project/packages/test-generated/node_modules/tsconfig-paths/lib/register.js:75:40)
@protobuf-ts/test-generated:     at Function.Module._load (internal/modules/cjs/loader.js:899:27)
@protobuf-ts/test-generated:     at Module.require (internal/modules/cjs/loader.js:1090:19)
@protobuf-ts/test-generated:     at require (internal/modules/cjs/helpers.js:75:18)
@protobuf-ts/test-generated:     at Object.<anonymous> (/home/circleci/project/packages/test-generated/ts-out/exclude-options.ts:4:1)
@protobuf-ts/test-generated:     at Module._compile (internal/modules/cjs/loader.js:1201:30)
@protobuf-ts/test-generated:     at Module.m._compile (/home/circleci/project/packages/test-generated/node_modules/ts-node/src/index.ts:858:23)
@protobuf-ts/test-generated:     at Module._extensions..js (internal/modules/cjs/loader.js:1221:10)
@protobuf-ts/test-generated:     at Object.require.extensions.<computed> [as .ts] (/home/circleci/project/packages/test-generated/node_modules/ts-node/src/index.ts:861:12)
@protobuf-ts/test-generated: Makefile:45: recipe for target 'test-spec' failed

timostamm avatar Feb 28 '22 08:02 timostamm

Hi @timostamm ,

Thanks for the feedback, sure!

For now, i'm using a quick'n dirty script on my side to ensure all local imports has an extension. This script is ran after protobuf-ts generation on all *.ts and *.js generated files :

import * as fs from "fs";
import glob from "glob";

function add_import_extensions(er, files) {
    files.forEach(file => {
        let data = fs.readFileSync(file, {encoding: "utf8"});
        data = data.replace(/from\ "\.\/(((?!\.js).)*)";$/gm, "from \"./$1.js\";");
        data = data.replace(/from\ "\.\.\/(((?!\.js).)*)";$/gm, "from \"../$1.js\";");
        fs.writeFileSync(file, data);
    });
}

glob("./api/js/**/*.ts", {}, add_import_extensions);
glob("./api/js/**/*.js", {}, add_import_extensions);

nvandamme avatar Feb 28 '22 09:02 nvandamme

@nvandamme any updates on this? Since ts 4.7 released this is crucial

debkanchan avatar May 28 '22 05:05 debkanchan

Any update on this? ESM is becoming more widespread so would be nice to have this added.

faustbrian avatar Jul 19 '22 03:07 faustbrian

@timostamm are you happy with this implementation, or are there changes you want performed, I've just hit a case where this is now a blocker, thanks.

sachaw avatar Sep 19 '22 04:09 sachaw

for those who suffers and cannot wait until this gets merged, just run this after generation

// proto-patch.js
import glob from "glob";
import fs from "fs";

const protoRoot = 'srv/proto';

glob(protoRoot + '/**/*.ts', async (err, files) => {
  files.forEach(file => {
    let content = fs.readFileSync(file, 'utf-8');

    content = content.split('\n').map(s => s.replace(/^(import .+? from ["']\..+?)(["'];)$/, '$1.js$2')).join('\n');

    fs.writeFileSync(file, content, 'utf-8')
  });
});

smnbbrv avatar Oct 24 '22 13:10 smnbbrv

any updates?

hugebdu avatar Nov 06 '22 14:11 hugebdu

@timostamm can we move it forward? without .js extension generated imports are broken for now

shrpne avatar Sep 14 '23 12:09 shrpne

@timostamm any update on when this can be merged? What's holding it back at the moment?

bbeesley avatar Oct 26 '23 11:10 bbeesley

@timostamm , if you still cannot get your test pipeline to work with this, please consider releasing this as experimental. You can make it obvious that there is no guarantee, if you name it --experimental_enable_import_extensions for example. The ESM is taking over the world and we all would love this component to come along.

jan-dolejsi avatar Nov 30 '23 15:11 jan-dolejsi

Another version without npm dependencies while we await this feature to get merged. I use it as: buf generate && node ./patch-esm.js && tsc

#! /usr/bin/env node
import fs from 'node:fs';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const currentDir = dirname(fileURLToPath(import.meta.url));

const collectFiles = (directory, fileList = []) => {
    fs.readdirSync(directory)
        .map((innerFile) => `${directory}/${innerFile}`)
        .forEach((file) =>
            fs.statSync(file).isDirectory() ? collectFiles(file, fileList) : fileList.push(file)
        );
    return fileList;
};

const files = collectFiles(`${currentDir}/dist`).filter((file) => file.endsWith('.ts'));

files.forEach((file) => {
    const content = fs.readFileSync(file, 'utf8');
    const updated = content
        .split('\n')
        .map((s) => s.replace(/(} from ["']\..+(?<!\.js))(["'];)$/, '$1.js$2'))
        .join('\n');
    fs.writeFileSync(`${file}`, updated, 'utf-8');
});

nebez avatar Mar 11 '24 21:03 nebez