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

h is not defined in .tsx functions #174

Open
gettinToasty opened this issue Feb 21, 2019 · 13 comments
Open

h is not defined in .tsx functions #174

gettinToasty opened this issue Feb 21, 2019 · 13 comments

Comments

@gettinToasty
Copy link

May be a duplicate of #93

After configuring our TsxComponent class to properly allow babel to handle h auto-injection it appears that there is no actual injection happening in .tsx files:

TsxComponent

interface ITsx {
  render(): JSX.Element;
}

export default abstract class TsxComponent<T> extends Vue implements ITsx {
  private vueTsxProps: Readonly<{}> & Readonly<T>;

  render() {
    return <div />;
  }
}

Implementation

export default class Foo extends TsxComponent<{}> {
  render() {
    return <h1>Hello World</h1>
  }
}

Error

Vue warn]: Error in render: "ReferenceError: h is not defined"
@maksnester
Copy link

var h = this.$createElement isn't added in transpiled functions automatically.

However in case of render I can just write render(h) and it works. But in other functions I have to add this string manually to make it work.

Posted a question on stackoverflow as well.

@gettinToasty
Copy link
Author

gettinToasty commented Feb 28, 2019

@alendorff not according to the features of this library:

Starting with version 3.4.0 we automatically inject const h = this.$createElement in any method and getter (not functions or arrow functions) declared in ES2015 syntax that has JSX so you can drop the (h) parameter.

@maksnester
Copy link

@gettinToasty yes, sure, I expected this behavior, but that's not happened in my case. 🤷‍♂️
JSX works fine, TSX - not.

@healqq
Copy link

healqq commented Mar 1, 2019

I would reccomend to look at https://github.com/kaorun343/vue-property-decorator and https://github.com/vuejs/vue-class-component, if you want to have component classes in TSX. At least check how they handle that.

@gettinToasty
Copy link
Author

We use vue-property-decorator for our component classes, I don't think that's part of the issue here.

@maksnester
Copy link

@healqq I didn't catch your point. At what exactly I should look? I use vue-property-decorator with TSX of course. It's quite hard to effectively utilize typescript in vue project without it.

@maksnester
Copy link

@healqq by the way even in their example they added h manually as an argument

@healqq
Copy link

healqq commented Mar 1, 2019

@alendorff that is just a bad(old) example, we’Re using it for our project and h is autoinjected. Other option would be to wait for vue3 release, but it’ll take some time

@healqq
Copy link

healqq commented Mar 1, 2019

Can you post your tsconfig? Maybe the issue is there?

@gettinToasty
Copy link
Author

we have jsx: preserve in our tsconfig so ts-loader shouldnt even touch it during compile

@healqq
Copy link

healqq commented Mar 2, 2019

That's correct, yes. Maybe you can do minimal repo that replicates issue?

@juanfernandoe
Copy link

juanfernandoe commented Mar 7, 2019

Hi,

this is a minimal example of how I resolve this issue.
there are 4 approaches.

  1. Separate template from logic
  2. typescript static type check in the template
  3. vuejs + tsx
  4. Hot reload

Test1.vue.ts

import { Vue, Component } from 'vue-property-decorator'
import { CreateElement, VNode } from 'vue';
import { render } from './Test1.vui';

@Component({})
export class Test1 extends Vue {
    public message:string = 'hello world';
    public render(h: CreateElement): VNode {
        return render.bind(this)(h);
    }
}

export default Test1;

Test1.vui.tsx

import { CreateElement, VNode } from 'vue';
import { Test1 } from './Test1.vue';

export function render(this: Test1, h: CreateElement): VNode {
    return (
        <div>
            <h1>Title</h1>
            {this.message}
        </div>
    );
}

add this rule to webpack


{
    test: /\.tsx$/,
    use: ['babel-loader', 'vue-jsx-hot-loader', 'ts-loader'],
    exclude: /node_modules/
}

tsconfig.json


{
    "compilerOptions": {
        "lib": [
            "dom",
            "es6",
            "es2015.promise"
        ],
        "sourceMap": true,
        "strict": true,
        "module": "esnext",
        "moduleResolution": "node",
        "target": "es6",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "allowSyntheticDefaultImports": true,
        "jsx": "preserve",
        "jsxFactory": "h",
        "typeRoots": ["./node_modules/@types", "./types"]
    }
}

I hope it helps someone.

@miguelramos
Copy link

miguelramos commented Jun 25, 2020

I got the same thing with rollup+tsx. If i use .vue all files works but with tsx h is not defined. Tried loy of babel presets but always got the same thing. BRRRRRRR....

// rollup config

import { RollupOptions, rollup } from 'rollup';
/* eslint-disable sort-imports-es6/sort-imports-es6 */
/* eslint-disable @typescript-eslint/no-var-requires */
import { join, resolve } from 'path';

import { BuildPackage } from '../build-package';
import { isObject } from '../utils';
import { terser } from 'rollup-plugin-terser';

