ts-nameof
ts-nameof copied to clipboard
Using ts-nameof with Vue
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?
@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)
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
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] })
}
}]
}
...
]
}
...
}
...
}
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?
@fairking Have you tried my workaround? https://github.com/dsherret/ts-nameof/issues/83#issuecomment-553907295
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>
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
@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
@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 😀
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 :-)
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!
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