# vue-codemod **Repository Path**: originjs/vue-codemod ## Basic Information - **Project Name**: vue-codemod - **Description**: No description available - **Primary Language**: TypeScript - **License**: MIT - **Default Branch**: 1.0.1 - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 1 - **Created**: 2021-12-13 - **Last Updated**: 2021-12-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # vue-codemod **Current status: experimental** This repository contains a collection of codemod scripts for use with [JSCodeshift](https://github.com/facebook/jscodeshift) and [vue-eslint-parser](https://github.com/mysticatea/vue-eslint-parser) that help update Vue.js APIs. Inspired by [react-codemod](https://github.com/reactjs/react-codemod). ## Command Line Usage - run a single transformation: `npx vue-codemod -t --params [transformation params] [...additional options]` - `transformation` (required) - name of transformation, see available transformations below; or you can provide a path to a custom transformation module. - `path` (required) - files or directory to transform. - `--params` (optional) - additional transformation specific args. - run all transformations: `npx vue-codemod -a` ## Programmatic API - `runTransformation(fileInfo, transformation, params)` ## Roadmap - [x] Basic testing setup and a dummy CLI - [x] Support applying `jscodeshift` codemods to `.vue` files - [x] Provide a programmatic interface for usage in `vue-cli-plugin-vue-next` - [x] Set up tests - [ ] (WIP) Implement the transformations described below for migration usage - [ ] Built-in transformations need to support TypeScript - [ ] Built-in transformations need to support module systems other than ES module, and those without modules - [x] Define an interface for transformation of template blocks (use [`vue-eslint-parser`](https://github.com/mysticatea/vue-eslint-parser/) for this) - [x] A playground for writing transformations - `yarn playground` and visit http://localhost:3000 ## Included Transformations ### Transformation List - `new-component-api` - `vue-class-component-v8` - `new-global-api` - `vue-router-v4` - `vuex-v4` - `define-component` - `new-vue-to-create-app` - `scoped-slots-to-slots` - `new-directive-api` - `remove-vue-set-and-delete` - `rename-lifecycle` - `add-emit-declaration` - `global-filter` - `tree-shaking` - `v-model` - `render-to-resolveComponent` - `remove-contextual-h-from-render` - `remove-production-tip` - `remove-trivial-root` - `remove-vue-use` - `root-prop-to-use` - `vue-as-namespace-import` - `add-import` - `remove-extraneous-import` - `slot-attribute` - `slot-default` - `slot-scope-attribute` - `v-for-template-key` - `v-else-if-key` - `transition-group-root` - `v-bind-order-sensitive` - `v-for-v-if-precedence-changed` - `remove-listeners` - `v-bind-sync` - `remove-v-on-native` - `router-link-event-tag` - `router-link-exact` - `router-view-keep-alive-transition` ### Migrating from Vue 2 to Vue 3 The migration path (to be integrated in a new version of [`vue-migration-helper`](https://github.com/vuejs/vue-migration-helper)): 1. Install eslint-plugin-vue@7, turn on the `vue3-essential` category (maybe a few exceptions like `vue/no-deprecated-dollar-scopedslots-api`) 2. Run `eslint --fix` to fix all auto-fixable issues; if there are any remaining errors, fix them manually 3. Run the `-a` command: `npx vue-codemod -a` 4. Install vue@3, vue-loader@16, etc. 5. Make sure to use the compat build of vue@3 6. Serve the app in development mode, fix the runtime deprecation warnings > Note: even though most of the migration process can be automated, please be aware there might still be subtle differences between Vue 3 and Vue 2 runtime, and the codemods may have uncovered edge cases. Please double check before deploying your Vue 3 app into production. Legend of annotations: | Mark | Description | | ---- | ---------------------------------------------------- | | 🔴 | work not started | | 🔵 | needs to or can be implemented in the compat runtime | #### Fixable in ESLint - [RFC14: Remove `keyCode` support in `v-on`](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0014-drop-keycode-support.md) - Can be detected and fixed by the [`vue/no-deprecated-v-on-number-modifiers`](https://eslint.vuejs.org/rules/no-deprecated-v-on-number-modifiers.html) ESLint rule - `config.keyCode` can be supported in the compat build. It is also detectable with the [`vue/no-deprecated-vue-config-keycodes`](https://eslint.vuejs.org/rules/no-deprecated-vue-config-keycodes.html) ESLint rule - [RFC19: Remove `data` object declaration](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0019-remove-data-object-declaration.md) - Can be detected and fixed by the [`vue/no-shared-component-data`](https://eslint.vuejs.org/rules/no-shared-component-data.html) and the [`vue/no-deprecated-data-object-declaration`](https://eslint.vuejs.org/rules/no-deprecated-data-object-declaration.html) ESLint rules #### Codemods - [RFC01: New slot syntax](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md) and [RFC06: Slots unification](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0006-slots-unification.md) - Can be detected and partially fixed by the [`vue/no-deprecated-slot-attribute`](https://eslint.vuejs.org/rules/no-deprecated-slot-attribute.html) and [`vue/no-deprecated-slot-scope-attribute`](https://eslint.vuejs.org/rules/no-deprecated-slot-scope-attribute.html) - During the transition period, with the 2 ESLint rules enabled, it will warn users when they use `this.$slots`, recommending `this.$scopedSlots` as a replacement - When upgrading to Vue 3, replace all `.$scopedSlots` occurrences with `.$slots` (should pass the abovementioned ESLint checks before running this codemod) (implemented as `scoped-slots-to-slots`) - [RFC04: Global API treeshaking](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0004-global-api-treeshaking.md) & [RFC09: Global mounting/configuration API change](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0009-global-api-change.md) - **implemented as `new-global-api`** - `import Vue from 'vue'` -> `import * as Vue from 'vue'` (implemented as `vue-as-namespace-import`) - `Vue.extend` -> `defineComponent` (implemented as `define-component`) - `new Vue()` -> `Vue.createApp()` (implemented as `new-vue-to-create-app`) - `new Vue({ el })`, `new Vue().$mount` -> `Vue.createApp().mount` - `new HelloWorld({ el })`, `new HelloWorld().$mount` -> `createApp(HelloWorld).mount` - `render(h)` -> `render()` and `import { h } from 'vue'` (implemented as `remove-contextual-h-from-render`) - `Vue.config.productionTip` -> removed (implemented as `remove-production-tip`) - 🔴 Some global APIs now can only be used on the app instances, while it's possible to support the legacy usage in a compat build, we will provide a codemod to help migration. (`global-to-per-app-api`) - `Vue.config`, `Vue.use`, `Vue.mixin`, `Vue.component`, `Vue.directive`, etc -> `app.**` (It's possible to provide a runtime compatibility layer for single-root apps) - `Vue.prototype.customProperty` -> `app.config.globalProperties.customProperty` - `Vue.config.ignoredElements` -> `app.config.isCustomElement` - The migration path would be a two-pass approach: 1. Scan the entire project to collect all the usages of the abovementioned global properties / methods 2. Depending on the result of the first scan: 1. If there's only one entry file using these global APIs, then transform it; 2. If there's exactly one entry file and one root instance, but several other files are also using `Vue.*`, then transform the entry file to export the root instance, import it in other files and transform them with the imported root instance; 3. If there are more than one entry file or root instances, then the user needs to manually export the root instances, re-apply this codemod to those non-entry files with an argument designating the root instance. - 🔵 Detect and warn on `optionMergeStrategies` behavior change - [RFC04: Global API treeshaking](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0004-global-api-treeshaking.md) - implemented as **`tree-shaking`** - `Vue.nextTick()` -> `nextTick()` - `Vue.observable()` -> `reactive()` - `Vue.version` -> `version` - [RFC05: Replace `v-bind`'s `.sync` with a `v-model` argument](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0005-replace-v-bind-sync-with-v-model-argument.md) - Can be detected and fixed by the [`vue/no-deprecated-v-bind-sync`](https://eslint.vuejs.org/rules/no-deprecated-v-bind-sync.html) ESLint rule - [RFC07: Functional and async components API change](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0007-functional-async-api-change.md) - 🔵 a compatibility mode can be provided for functional components for one-at-a-time migration - Can be detected by the [`vue/no-deprecated-functional-template`](https://eslint.vuejs.org/rules/no-deprecated-functional-template.html) ESLint rule - 🔴 SFCs using `