Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using ts-nameof with Vue #83

Open
lundmikkel opened this issue Oct 25, 2019 · 11 comments
Open

Using ts-nameof with Vue #83

lundmikkel opened this issue Oct 25, 2019 · 11 comments
Labels

Comments

@lundmikkel
Copy link

I've tried to install the npm package using both npm install ts-nameof @types/ts-nameof --save-dev and npm install @types/ts-nameof --save-dev, and included a reference to ts-nameof in my tsconfig.json like this:

{
  "compilerOptions": {
    "types": [
      "ts-nameof"
    ],
    "typeRoots": [
      "./node_modules/@types/",
    ],
  }
}

But without much luck. Do you have any suggestions as how to continue?

@dsherret
Copy link
Owner

@lundmikkel how are you compiling it? This is a compile time transformation so it needs to get injected into the compiler.

Generally the instructions are: https://github.com/dsherret/ts-nameof/blob/master/packages/ts-nameof/setup/tsc.md (which sucks, but that's the current state of things because compiler plugins aren't supported in tsconfig.json by default)

@Shinigami92
Copy link

In vue.config.js I have

// ... chainWebpack
config.module
    .rule('ts')
    .exclude.add(/node_modules/)
    .end()
    .test(/\.ts$/)
    .use('ts-loader')
    .loader('ts-loader')
    .options({
      transpileOnly: true,
      // Transformer functions do not work with happy pack mode due to process forking, see:
      // https://github.com/TypeStrong/ts-loader#getcustomtransformers--program-program---before-transformerfactory-after-transformerfactory--
      getCustomTransformers: path.resolve(__dirname, 'vue-ts-nameof.js'),
      appendTsSuffixTo: ['\\.vue$'],
      happyPackMode: true
    })
    .end();
// ...

Content of vue-ts-nameof.js

const tsNameof = require('ts-nameof');

module.exports = () => ({
  before: [tsNameof]
});

Hope this can help in any way

@babalubas090
Copy link

In order to make it work you can simply do this:

In vue.config.js you need to add:

const tsNameof = require('ts-nameof');

module.exports = {
  configureWebpack: {
    module: {
      rules: [
        {
          test: /\.ts$/,
          exclude: /node_modules/,
          use: [{
            loader: 'ts-loader',
            options: {
              getCustomTransformers: () => ({ before: [tsNameof] })
            }
          }]
        }
        ...
      ]
    }
    ...
  }
  ...
}

@fairking
Copy link

fairking commented Jul 27, 2020

I tried something like the following but it is not working:

npm install ts-nameof --save-dev

Sample.vue

<template>
    <div>{{myClassName}} - {{nameof<MyClass>()}}<div>
<template>
<script lang="ts">
  import Vue from "vue";
  import { MyClass } from '../../classes';
  export default Vue.extend({
    data() {
      return {
        myClassName: nameof<MyClass>(), // Line 81
      };
    }
});
</script>

vue.config.js:

const tsNameof = require("ts-nameof");
...
module.exports = {
  ...
  configureWebpack: {
    module: {
      rules: [
      {
        test: /\.(ts|vue)$/,
        exclude: /node_modules/,
        use: [{
          loader: 'ts-loader',
          options: {
            getCustomTransformers: () => ({ before: [tsNameof] })
          }
        }]
      }
    ]
  }
  },
  ...
};

Error says:

Error	TS2552	(TS) Cannot find name 'nameof'. Did you mean 'name'?	\src\Sample.vue	81	Active

Do you have any example how to use it in vue? If not maybe with your help I can find out and create a PR with a sample. So others can use it?

@Shinigami92
Copy link

@fairking Have you tried my workaround? #83 (comment)

But I think whithin a template it will never work 🤔

<template>
    <div>{{myClassName}} - {{nameof<MyClass>()}}<div> // <- this one 🤔, you should move this into a variable
<template>

@fairking
Copy link

fairking commented Jul 27, 2020

Tried. Got the following error:

 ERROR  Failed to compile with 1 errors                                                                       8:54:51 AM

 error  in ./src/components/HelloWorld.vue

Module Error (from ./node_modules/eslint-loader/index.js):

C:\Code\vue-ts-nameof-sample\src\components\HelloWorld.vue
  25:28  error  'nameof' is not defined  no-undef
  26:32  error  'nameof' is not defined  no-undef
  27:35  error  'nameof' is not defined  no-undef
  28:27  error  'nameof' is not defined  no-undef
  29:32  error  'nameof' is not defined  no-undef
  30:85  error  'nameof' is not defined  no-undef

