Crafting a Dynamic VueJS Component Using TSX Files and Render Function
Just created a step to step tutorial to reproduce the project pattern I have been using these last years ( 2+ years with projects in production currently ).
I'm sure it will bring you some great benefits use VueJS + TSX Files, like:
Type Safety: One of the key benefits of using TSX files in Vue.js is the type safety that it provides. With TypeScript, you can ensure that your components are correctly typed, avoiding errors and improving code quality.
Improved Readability: TSX files can improve the readability of your Vue.js code, making it easier to understand and maintain.
Enhanced Editor Support: Using TSX files in Vue.js can improve the support you get from your code editor, providing enhanced code completion, error highlighting, and more.
Increased Productivity: With its strong typing, improved readability and better editor support, using TSX files in Vue.js can help you write code faster and with fewer errors, ultimately increasing your productivity ?? ??
Disclaimer: This approach can be useful only for Vue Projects version 2+ and 2.6+.
First of all, we need to setup?TSX properly?in your?VueJS?project. To do this, you?must follow these steps:
1- Add Typescript Dependencies (If your project already has typescript, skip this step )
yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser @vue/cli-plugin-typescript @vue/eslint-config-typescript typescript
Ops: I'm assuming you already have a package manager installed. In this example I will use yarn to install Typescript dependencies.
"@typescript-eslint/eslint-plugin" and "@typescript-eslint/parser" are ESLint plugins that add support for TypeScript to the ESLint linter.
"@vue/cli-plugin-typescript" is a plugin for the Vue CLI that adds TypeScript support to Vue.js projects.
"@vue/eslint-config-typescript" is an ESLint config that provides recommended rules for using TypeScript with Vue.js and "typescript" for sure is the programming compiler itself.
2 - Configure your Typescript using tsconig.json file:
The most important properties for us to set here are:
Include: tells the Typescript compiler what to search for and where to search, in this case any .ts | .tsx | .vue files inside src or test folder.
jsx: preserve: this property specify how Typescript should handle JSX syntax, the "preserve" option ensures that JSX syntax is preserved during compilation, which means that will be outputted as-is in the compiled Javascript code.
Ops: Don't forgot to set Include and jsx properties even if your project already has Typescript
3 - Providing .d.ts files for your TS compile
Create and save these files on your project root:
In TypeScript, .d.ts files are definition files that describe the shape of a JavaScript module or library's API, they are used to provide type information for third-party JavaScript libraries or modules that don't have TypeScript definitions included.
By including these .d.ts files in your TypeScript project, you will get the benefits of TypeScript's type checking for Vue components written in .TSX files, in addiction to keep our compiler aware that we are going to write JSX inside Vue components.
4 - Now, let's configure your babel !
The most important setup dependency you might need is @Vue/babel-preset-jsx
Created by the Vuejs Core Team, it's a babel transpiler that allows you to create VueJS components using render functions and to write your VueJS components using .TSX or .JSX files.
Add these follow dev dependencies:
yarn add -D @babel/core @babel/preset-env @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
Then, create your .babelrc in your project root, and set the preset property with "@vue/babel-preset-jsx".
It will allow you to use JSX within Vue components.
Now you are ready to create something beautiful like this:
// MyComp.tsx
export default {
? render() {
? ? return <p>hello</p>
? }
}
or even better like this:
// MyComp.tsx
export default {
?render() {
const inputAttrs = {
type: 'email',
placeholder: 'Enter your email'
}
return <input {...{ attrs: inputAttrs }} />
}
}
now you have 100% Vue functional components also:
领英推荐
export default ({ props }) => <p>hello { props.message }</p>
5 - To proceed, we'll need to develop a wrapper class for our Vue Components. To do so, we should create a new folder in the project root directory and name it "config". Then, we can add a file to this folder called "vue-components.ts".
The idea behind this class is to act as a wrapper providing type safety for all your components props.
By extending the Vue class and defining a generic $props property with the P type, we can ensure that our components receive the correct props and avoid runtime errors.
6 - Let's code
Let's bring this idea to the real world, I will show you how to easily?customize?and?manage a?typography component throughout your application,?ensuring consistency and a polished?look by using TSX file to create and render your component.
First of all, I would recommend using the Vue Facing Decorator library to enhance your developer experience. It provides a set of decorators that are useful in creating reactive properties and methods for Vue components, allowing you to quickly bootstrap your components using TypeScript.
Check out the Docs ( Portuguese translation made by me ?????? )
Alright, without further ado, let's checkout our Typography component structure :
Typography/?
├── prop-accessor.ts?
└──?index.tsx
Let's start by the?Typography/props-accessor.ts:
A module that exports an object with?different typography keys, representing?different font sizes and?styles, each?with their own set of CSS properties such?as?font size,?line height, and?fontWeight.?
We are?going to?take advantage of render?function flexibility with this afterwards.
Here is our Typography/index.tsx:
Here, we are taking advantage of our VueComponent class wrapper ( previous step ), to define an interface for our Typography component, ensure type-safety and for sure for intellisense proposes.
Note: the '?' operator in the TypographyProps interface creates optional parameters, so if you don't pass anything to those parameters, TypeScript won't throw any error. Otherwise, it will throw ( see image below, props 'as' is required ).
Our Typography.tsx Component now has:
8 - Bonus: Creating a flexible Input Component
We can create a truly flexible Input component by spreading $attrs and $listeners objects into "attrs" and "on" properties respectively, this can ensure that any non-props attributes or listeners passed to the parent component are passed down to the rendered HTML element.
e.g:
// Input.tsx
import { Component } from 'vue-facing-decorator'
import { VueComponent } from '@/config/vue-component.ts'
@Component({})
export default class Input extends VueComponent {
render(h) {
return h(
'input',
{
attrs: { ...this.$attrs },
on: { ...this.$listeners }
}
)
}
}
You can create any input using this component, without needed to create props for any Html Input Attributes for example. ????
Or even better, you can take advantage of some UI Library like ChakraUI and extend a pre-build Input Component.
// Input.tsx
import { Component } from 'vue-facing-decorator'
import { VueComponent } from '@/config/vue-component.ts'
import { CInput } from '@chakra-ui/vue'
@Component({})
export default class Input extends VueComponent {
render(h) {
return h(
CInput, <-- here is where you extend your pre-made component
{
attrs: { ...this.$attrs },
on: { ...this.$listeners }
}
)
}
}
Now your Input Component inherit all Chakra UI Style Props and Chakra Input Props in less than 20 lines. ??????
That's all folks !
Full Stack Developer @ Ethosx - Vue | React | Node | Typescript | PHP | JavaScript | Kanban | UX/UI | APIs
9 个月An update using more current resources like Vite, etc. would be interesting. How would you approach style in this case? In short, the step by step was incredible
Systems Analyst
1 年Amazing Brendon ????????????