Skip to content

Commit 4d6b5fb

Browse files
committed
fix: resolve vue.js cache bug and add e2e tests
1 parent 8b383df commit 4d6b5fb

File tree

4 files changed

+204
-30
lines changed

4 files changed

+204
-30
lines changed

README.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* Faster [TypeScript](https://github.com/Microsoft/TypeScript) type checking and [ESLint](https://eslint.org/) linting (each on a separate process) 🏎
1818
* Support for modern TypeScript features like [project references](https://www.typescriptlang.org/docs/handbook/project-references.html) and [incremental mode](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#faster-subsequent-builds-with-the---incremental-flag)
1919
* Support for [Yarn PnP](https://classic.yarnpkg.com/en/docs/pnp/) 🧶
20+
* Support for [Vue Single File Component](https://vuejs.org/v2/guide/single-file-components.html) ✅ 
2021
* Nice errors reporting with the [code frame](https://babeljs.io/docs/en/next/babel-code-frame.html) formatter 🌈
2122

2223
## Installation
@@ -194,6 +195,10 @@ Options for the issues filtering (`issues` option object).
194195
| `exclude` | `object` or `function` or `array` | `undefined` | Same as `include` but issues that match this predicate will be excluded. |
195196

196197
## Yarn PnP
198+
To enable Yarn PnP support, follow these steps:
199+
200+
<details>
201+
<summary>Expand Yarn PnP set up instruction</summary>
197202

198203
To enable Yarn PnP, you have to install [`ts-pnp`](https://github.com/arcanis/ts-pnp) and [`pnp-webpack-plugin`](https://github.com/arcanis/pnp-webpack-plugin) package:
199204

@@ -243,6 +248,109 @@ module.exports = {
243248
]
244249
};
245250
```
251+
</details>
252+
253+
## Vue.js
254+
To enable Vue.js support, follow these steps:
255+
256+
<details>
257+
<summary>Expand Vue.js set up instruction</summary>
258+
259+
1. Ensure you have all required packages installed:
260+
```sh
261+
# with npm
262+
npm install --save vue vue-class-component
263+
npm install --save-dev vue-loader ts-loader css-loader vue-template-compiler
264+
265+
# with yarn
266+
yarn add vue vue-class-component
267+
yarn add --dev vue-loader ts-loader css-loader vue-template-compiler
268+
```
269+
270+
2. Add `tsconfig.json` configuration:
271+
```json
272+
{
273+
"compilerOptions": {
274+
"experimentalDecorators": true,
275+
"jsx": "preserve",
276+
"target": "ES5",
277+
"lib": ["ES6", "DOM"],
278+
"baseUrl": ".",
279+
"paths": {
280+
"@/*": ["src/*"],
281+
"~/*": ["src/*"]
282+
},
283+
"sourceMap": true
284+
},
285+
"include": [
286+
"src/**/*.ts",
287+
"src/**/*.vue"
288+
],
289+
"exclude": [
290+
"node_modules"
291+
]
292+
}
293+
```
294+
295+
3. Add `webpack.config.js` configuration:
296+
```js
297+
const path = require('path');
298+
const VueLoaderPlugin = require('vue-loader/lib/plugin');
299+
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
300+
301+
module.exports = {
302+
entry: './src/index.ts',
303+
output: {
304+
filename: 'index.js',
305+
path: path.resolve(__dirname, 'dist'),
306+
},
307+
module: {
308+
rules: [
309+
{
310+
test: /\.vue$/,
311+
loader: 'vue-loader'
312+
},
313+
{
314+
test: /\.ts$/,
315+
loader: 'ts-loader',
316+
exclude: /node_modules/,
317+
options: {
318+
appendTsSuffixTo: [/\.vue$/]
319+
}
320+
},
321+
],
322+
},
323+
resolve: {
324+
extensions: ['.ts', '.js', '.vue', '.json'],
325+
alias: {
326+
'@': path.resolve(__dirname, './src'),
327+
'~': path.resolve(__dirname, './src'),
328+
}
329+
},
330+
plugins: [
331+
new VueLoaderPlugin(),
332+
new ForkTsCheckerWebpackPlugin({
333+
typescript: {
334+
extensions: {
335+
vue: true
336+
}
337+
}
338+
})
339+
]
340+
};
341+
```
342+
343+
4. Add `src/types/vue.d.ts` file to shim `.vue` modules:
344+
```typescript
345+
declare module "*.vue" {
346+
import Vue from "vue";
347+
export default Vue;
348+
}
349+
```
350+
351+
5. If you are working in VSCode, you can get the [Vetur](https://marketplace.visualstudio.com/items?itemName=octref.vetur) extension to complete the developer workflow.
352+
353+
</details>
246354

247355
## Type-Only modules watching
248356

src/typescript-reporter/extension/TypeScriptEmbeddedExtension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ function createTypeScriptEmbeddedExtension({
122122
return host.watchFile(
123123
embeddedFileName,
124124
(innerFileName: string, eventKind: ts.FileWatcherEventKind) => {
125-
embeddedSourceCache.delete(innerFileName);
125+
embeddedSourceCache.delete(embeddedFileName);
126126
return callback(fileName, eventKind);
127127
},
128128
poolingInterval

test/e2e/TypeScriptVueExtension.spec.ts

Lines changed: 89 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,33 +22,93 @@ describe('TypeScript Vue Extension', () => {
2222
await sandbox.cleanup();
2323
});
2424

25-
it.each([{ async: true, webpack: '^4.0.0', typescript: '2.7.1', tsloader: '^5.0.0' }])(
26-
'reports semantic error for %p',
27-
async ({ async, webpack, typescript, tsloader }) => {
28-
await sandbox.load([
29-
await readFixture(join(__dirname, 'fixtures/environment/typescript-vue.fixture'), {
30-
FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION: JSON.stringify(
31-
FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION
32-
),
33-
TS_LOADER_VERSION: JSON.stringify(tsloader),
34-
TYPESCRIPT_VERSION: JSON.stringify(typescript),
35-
WEBPACK_VERSION: JSON.stringify(webpack),
36-
WEBPACK_CLI_VERSION: JSON.stringify(WEBPACK_CLI_VERSION),
37-
WEBPACK_DEV_SERVER_VERSION: JSON.stringify(WEBPACK_DEV_SERVER_VERSION),
38-
ASYNC: JSON.stringify(async),
39-
}),
40-
await readFixture(join(__dirname, 'fixtures/implementation/typescript-vue.fixture')),
41-
]);
42-
43-
const driver = createWebpackDevServerDriver(
44-
sandbox.spawn('npm run webpack-dev-server'),
45-
async
46-
);
47-
48-
// first compilation is successful
49-
await driver.waitForNoErrors();
50-
51-
// TODO: it seems that single-file components are broken on the ts-loader/typescript side
52-
}
53-
);
25+
it.each([
26+
{ async: true, typescript: '2.7.1', tsloader: '^5.0.0' },
27+
{ async: false, typescript: '~3.0.0', tsloader: '^5.0.0' },
28+
{ async: true, typescript: '~3.6.0', tsloader: '^6.0.0' },
29+
{ async: false, typescript: '^3.8.0', tsloader: '^7.0.0' },
30+
])('reports semantic error for %p', async ({ async, typescript, tsloader }) => {
31+
await sandbox.load([
32+
await readFixture(join(__dirname, 'fixtures/environment/typescript-vue.fixture'), {
33+
FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION: JSON.stringify(
34+
FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION
35+
),
36+
TS_LOADER_VERSION: JSON.stringify(tsloader),
37+
TYPESCRIPT_VERSION: JSON.stringify(typescript),
38+
WEBPACK_VERSION: JSON.stringify('^4.0.0'),
39+
WEBPACK_CLI_VERSION: JSON.stringify(WEBPACK_CLI_VERSION),
40+
WEBPACK_DEV_SERVER_VERSION: JSON.stringify(WEBPACK_DEV_SERVER_VERSION),
41+
ASYNC: JSON.stringify(async),
42+
}),
43+
await readFixture(join(__dirname, 'fixtures/implementation/typescript-vue.fixture')),
44+
]);
45+
46+
const driver = createWebpackDevServerDriver(sandbox.spawn('npm run webpack-dev-server'), async);
47+
let errors: string[] = [];
48+
49+
// first compilation is successful
50+
await driver.waitForNoErrors();
51+
52+
// let's modify user model file
53+
await sandbox.patch(
54+
'src/component/LoggedIn.vue',
55+
"import User, { getUserName } from '@/model/User';",
56+
"import User from '@/model/User';"
57+
);
58+
59+
// next compilation should have missing function error
60+
errors = await driver.waitForErrors();
61+
expect(errors).toEqual([
62+
[
63+
'ERROR in src/component/LoggedIn.vue 28:24-35',
64+
"TS2304: Cannot find name 'getUserName'.",
65+
' 26 | ',
66+
' 27 | get userName() {',
67+
" > 28 | return this.user ? getUserName(this.user) : '';",
68+
' | ^^^^^^^^^^^',
69+
' 29 | }',
70+
' 30 | ',
71+
' 31 | async logout() {',
72+
].join('\n'),
73+
]);
74+
75+
// let's fix it
76+
await sandbox.patch(
77+
'src/component/LoggedIn.vue',
78+
"return this.user ? getUserName(this.user) : '';",
79+
"return this.user ? `${this.user.firstName} ${this.user.lastName}` : '';"
80+
);
81+
82+
await driver.waitForNoErrors();
83+
84+
// let's modify user model file again
85+
await sandbox.patch('src/model/User.ts', ' firstName?: string;\n', '');
86+
87+
// not we should have an error about missing firstName property
88+
errors = await driver.waitForErrors();
89+
expect(errors).toEqual([
90+
[
91+
'ERROR in src/component/LoggedIn.vue 28:37-46',
92+
"TS2339: Property 'firstName' does not exist on type 'User'.",
93+
' 26 | ',
94+
' 27 | get userName() {',
95+
" > 28 | return this.user ? `${this.user.firstName} ${this.user.lastName}` : '';",
96+
' | ^^^^^^^^^',
97+
' 29 | }',
98+
' 30 | ',
99+
' 31 | async logout() {',
100+
].join('\n'),
101+
[
102+
'ERROR in src/model/User.ts 11:16-25',
103+
"TS2339: Property 'firstName' does not exist on type 'User'.",
104+
' 9 | ',
105+
' 10 | function getUserName(user: User): string {',
106+
' > 11 | return [user.firstName, user.lastName]',
107+
' | ^^^^^^^^^',
108+
' 12 | .filter(name => name !== undefined)',
109+
" 13 | .join(' ');",
110+
' 14 | }',
111+
].join('\n'),
112+
]);
113+
});
54114
});

test/e2e/fixtures/environment/typescript-vue.fixture

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,9 @@ module.exports = {
9696
})
9797
]
9898
};
99+
100+
/// src/vue-shim.d.ts
101+
declare module "*.vue" {
102+
import Vue from "vue";
103+
export default Vue;
104+
}

0 commit comments

Comments
 (0)