Skip to content

Commit baf2ee7

Browse files
author
Santosh Sutar
committed
[docs] Add a how to run codemods guide
1 parent 223e662 commit baf2ee7

File tree

1 file changed

+220
-0
lines changed

1 file changed

+220
-0
lines changed

howto.md

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
# Ember ES6 - How to run ES6 class codemods
2+
3+
## Overview
4+
The [ES6 native classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) support is available in Ember starting with 3.4.x via [polyfill](https://github.com/pzuraq/ember-native-class-polyfill) (3.6.x without polyfill). Transitioning to the new ES6 classes syntax would provide better overall developer experience. The [ember ES6 class codemods](https://github.com/scalvert/ember-es6-class-codemod) are developed to make this transition easier.
5+
6+
The purpose of this document is to provide step by step guide to install and run codemods on your code base.
7+
8+
## Prerequisites
9+
The application must be running on
10+
- `ember-source@^3.4.6`
11+
- `ember-cli-babel@^7.x.x`
12+
13+
## Dependencies
14+
15+
Before moving on to installation steps, let's take a quick overview of dependencies which will be added to the application.
16+
17+
### [ember-es6-class-codemod](https://github.com/scalvert/ember-es6-class-codemod)
18+
Codemods for transforming ember app code to native ES6 class syntax with decorators. The codemods can be installed globally (recommended) or locally.
19+
20+
### [ember-es6-class-codemod-dyfactor](https://github.com/ssutar/ember-es6-class-codemod-dyfactor)
21+
[Dyfactor](https://github.com/dyfactor/dyfactor) is a plugin runner system which allows you to collect the runtime information about the code. The [ember-es6-class-codemod-dyfactor](https://github.com/ssutar/ember-es6-class-codemod-dyfactor) is a dyfactor plugin to extract the runtime data about ember objects. This data need to be passed to the codemods to provide metadata about the objects being transformed.
22+
23+
### [eslint-plugin-ember-es6-class](https://github.com/scalvert/eslint-plugin-ember-es6-class)
24+
Eslint plugin for enforcing usages of Ember ES6 classes in your application. Recommended to enable after transformation to ES6 classes to prevent addition of code in EmberObject.extend syntax.
25+
26+
### [ember-decorators](https://github.com/ember-decorators/ember-decorators)
27+
Ember decorators provide a set of [decorators](https://github.com/tc39/proposal-decorators#decorators) which can be used to write native classes with every standard feature that is available in Ember, along with the transforms and build system required to polyfill
28+
29+
### [ember-native-class-polyfill](https://github.com/pzuraq/ember-native-class-polyfill)
30+
This addon provides a polyfill for the native class behavior that was proposed in Ember RFCs [#240](https://emberjs.github.io/rfcs/0240-es-classes.html) and [#337](https://emberjs.github.io/rfcs/0337-native-class-constructor-update.html).
31+
32+
## Installation
33+
Install [ember-es6-class-codemod](https://github.com/scalvert/ember-es6-class-codemod) globally
34+
```
35+
yarn global add ember-es6-class-codemod
36+
```
37+
Install the following dev dependencies in your project:
38+
- [eslint rule](https://github.com/scalvert/eslint-plugin-ember-es6-class) and
39+
- [dyfactor plugin](https://github.com/ssutar/ember-es6-class-codemod-dyfactor)
40+
```
41+
yarn add eslint-plugin-ember-es6-class ember-es6-class-codemod-dyfactor --dev
42+
```
43+
- Install the [ember decorators](https://github.com/ember-decorators/ember-decorators) in your project:
44+
45+
```
46+
yarn ember install ember-decorators
47+
```
48+
- _Install [ember native class polyfill](https://github.com/pzuraq/ember-native-class-polyfill) only if your application is running on `ember-source` less than v3.6.x_
49+
```
50+
yarn ember install ember-native-class-polyfill
51+
```
52+
53+
## Setup dyfactor plugin
54+
Once all the dependencies are installed successfully, the application need to be setup to run the [dyfactor plugin](https://github.com/ssutar/ember-es6-class-codemod-dyfactor), which is used to gather valuable runtime information from the application for use within the codemod
55+
56+
To initialize the dyfactor plugin, run
57+
```
58+
yarn dyfactor init
59+
```
60+
A file `.dyfactor.json` will be created in the current directory.
61+
62+
To view the list of dyfactor plugins installed
63+
```
64+
yarn dyfactor list-plugins
65+
66+
The list of available dyfactor plugins will be displayed, for example:
67+
68+
Plugins
69+
=============
70+
Name: ember-object Type: template Levels: extract, modify
71+
✨ Done in 0.83s.
72+
```
73+
74+
Open `.dyfactor.json` and set the entry in navigation.pages list. The page entry must be of the test page url, for example:
75+
```
76+
{
77+
"navigation": {
78+
"pages": [
79+
"http://localhost:4200/tests/index.html?runtimedata"
80+
]
81+
}
82+
}
83+
```
84+
**Note** The dyfactor plugin does not need to run all the tests. It is recommended to configure the url using filters or module/test ids such that it would run a small subset of tests or a single test (preferred).
85+
86+
Edit the `test-helper.js` file from the application and add the following code:
87+
```
88+
// ... Other imports
89+
90+
import { extract } from "ember-es6-class-codemod-dyfactor/test-support/ember-object";
91+
92+
// Add this after all the assets are loaded, just before `start`
93+
94+
if (QUnit.urlParams.runtimedata) {
95+
extract();
96+
}
97+
98+
start();
99+
```
100+
**Note** Make sure to wrap the extract call in some query parameter, and pass in the same query parameter to the configuration url in `.dyfactor.json`
101+
102+
**IMPORTANT** Commit all the changes locally. The dyfactor plugin switches to a new branch and modifies the code. It removes all the uncommitted local changes in the process.
103+
104+
## Collecting runtime data
105+
Start your application
106+
```
107+
ember serve
108+
```
109+
Run the dyfactor plugin using following command:
110+
```
111+
yarn dyfactor run template ember-object <path> --level extract
112+
```
113+
`<path>` can be any directory in the application for which the runtime data need to be extracted.
114+
115+
This command prompts for user input in different stages of execution
116+
117+
The first prompt is
118+
```
119+
? Start your dev server and press enter to continue... (Continue)
120+
```
121+
Make sure your application is running and press enter.
122+
123+
Once you press enter the dyfactor will
124+
- Create a new branch
125+
- Switch to the newly created branch
126+
- Run the dyfactor plugin codemods on your application code
127+
128+
The next prompt will be
129+
```
130+
? Press enter when your dev server is reset... (Continue)
131+
```
132+
Wait till the server is reset after applying the changes made by dyfactor plugin in the application code. Press enter when server is done reset.
133+
134+
A message will be displayed something like:
135+
```
136+
Collecting telemetry data…
137+
```
138+
At this step a new browser window (chromium) is opened with the url configured in the `.dyfactor.json`. The test will be run and the window will be closed automatically.
139+
140+
After this step the runtime data will be collected in the file `dyfactor-telemetry.json`
141+
142+
## Running codemods
143+
Run the transforms [ember-object](https://github.com/scalvert/ember-es6-class-codemod/tree/master/transforms/ember-object)
144+
```
145+
ember-es6-class-codemod ember-object <path-to-run-codemods-on> --decorators=true --runtime-config-path=dyfactor-telemetry.json
146+
```
147+
148+
The codemods can be run targeting a small subset of application code. For example you can target a single in-repo addon or single type (for example services, controllers etc) in the addon. See the [usage details](https://github.com/scalvert/ember-es6-class-codemod#usage) for all the options.
149+
150+
## Configuring ESLint rule
151+
152+
To enable the [ESLint rule](https://github.com/scalvert/eslint-plugin-ember-es6-class) which will disallow usage of the old `EmberObject.extend` syntax -
153+
154+
Add the following code to `.eslintrc.js`
155+
156+
```
157+
module.exports = {
158+
root: true,
159+
plugins: ['ember-es6-class'],
160+
161+
// ... other config ...
162+
163+
rules: {
164+
overrides: [{
165+
files: ['<transformed-addon-path>/**/*.js'],
166+
rules: {
167+
'ember-es6-class/no-object-extend': 'error',
168+
},
169+
}]
170+
}
171+
}
172+
```
173+
174+
## Debugging
175+
Check the `codemods.log` in the directory from where the codemods are being executed.
176+
177+
The codemods execution details are logged into the `codemods.log` file. Specifically, details such as failures and reasons for failures, are logged. This would be the recommended starting point for debugging issues.
178+
179+
## Known errors
180+
- In dyfactor plugin execution, an error might be logged to console
181+
```
182+
Error occurred in instrumenting <some/file/path.js> { TypeError: unknown: Property init of VariableDeclarator expected node to be of a type ["Expression"] but instead got "FunctionDeclaration"
183+
```
184+
185+
This means that the file which the plugin is instrumenting does not have a default export, in other words the file does not need transformation. Please ignore this error
186+
187+
- Codemods might throw below error
188+
```
189+
ERR <path> Transformation error
190+
<error reason with stack trace>
191+
```
192+
193+
Verify the `<path>` value, in most cases it would be a non js file. While this is [known issue](https://github.com/scalvert/ember-es6-class-codemod/issues/42) in the codemods, it will be fixed soon
194+
195+
- An eslint error might be reported after running codemods.
196+
```
197+
Parsing error: Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.
198+
```
199+
This happens because your application is running on `babel-eslint` v9 or higher. To fix this issue set the `legacyDecorators` option in the `.eslintrc.js` file as following:
200+
```
201+
module.exports = {
202+
// ... config options ...
203+
parserOptions: {
204+
ecmaFeatures: { legacyDecorators: true },
205+
},
206+
207+
// ... more config options ...
208+
}
209+
```
210+
211+
## References
212+
- [jscodeshift](https://github.com/facebook/jscodeshift)
213+
- [Recast](https://github.com/benjamn/recast)
214+
- [ASTExplorer](https://astexplorer.net/)
215+
- [Codemod-cli](https://github.com/rwjblue/codemod-cli)
216+
- [Dyfactor](https://github.com/dyfactor/dyfactor)
217+
- [RFC - Ember native class roadmap](https://github.com/pzuraq/emberjs-rfcs/blob/b47e7f9ec4f02c7d27d50de64691130e7d22747d/text/0000-native-class-roadmap.md)
218+
- [RFC - Ember native class constructor update](https://github.com/pzuraq/emberjs-rfcs/blob/94b38d429eb2964fa86cd13bea6823a01b3ef68d/text/0000-native-class-constructor-update.md)
219+
- [RFC - Ember native classes codemods](https://docs.google.com/document/d/18QW1SJ6crN5Lh2ZhsSJgjx-oxpMZXUhYBSnrBqxKprI/edit#heading=h.hmogsghmufas)
220+
- [ember-es6-class-codemod-dyfactor](https://github.com/ssutar/ember-es6-class-codemod-dyfactor)

0 commit comments

Comments
 (0)