const autoprefixer = require('autoprefixer');
const nodeResolve = require('rollup-plugin-node-resolve');
const vue = require('rollup-plugin-vue');
const babel = require('rollup-plugin-babel');
const cjs = require('rollup-plugin-commonjs');
const rollString = require('rollup-plugin-string');
const ts = require('rollup-plugin-typescript2');
const requireContext = require('rollup-plugin-require-context');

const { assign, keys } = Object;

const baseConfig = (settings: BuildPackage) => {
  const {
    options: { entryFile },
    sourceDir
  } = settings;
  const pkg = require(join(sourceDir, 'package.json'));
  /*const input = Array.isArray(entryFile)
    ? [...entryFile].map(file => join(sourceDir, file))
    : join(sourceDir, entryFile);
  */
  return {
    external: [...keys(pkg.dependencies), ...keys(pkg.peerDependencies), ...['path', 'url']],
    // inlineDynamicImports: true,
    input: entryFile,
    plugins: [
      nodeResolve({
        mainFields: ['main', 'module', 'browser'],
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue']
      }),
      cjs(),
      requireContext(),
      rollString.string({
        include: '**/*.svg'
      }),
      vue({
        css: false,
        style: {
          postcssPlugins: [autoprefixer]
        },
        compileTemplate: true
      }),
      ts({
        cacheRoot: resolve(sourceDir, 'node_modules/.rts2_cache'),
        tsconfig: join(sourceDir, 'tsconfig.build.json'),
        tsconfigOverride: {
          compilerOptions: {
            declaration: true,
            declarationDir: join(settings.outputDir, '@types'),
            moduleResolution: 'node',
            rootDir: settings.sourceDir
          }
        },
        useTsconfigDeclarationDir: true
      }),
      babel({
        // babelrc: false,
        exclude: 'node_modules/**',
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
        presets: [
          [
            '@babel/preset-env',
            {
              modules: false
            }
          ],
          //'@vue/babel-preset-jsx'
          //'@vue/babel-preset-app'
          '@vue/app'
        ],
        include: [join(settings.sourceDir, '**/*')],
        //plugins: ["transform-vue-jsx"],
        /*plugins: [
          "@babel/plugin-syntax-jsx",
          ["@babel/plugin-transform-react-jsx", { pragma : 'dom' }]
        ],*/
        //externalHelpers: true,
        runtimeHelpers: true
      })
    ]
  };
};

// compiled es format

import { __extends, __decorate, __metadata } from 'tslib';
import Vue from 'vue';
import { Component } from 'vue-property-decorator';

var UIButton =
/** @class */
function (_super) {
  __extends(UIButton, _super);

  function UIButton(props) {
    return _super.call(this, props) || this;
  }

  UIButton.prototype.render = function (_h) {
    return h("div", {
      "attrs": {
        "className": 'ui__button'
      }
    }, [h("button", ["Ok Button"])]);
  };

  UIButton = __decorate([Component({
    name: 'ui-button'
  }), __metadata("design:paramtypes", [Object])], UIButton);
  return UIButton;
}(Vue);

export default UIButton;

// compiled umd format

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('tslib'), require('vue'), require('vue-property-decorator')) :
  typeof define === 'function' && define.amd ? define(['exports', 'tslib', 'vue', 'vue-property-decorator'], factory) :
  (global = global || self, factory(global.ui = {}, global.tslib, global.Vue, global.vuePropertyDecorator));
}(this, (function (exports, tslib, Vue, vuePropertyDecorator) { 'use strict';

  Vue = Vue && Object.prototype.hasOwnProperty.call(Vue, 'default') ? Vue['default'] : Vue;

  var UIButton =
  /** @class */
  function (_super) {
    tslib.__extends(UIButton, _super);

    function UIButton(props) {
      return _super.call(this, props) || this;
    }

    UIButton.prototype.render = function (_h) {
      return h("div", {
        "attrs": {
          "className": 'ui__button'
        }
      }, [h("button", ["Ok Button"])]);
    };

    UIButton = tslib.__decorate([vuePropertyDecorator.Component({
      name: 'ui-button'
    }), tslib.__metadata("design:paramtypes", [Object])], UIButton);
    return UIButton;
  }(Vue);

  // eslint-disable-next-line sort-imports-es6/sort-imports-es6
  /**
   * Plugin install function
   *
   * @param vue - Vue Instance
   * @param _options - Plubin Options
   *
   * @internal
   */
  // eslint-disable-next-line id-match, @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any

  var install = function install(Vue, _options) {
    Vue.component('ui-button', UIButton);
  };
  /**
   * @public
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any


  var plugin = {
    install: install,
    version: '1.0.0'
  };
  var GlobalVue = null;

  if (typeof window !== 'undefined') {
    GlobalVue = window.Vue;
  } else if (typeof global !== 'undefined') {
    GlobalVue = global.Vue;
  }

  if (GlobalVue) {
    GlobalVue.use(plugin);
  }

  exports.UIButton = UIButton;
  exports.plugin = plugin;

  Object.defineProperty(exports, '__esModule', { value: true });

})));

When imported to a vue app created by cli always complain about h function. Any clues for Rollup+tsx??

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

No branches or pull requests

5 participants