UNPKG

4.45 kBJavaScriptView Raw
1const path = require('path')
2
3module.exports = (api, projectOptions) => {
4 const fs = require('fs')
5 const useThreads = process.env.NODE_ENV === 'production' && !!projectOptions.parallel
6
7 const { semver, loadModule } = require('@vue/cli-shared-utils')
8 const vue = loadModule('vue', api.service.context)
9 const isVue3 = (vue && semver.major(vue.version) === 3)
10
11 api.chainWebpack(config => {
12 config.resolveLoader.modules.prepend(path.join(__dirname, 'node_modules'))
13
14 if (!projectOptions.pages) {
15 config.entry('app')
16 .clear()
17 .add('./src/main.ts')
18 }
19
20 config.resolve
21 .extensions
22 .prepend('.ts')
23 .prepend('.tsx')
24
25 const tsRule = config.module.rule('ts').test(/\.ts$/)
26 const tsxRule = config.module.rule('tsx').test(/\.tsx$/)
27
28 // add a loader to both *.ts & vue<lang="ts">
29 const addLoader = ({ name, loader, options }) => {
30 tsRule.use(name).loader(loader).options(options)
31 tsxRule.use(name).loader(loader).options(options)
32 }
33
34 addLoader({
35 name: 'cache-loader',
36 loader: require.resolve('cache-loader'),
37 options: api.genCacheConfig('ts-loader', {
38 'ts-loader': require('ts-loader/package.json').version,
39 'typescript': require('typescript/package.json').version,
40 modern: !!process.env.VUE_CLI_MODERN_BUILD
41 }, 'tsconfig.json')
42 })
43
44 if (useThreads) {
45 addLoader({
46 name: 'thread-loader',
47 loader: require.resolve('thread-loader'),
48 options:
49 typeof projectOptions.parallel === 'number'
50 ? { workers: projectOptions.parallel }
51 : {}
52 })
53 }
54
55 if (api.hasPlugin('babel')) {
56 addLoader({
57 // TODO: I guess the intent is to require the `babel-loader` provided by the Babel vue
58 // plugin, but that means we now rely on the hoisting. It should instead be queried
59 // against the plugin itself, or through a peer dependency.
60 name: 'babel-loader',
61 // eslint-disable-next-line node/no-extraneous-require
62 loader: require.resolve('babel-loader')
63 })
64 }
65 addLoader({
66 name: 'ts-loader',
67 loader: require.resolve('ts-loader'),
68 options: {
69 transpileOnly: true,
70 appendTsSuffixTo: ['\\.vue$'],
71 // https://github.com/TypeStrong/ts-loader#happypackmode-boolean-defaultfalse
72 happyPackMode: useThreads
73 }
74 })
75 // make sure to append TSX suffix
76 tsxRule.use('ts-loader').loader(require.resolve('ts-loader')).tap(options => {
77 options = Object.assign({}, options)
78 delete options.appendTsSuffixTo
79 options.appendTsxSuffixTo = ['\\.vue$']
80 return options
81 })
82
83 // this plugin does not play well with jest + cypress setup (tsPluginE2e.spec.js) somehow
84 // so temporarily disabled for vue-cli tests
85 if (!process.env.VUE_CLI_TEST) {
86 if (isVue3) {
87 config
88 .plugin('fork-ts-checker')
89 .use(require('fork-ts-checker-webpack-plugin-v5'), [{
90 typescript: {
91 extensions: {
92 vue: {
93 enabled: true,
94 compiler: '@vue/compiler-sfc'
95 }
96 },
97 diagnosticOptions: {
98 semantic: true,
99 // https://github.com/TypeStrong/ts-loader#happypackmode
100 syntactic: useThreads
101 }
102 }
103 }])
104 } else {
105 config
106 .plugin('fork-ts-checker')
107 .use(require('fork-ts-checker-webpack-plugin'), [{
108 vue: { enabled: true, compiler: 'vue-template-compiler' },
109 tslint: projectOptions.lintOnSave !== false && fs.existsSync(api.resolve('tslint.json')),
110 formatter: 'codeframe',
111 // https://github.com/TypeStrong/ts-loader#happypackmode-boolean-defaultfalse
112 checkSyntacticErrors: useThreads
113 }])
114 }
115 }
116 })
117
118 if (!api.hasPlugin('eslint')) {
119 api.registerCommand('lint', {
120 description: 'lint source files with TSLint',
121 usage: 'vue-cli-service lint [options] [...files]',
122 options: {
123 '--format [formatter]': 'specify formatter (default: codeFrame)',
124 '--no-fix': 'do not fix errors',
125 '--formatters-dir [dir]': 'formatter directory',
126 '--rules-dir [dir]': 'rules directory'
127 }
128 }, args => {
129 return require('./lib/tslint')(args, api)
130 })
131 }
132}