✖ 6 problems (6 errors, 0 warnings)


 @ ./node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/babel-loader/lib!./node_modules/ts-loader??ref--14-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=ts& 2:0-53 6:16-26
 @ ./src/App.vue?vue&type=script&lang=ts&
 @ ./src/App.vue
 @ ./src/main.ts
 @ multi (webpack)-dev-server/client?http://192.168.0.36:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.ts

No type errors found
Version: typescript 3.9.7
Time: 2567ms

See my example here: https://github.com/fairking/vue-ts-nameof-sample

@Shinigami92
Copy link

@fairking I think you've already made progress and haven't noticed 😃

Your new problem is that eslint-loader is used too early. This of course does not know nameof and should only process if nameof has already been processed

@Shinigami92
Copy link

@fairking

https://github.com/fairking/vue-ts-nameof-sample/blob/c24c227023f0da47fbaee713366383a49748b5c5/vue.config.js#L9

I'm not quite sure if my workaround supports embedded code in <script>
I'm always using

<script lang="ts" src="./code.ts" />

So maybe cause you have code in your vue file, you need to find a improved way of handling this, good luck and post your results so others can benefit from it 😀

@fairking
Copy link

fairking commented Jul 28, 2020

Moving ts scripts outside of .vue is not an option for me. The entire component must be in on single file otherwise it makes development nightmare. Sorry I am not an angular guy :-)

@perf2711
Copy link

perf2711 commented Nov 25, 2020

I had the same problem. Almost got it to work (vue-cli-service build sometimes worked, and sometimes it threw nameof errors).

Your new problem is that eslint-loader is used too early. This of course does not know nameof and should only process if nameof has already been processed

This comment actually guided me to the answer, so thanks @Shinigami92 😄

If someone is still trying to make this work, this is how I accomplished this.

In tsconfig.json add:

{
  /* compilerOptions, etc. */
  "files": [
    "./node_modules/ts-nameof/ts-nameof.d.ts"
  ]
}

so this declaration file would be visible globally.

My vue.config.js was looking like this:

const tsNameOf = require('ts-nameof');

module.exports = {
    chainWebpack: config => {
        config.module
            .rule('ts')
                .test(/\.ts$/)
                    .use('ts-loader')
                        .loader('ts-loader')
                            .options({
                                transpileOnly: true,
                                getCustomTransformers: () => ({ before: [tsNameOf] }),
                                appendTsSuffixTo: [/\.vue$/],
                                happyPackMode: true
                            })
                        .end()
                      .use('ts-nameof')
                        .loader('ts-nameof-loader')
                        .end()

I added the ts-nameof-loader (npm package has the same name) by the way, it helped actually replacing nameof calls with strings.

However it seems, that at this moment eslint-loader was "fighting" with ts-loader in parallel, creating a race condition, which caused the build to sometimes work, and sometimes not. So, by inspecting the webpack config using vue inspect, I moved the eslint-loader explicitly to run after ts-nameof-loader:

const tsNameOf = require('ts-nameof');

module.exports = {
    chainWebpack: config => {
        // Delete the rule completely
        config.module.rules.delete('eslint');

        config.module
            .rule('ts')
                .test(/\.ts$/)
                    .use('ts-loader')
                        .loader('ts-loader')
                            .options({
                                transpileOnly: true,
                                getCustomTransformers: () => ({ before: [tsNameOf] }),
                                appendTsSuffixTo: [/\.vue$/],
                                happyPackMode: true
                            })
                        .end()
                    .use('ts-nameof')
                        .loader('ts-nameof-loader')
                        .end()
                    .use('eslint') // Add the loader here
                        .loader('eslint-loader')
                        .options({
                            extensions: [
                                '.ts',
                                '.tsx',
                                '.vue'
                            ],
                            cache: true,
                            emitWarning: false,
                            emitError: false,
                            formatter: undefined
                        })

    }
};

And there we have it!
obraz

@Shinigami92
Copy link

Shinigami92 commented Feb 26, 2021

I created a plugin for vite

https://www.npmjs.com/package/vite-plugin-ts-nameof

You still need files: ["./node_modules/ts-nameof/ts-nameof.d.ts"] in your tsconfig.json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants