ember-codemod-remove-ember-css-modules 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -172
- package/dist/src/migration/ember-app/index.js +1 -9
- package/dist/src/migration/ember-app/steps/index.js +0 -2
- package/dist/src/migration/ember-app/steps/move-stylesheets.js +10 -0
- package/dist/src/utils/blueprints.js +0 -1
- package/package.json +3 -3
- package/dist/src/migration/ember-app/steps/update-app-app-js.js +0 -46
- package/dist/src/migration/ember-app/steps/update-package-json.js +0 -47
- package/dist/src/utils/blueprints/get-version.js +0 -19
package/README.md
CHANGED
|
@@ -8,9 +8,6 @@ _Codemod to replace `ember-css-modules` with `embroider-css-modules`_
|
|
|
8
8
|
1. [Usage](#usage)
|
|
9
9
|
- [Arguments](#arguments)
|
|
10
10
|
- [Limitations](#limitations)
|
|
11
|
-
1. [How to refactor code](#how-to-refactor-code)
|
|
12
|
-
- [Remove code inheritance](#remove-code-inheritance)
|
|
13
|
-
- [Remove complex string concatenations](#remove-complex-string-concatenations)
|
|
14
11
|
1. [Compatibility](#compatibility)
|
|
15
12
|
1. [Contributing](#contributing)
|
|
16
13
|
1. [License](#license)
|
|
@@ -21,30 +18,30 @@ _Codemod to replace `ember-css-modules` with `embroider-css-modules`_
|
|
|
21
18
|
The codemod helps you:
|
|
22
19
|
|
|
23
20
|
- Remove `ember-css-modules` syntax from an Embroider app
|
|
24
|
-
- Set up `embroider-css-modules` on an Embroider app
|
|
25
21
|
- Remove `ember-css-modules` syntax from a v2 addon
|
|
26
22
|
|
|
27
|
-
It
|
|
23
|
+
It preserves your code whenever possible.
|
|
28
24
|
|
|
29
25
|
|
|
30
26
|
## Usage
|
|
31
27
|
|
|
32
28
|
You can find a migration example in [`ember-container-query`](https://github.com/ijlee2/ember-container-query/pull/167).
|
|
33
29
|
|
|
34
|
-
Step 1. Quickly
|
|
30
|
+
Step 1. Quickly remove `ember-css-modules` syntax.<sup>1</sup>
|
|
35
31
|
|
|
36
32
|
```sh
|
|
37
33
|
cd <path/to/your/project>
|
|
38
34
|
npx ember-codemod-remove-ember-css-modules <arguments>
|
|
39
35
|
```
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
Manually remove the remaining instances of `local-class` attributes and `{{local-class}}` helpers.
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
Step 2. Update project configurations.
|
|
40
|
+
|
|
41
|
+
- [x] Set up CSS modules (see the guides for [apps](../../docs/written-guides/set-up-css-modules-apps.md) and [v2 addons](../../docs/written-guides/set-up-css-modules-v2-addons.md)).
|
|
45
42
|
- [x] Confirm that you can run all scripts in `package.json`.
|
|
46
43
|
|
|
47
|
-
<sup>1. Some prerequisites for running the codemod: First, migrate to the Octane layout (flat or nested). You can leverage codemods for [classic](https://github.com/ember-codemods/ember-component-template-colocation-migrator) and [pod](https://github.com/ijlee2/ember-codemod-pod-to-octane) layouts. Second, [refactor code](
|
|
44
|
+
<sup>1. Some prerequisites for running the codemod: First, migrate to the Octane layout (flat or nested). You can leverage codemods for [classic](https://github.com/ember-codemods/ember-component-template-colocation-migrator) and [pod](https://github.com/ijlee2/ember-codemod-pod-to-octane) layouts. Second, [refactor code](../../docs/refactor-code.md) to help the codemod update templates correctly.</sup>
|
|
48
45
|
|
|
49
46
|
<sup>2. Files such as `.eslintrc.js`, `.prettierrc.js`, `.stylelintrc.js`, `.template-lintrc.js`, `ember-cli-build.js`, `package.json`, `postcss.config.js`, `tsconfig.json`, etc.</sup>
|
|
50
47
|
|
|
@@ -63,7 +60,7 @@ npx ember-codemod-remove-ember-css-modules --type v2-addon
|
|
|
63
60
|
|
|
64
61
|
<summary>Optional: Specify the component structure</summary>
|
|
65
62
|
|
|
66
|
-
By default, an
|
|
63
|
+
By default, an Embroider project has the flat component structure. Pass `--component-structure` to indicate otherwise.
|
|
67
64
|
|
|
68
65
|
```sh
|
|
69
66
|
npx ember-codemod-remove-ember-css-modules --component-structure nested
|
|
@@ -109,167 +106,6 @@ pnpm build
|
|
|
109
106
|
```
|
|
110
107
|
|
|
111
108
|
|
|
112
|
-
## How to refactor code
|
|
113
|
-
|
|
114
|
-
### Remove code inheritance
|
|
115
|
-
|
|
116
|
-
`ember-css-modules` allows composing (really, inheriting) CSS code in two ways:
|
|
117
|
-
|
|
118
|
-
- `composes: ... from '...';` in `*.css`
|
|
119
|
-
- `{{local-class ... from="..."}}` in `*.hbs`
|
|
120
|
-
|
|
121
|
-
The first syntax will continue to work in an Embroider app, provided that the import path is either `global` or a relative path.
|
|
122
|
-
|
|
123
|
-
```css
|
|
124
|
-
/* app/components/ui/form/textarea.css */
|
|
125
|
-
.textarea {
|
|
126
|
-
composes: input from "./input.css";
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
.is-disabled {
|
|
130
|
-
composes: input-disabled from global;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/* These do not work */
|
|
134
|
-
.textarea {
|
|
135
|
-
composes: input from "my-app/components/ui/form/input.css";
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.textarea {
|
|
139
|
-
composes: input from "my-v2-addon/components/ui/form/input.css";
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
The second syntax isn't supported by the `{{local}}` helper from `embroider-css-modules`, so you will need to update the template and stylesheet accordingly.
|
|
144
|
-
|
|
145
|
-
However, note that the presence of `composes` (in a set of related components) may indicate a premature abstraction and an incorrect component design. Ideally, you might duplicate the CSS, then refactor the components. If short on time, you can import the relevant `styles` object in the backing class.
|
|
146
|
-
|
|
147
|
-
<details>
|
|
148
|
-
|
|
149
|
-
<summary>Before, with <code>ember-css-modules</code></summary>
|
|
150
|
-
|
|
151
|
-
Case 1:
|
|
152
|
-
|
|
153
|
-
```hbs
|
|
154
|
-
{{! app/components/ui/form/textarea.hbs }}
|
|
155
|
-
<textarea
|
|
156
|
-
class={{local-class "input" from="my-app/components/ui/form/input.css"}}
|
|
157
|
-
/>
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Case 2:
|
|
161
|
-
|
|
162
|
-
```css
|
|
163
|
-
/* app/components/ui/form/textarea.css */
|
|
164
|
-
.textarea {
|
|
165
|
-
composes: input from "my-app/components/ui/form/input.css";
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
```hbs
|
|
170
|
-
{{! app/components/ui/form/textarea.hbs }}
|
|
171
|
-
<textarea
|
|
172
|
-
local-class="textarea"
|
|
173
|
-
/>
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
</details>
|
|
177
|
-
|
|
178
|
-
<details>
|
|
179
|
-
|
|
180
|
-
<summary>After, with <code>embroider-css-modules</code></summary>
|
|
181
|
-
|
|
182
|
-
```ts
|
|
183
|
-
/* app/components/ui/form/textarea.ts */
|
|
184
|
-
import Component from '@glimmer/component';
|
|
185
|
-
|
|
186
|
-
import inputStyles from './input.css';
|
|
187
|
-
import styles from './textarea.css';
|
|
188
|
-
|
|
189
|
-
export default class UiFormTextareaComponent extends Component {
|
|
190
|
-
inputStyles = inputStyles;
|
|
191
|
-
styles = styles;
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
```hbs
|
|
196
|
-
{{! app/components/ui/form/textarea.hbs }}
|
|
197
|
-
<textarea
|
|
198
|
-
class={{this.inputStyles.input}}
|
|
199
|
-
/>
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
</details>
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
### Remove complex string concatenations
|
|
206
|
-
|
|
207
|
-
In `ember-css-modules`, a string can represent multiple local class names via concatenation. In `embroider-css-modules`, each string represents exactly one.
|
|
208
|
-
|
|
209
|
-
<details>
|
|
210
|
-
|
|
211
|
-
<summary>Before, with <code>ember-css-modules</code></summary>
|
|
212
|
-
|
|
213
|
-
```hbs
|
|
214
|
-
{{! app/components/ui/form/textarea.hbs }}
|
|
215
|
-
<textarea
|
|
216
|
-
local-class="
|
|
217
|
-
textarea
|
|
218
|
-
{{if (or @isDisabled @isReadOnly) 'is-disabled'}}
|
|
219
|
-
"
|
|
220
|
-
/>
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
</details>
|
|
224
|
-
|
|
225
|
-
<details>
|
|
226
|
-
|
|
227
|
-
<summary>After, with <code>embroider-css-modules</code></summary>
|
|
228
|
-
|
|
229
|
-
```hbs
|
|
230
|
-
{{! app/components/ui/form/textarea.hbs }}
|
|
231
|
-
<textarea
|
|
232
|
-
class={{local-class
|
|
233
|
-
this.styles
|
|
234
|
-
"textarea"
|
|
235
|
-
(if (or @isDisabled @isReadOnly) "is-disabled")
|
|
236
|
-
}}
|
|
237
|
-
/>
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
</details>
|
|
241
|
-
|
|
242
|
-
The codemod may fail to update complex expressions. Refactor templates to provide hints. For example, remove nested conditionals (apply them outside the HTML element) and use the `{{concat}}` helper to group substrings.
|
|
243
|
-
|
|
244
|
-
<details>
|
|
245
|
-
|
|
246
|
-
<summary>Before refactor, with <code>ember-css-modules</code></summary>
|
|
247
|
-
|
|
248
|
-
```hbs
|
|
249
|
-
{{! app/components/ui/form/phone.hbs }}
|
|
250
|
-
<input
|
|
251
|
-
local-class="input flag-{{@country}}"
|
|
252
|
-
type="tel"
|
|
253
|
-
/>
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
</details>
|
|
257
|
-
|
|
258
|
-
<details>
|
|
259
|
-
|
|
260
|
-
<summary>After refactor, with <code>ember-css-modules</code></summary>
|
|
261
|
-
|
|
262
|
-
```hbs
|
|
263
|
-
{{! app/components/ui/form/phone.hbs }}
|
|
264
|
-
<input
|
|
265
|
-
local-class="input {{concat 'flag-' @country}}"
|
|
266
|
-
type="tel"
|
|
267
|
-
/>
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
</details>
|
|
271
|
-
|
|
272
|
-
|
|
273
109
|
## Compatibility
|
|
274
110
|
|
|
275
111
|
- Node.js v18 or above
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { createOptions } from '../../utils/steps/create-options.js';
|
|
2
|
-
import { analyzeProject, importStylesInComponents, importStylesInRoutes, moveStylesheets,
|
|
2
|
+
import { analyzeProject, importStylesInComponents, importStylesInRoutes, moveStylesheets, updateComponentTemplates, updateRouteTemplates, } from './steps/index.js';
|
|
3
3
|
export function migrateEmberApp(codemodOptions) {
|
|
4
4
|
const options = createOptions(codemodOptions);
|
|
5
|
-
const { hasEmberCssModules } = options.project;
|
|
6
|
-
// Guarantee idempotency
|
|
7
|
-
if (!hasEmberCssModules) {
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
5
|
// Prepare for migration
|
|
11
6
|
const context = analyzeProject(options);
|
|
12
7
|
// Import styles in classes
|
|
@@ -16,7 +11,4 @@ export function migrateEmberApp(codemodOptions) {
|
|
|
16
11
|
// Update templates
|
|
17
12
|
updateComponentTemplates(context, options);
|
|
18
13
|
updateRouteTemplates(context, options);
|
|
19
|
-
// Fine-tune individual files
|
|
20
|
-
updateAppAppJs(options);
|
|
21
|
-
updatePackageJson(options);
|
|
22
14
|
}
|
|
@@ -2,7 +2,5 @@ export * from './analyze-project.js';
|
|
|
2
2
|
export * from './import-styles-in-components.js';
|
|
3
3
|
export * from './import-styles-in-routes.js';
|
|
4
4
|
export * from './move-stylesheets.js';
|
|
5
|
-
export * from './update-app-app-js.js';
|
|
6
5
|
export * from './update-component-templates.js';
|
|
7
|
-
export * from './update-package-json.js';
|
|
8
6
|
export * from './update-route-templates.js';
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { createFiles, findFiles, mapFilePaths, moveFiles, } from '@codemod-utils/files';
|
|
2
|
+
function canSkip(options) {
|
|
3
|
+
const { projectRoot } = options;
|
|
4
|
+
const filePaths = findFiles('app/assets/app.css', {
|
|
5
|
+
projectRoot,
|
|
6
|
+
});
|
|
7
|
+
return filePaths.length === 1;
|
|
8
|
+
}
|
|
2
9
|
function moveRouteStylesheets(options) {
|
|
3
10
|
const { projectRoot } = options;
|
|
4
11
|
const filePaths = findFiles('app/styles/**/*.css', {
|
|
@@ -12,6 +19,9 @@ function moveRouteStylesheets(options) {
|
|
|
12
19
|
moveFiles(pathMapping, options);
|
|
13
20
|
}
|
|
14
21
|
function moveAppCssToAssets(options) {
|
|
22
|
+
if (canSkip(options)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
15
25
|
const { projectRoot } = options;
|
|
16
26
|
const filePaths = findFiles('app/styles/app.css', {
|
|
17
27
|
projectRoot,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember-codemod-remove-ember-css-modules",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Codemod to replace ember-css-modules with embroider-css-modules",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codemod",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"prettier": "^3.2.5",
|
|
45
45
|
"typescript": "^5.4.2",
|
|
46
46
|
"@shared-configs/eslint-config-node": "0.0.0",
|
|
47
|
-
"@shared-configs/
|
|
48
|
-
"@shared-configs/
|
|
47
|
+
"@shared-configs/prettier": "0.0.0",
|
|
48
|
+
"@shared-configs/typescript": "0.0.0"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": "18.* || >= 20"
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { extname, join } from 'node:path';
|
|
3
|
-
import { AST } from '@codemod-utils/ast-javascript';
|
|
4
|
-
import { createFiles, findFiles } from '@codemod-utils/files';
|
|
5
|
-
function addCssEntryPoint(file, data) {
|
|
6
|
-
const traverse = AST.traverse(data.isTypeScript);
|
|
7
|
-
const ast = traverse(file, {
|
|
8
|
-
visitProgram(path) {
|
|
9
|
-
const nodesToAdd = [
|
|
10
|
-
AST.builders.importDeclaration([], AST.builders.literal('./assets/app.css')),
|
|
11
|
-
AST.builders.noop(),
|
|
12
|
-
];
|
|
13
|
-
path.value.body.unshift(...nodesToAdd);
|
|
14
|
-
return false;
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
return AST.print(ast);
|
|
18
|
-
}
|
|
19
|
-
export function updateAppAppJs(options) {
|
|
20
|
-
const { projectRoot } = options;
|
|
21
|
-
const filePaths = findFiles('app/app.{js,ts}', {
|
|
22
|
-
projectRoot,
|
|
23
|
-
});
|
|
24
|
-
if (filePaths.length !== 1) {
|
|
25
|
-
console.warn('WARNING: updateAppAppJs could not find app.{js,ts} in the app folder. Will skip this step.\n');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const filePath = filePaths[0];
|
|
29
|
-
const fileExtension = extname(filePath);
|
|
30
|
-
const data = {
|
|
31
|
-
isTypeScript: fileExtension === '.ts',
|
|
32
|
-
};
|
|
33
|
-
try {
|
|
34
|
-
let file = readFileSync(join(projectRoot, filePath), 'utf8');
|
|
35
|
-
file = addCssEntryPoint(file, data);
|
|
36
|
-
const fileMap = new Map([[filePath, file]]);
|
|
37
|
-
createFiles(fileMap, options);
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
let message = `WARNING: updateAppAppJs could not update \`${filePath}\`. Please update the file manually.`;
|
|
41
|
-
if (error instanceof Error) {
|
|
42
|
-
message += ` (${error.message})`;
|
|
43
|
-
}
|
|
44
|
-
console.warn(`${message}\n`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { convertToMap, convertToObject, readPackageJson, } from '@codemod-utils/json';
|
|
4
|
-
import { getVersion } from '../../../utils/blueprints.js';
|
|
5
|
-
function updateDevDependencies(packageJson, options) {
|
|
6
|
-
const { project } = options;
|
|
7
|
-
const devDependencies = convertToMap(packageJson['devDependencies']);
|
|
8
|
-
const packagesToDelete = ['ember-css-modules'];
|
|
9
|
-
packagesToDelete.forEach((packageName) => {
|
|
10
|
-
devDependencies.delete(packageName);
|
|
11
|
-
});
|
|
12
|
-
const packagesToInstall = new Set([
|
|
13
|
-
'@embroider/compat',
|
|
14
|
-
'@embroider/core',
|
|
15
|
-
'@embroider/webpack',
|
|
16
|
-
'autoprefixer',
|
|
17
|
-
'embroider-css-modules',
|
|
18
|
-
'postcss',
|
|
19
|
-
'postcss-loader',
|
|
20
|
-
'webpack',
|
|
21
|
-
]);
|
|
22
|
-
if (project.hasTypeScript) {
|
|
23
|
-
packagesToInstall.add('type-css-modules');
|
|
24
|
-
}
|
|
25
|
-
[...packagesToInstall].sort().forEach((packageName) => {
|
|
26
|
-
const version = getVersion(packageName, options);
|
|
27
|
-
devDependencies.set(packageName, version);
|
|
28
|
-
});
|
|
29
|
-
packageJson['devDependencies'] = convertToObject(devDependencies);
|
|
30
|
-
}
|
|
31
|
-
function updateScripts(packageJson, options) {
|
|
32
|
-
const { project } = options;
|
|
33
|
-
const scripts = convertToMap(packageJson.scripts);
|
|
34
|
-
if (project.hasTypeScript) {
|
|
35
|
-
scripts.set('prelint:types', 'type-css-modules --src app');
|
|
36
|
-
}
|
|
37
|
-
packageJson['scripts'] = convertToObject(scripts);
|
|
38
|
-
}
|
|
39
|
-
export function updatePackageJson(options) {
|
|
40
|
-
const { projectRoot } = options;
|
|
41
|
-
const packageJson = readPackageJson(options);
|
|
42
|
-
updateDevDependencies(packageJson, options);
|
|
43
|
-
updateScripts(packageJson, options);
|
|
44
|
-
const destination = join(projectRoot, 'package.json');
|
|
45
|
-
const file = JSON.stringify(packageJson, null, 2) + '\n';
|
|
46
|
-
writeFileSync(destination, file, 'utf8');
|
|
47
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { decideVersion } from '@codemod-utils/blueprints';
|
|
2
|
-
const latestVersions = new Map([
|
|
3
|
-
['@embroider/compat', '3.2.1'],
|
|
4
|
-
['@embroider/core', '3.2.1'],
|
|
5
|
-
['@embroider/webpack', '3.1.5'],
|
|
6
|
-
['autoprefixer', '10.4.15'],
|
|
7
|
-
['embroider-css-modules', '1.0.0'],
|
|
8
|
-
['postcss', '8.4.29'],
|
|
9
|
-
['postcss-loader', '7.3.3'],
|
|
10
|
-
['type-css-modules', '1.0.0'],
|
|
11
|
-
['webpack', '5.88.2'],
|
|
12
|
-
]);
|
|
13
|
-
export function getVersion(packageName, options) {
|
|
14
|
-
const { project } = options;
|
|
15
|
-
return decideVersion(packageName, {
|
|
16
|
-
dependencies: project.dependencies,
|
|
17
|
-
latestVersions,
|
|
18
|
-
});
|
|
19
|
-
}
|