Skip to content

Commit 367b78b

Browse files
committed
fix: more global resolve fixes + better error message for missing loaders
1 parent 76dda73 commit 367b78b

File tree

9 files changed

+70
-29
lines changed

9 files changed

+70
-29
lines changed

packages/@vue/cli-plugin-babel/index.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ module.exports = api => {
1010
.add(api.resolve('test'))
1111
.end()
1212
.use('cache-loader')
13-
.loader(require.resolve('cache-loader'))
13+
.loader('cache-loader')
1414
.options({ cacheDirectory })
1515
.end()
1616
.use('babel-loader')
17-
.loader(require.resolve('babel-loader'))
17+
.loader('babel-loader')
1818

1919
webpackConfig.module
2020
.rule('vue')
@@ -23,11 +23,11 @@ module.exports = api => {
2323
options.loaders = options.loaders || {}
2424
options.loaders.js = [
2525
{
26-
loader: require.resolve('cache-loader'),
26+
loader: 'cache-loader',
2727
options: { cacheDirectory }
2828
},
2929
{
30-
loader: require.resolve('babel-loader')
30+
loader: 'babel-loader'
3131
}
3232
]
3333
return options

packages/@vue/cli-plugin-eslint/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = (api, { lintOnSave }) => {
1111
.end()
1212
.test(/\.(vue|jsx?)$/)
1313
.use('eslint-loader')
14-
.loader(require.resolve('eslint-loader'))
14+
.loader('eslint-loader')
1515
.options(Object.assign(options, {
1616
formatter: require('eslint/lib/formatters/codeframe')
1717
}))

packages/@vue/cli-plugin-typescript/index.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ module.exports = (api, options) => {
2424
// this is pending on the readiness of @babel/preset-typescript.
2525
tsRule
2626
.use('cache-loader')
27-
.loader(require.resolve('cache-loader'))
27+
.loader('cache-loader')
2828
.options({ cacheDirectory })
2929
.end()
3030
.use('babel-loader')
31-
.loader(require.resolve('babel-loader'))
31+
.loader('babel-loader')
3232

3333
config.module
3434
.rule('vue')
@@ -41,19 +41,19 @@ module.exports = (api, options) => {
4141
if (api.hasPlugin('babel')) {
4242
tsRule
4343
.use('cache-loader')
44-
.loader(require.resolve('cache-loader'))
44+
.loader('cache-loader')
4545
.options({ cacheDirectory })
4646
.end()
4747
.use('babel-loader')
48-
.loader(require.resolve('babel-loader'))
48+
.loader('babel-loader')
4949
}
5050
tsRule
5151
.use('cache-loader-2')
52-
.loader(require.resolve('cache-loader'))
52+
.loader('cache-loader')
5353
.options({ cacheDirectory })
5454
.end()
5555
.use('ts-loader')
56-
.loader(require.resolve('ts-loader'))
56+
.loader('ts-loader')
5757
.options({
5858
transpileOnly: true,
5959
appendTsSuffixTo: [/\.vue$/]

packages/@vue/cli-service-global/lib/createConfigPlugin.js

+20-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
const path = require('path')
2+
const resolve = require('resolve')
23
const { findExisting } = require('./util')
34

45
module.exports = function createConfigPlugin (context, entry) {
56
return {
67
id: '@vue/cli-service-global-config',
7-
apply: api => {
8+
apply: (api, options) => {
89
api.chainWebpack(config => {
910
// entry is *.vue file, create alias for built-in js entry
1011
if (/\.vue$/.test(entry)) {
@@ -19,21 +20,29 @@ module.exports = function createConfigPlugin (context, entry) {
1920
}
2021
}
2122

22-
// include resolve for deps of this module.
23-
// when installed globally, the location may vary depending on
24-
// package managers their folder structures for global install.
25-
// so we first resolve the location of vue and then trace to the
26-
// install location.
23+
// ensure loaders can be resolved properly
2724
const modulePath = path.resolve(require.resolve('vue'), '../../../')
28-
29-
config.resolve
30-
.modules
31-
.add(modulePath)
32-
3325
config.resolveLoader
3426
.modules
3527
.add(modulePath)
3628

29+
// add resolve alias for vue and vue-hot-reload-api
30+
// but prioritize versions installed locally.
31+
try {
32+
resolve.sync('vue', { basedir: context })
33+
} catch (e) {
34+
const vuePath = path.dirname(require.resolve('vue'))
35+
config.resolve.alias
36+
.set('vue$', `${vuePath}/${options.compiler ? `vue.esm.js` : `vue.runtime.esm.js`}`)
37+
}
38+
39+
try {
40+
resolve.sync('vue-hot-reload-api', { basedir: context })
41+
} catch (e) {
42+
config.resolve.alias
43+
.set('vue-hot-reload-api', require.resolve('vue-hot-reload-api'))
44+
}
45+
3746
// set entry
3847
config
3948
.entry('app')

packages/@vue/cli-service-global/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@vue/cli-service": "^3.0.0-alpha.2",
2828
"chalk": "^2.3.0",
2929
"eslint-plugin-vue": "^4.2.0",
30+
"resolve": "^1.5.0",
3031
"vue": "^2.5.13"
3132
}
3233
}

packages/@vue/cli-service/lib/config/base.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ module.exports = (api, options) => {
4444
.rule('vue')
4545
.test(/\.vue$/)
4646
.use('vue-loader')
47-
.loader(require.resolve('vue-loader'))
47+
.loader('vue-loader')
4848
.options(Object.assign({}, options.vueLoader))
4949

5050
webpackConfig.module
5151
.rule('images')
5252
.test(/\.(png|jpe?g|gif)(\?.*)?$/)
5353
.use('url-loader')
54-
.loader(require.resolve('url-loader'))
54+
.loader('url-loader')
5555
.options({
5656
limit: 10000,
5757
name: `img/[name].[hash:8].[ext]`
@@ -63,7 +63,7 @@ module.exports = (api, options) => {
6363
.rule('svg')
6464
.test(/\.(svg)(\?.*)?$/)
6565
.use('file-loader')
66-
.loader(require.resolve('file-loader'))
66+
.loader('file-loader')
6767
.options({
6868
name: `img/[name].[hash:8].[ext]`
6969
})
@@ -72,7 +72,7 @@ module.exports = (api, options) => {
7272
.rule('media')
7373
.test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/)
7474
.use('url-loader')
75-
.loader(require.resolve('url-loader'))
75+
.loader('url-loader')
7676
.options({
7777
limit: 10000,
7878
name: `media/[name].[hash:8].[ext]`
@@ -82,7 +82,7 @@ module.exports = (api, options) => {
8282
.rule('fonts')
8383
.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/)
8484
.use('url-loader')
85-
.loader(require.resolve('url-loader'))
85+
.loader('url-loader')
8686
.options({
8787
limit: 10000,
8888
name: `fonts/[name].[hash:8].[ext]`

packages/@vue/cli-service/lib/config/dev.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@ module.exports = api => {
1818
.plugin('no-emit-on-errors')
1919
.use(require('webpack/lib/NoEmitOnErrorsPlugin'))
2020

21+
// friendly error plugin displays very confusing errors when webpack
22+
// fails to resolve a loader, so we provide custom handlers to improve it
23+
const { transformer, formatter } = require('../webpack/resolveLoaderError')
2124
webpackConfig
2225
.plugin('firendly-errors')
23-
.use(require('friendly-errors-webpack-plugin'))
26+
.use(require('friendly-errors-webpack-plugin'), [{
27+
additionalTransformers: [transformer],
28+
additionalFormatters: [formatter]
29+
}])
2430

2531
webpackConfig
2632
.plugin('watch-missing')

packages/@vue/cli-service/lib/config/prod.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ module.exports = (api, options) => {
194194
// .rule('vue')
195195
// .use('thread-loader')
196196
// .before('vue-loader')
197-
// .loader(require.resolve('thread-loader'))
197+
// .loader('thread-loader')
198198
// .options({ name: 'vue' })
199199
}
200200
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const chalk = require('chalk')
2+
const TYPE = 'cant-resolve-loader'
3+
const errorRE = /Can't resolve '(.*loader)'/
4+
5+
exports.transformer = error => {
6+
if (error.webpackError) {
7+
const match = error.webpackError.message.match(errorRE)
8+
if (match) {
9+
return Object.assign({}, error, {
10+
type: TYPE,
11+
loader: match[1]
12+
})
13+
}
14+
}
15+
return error
16+
}
17+
18+
exports.formatter = errors => {
19+
errors = errors.filter(e => e.type === TYPE)
20+
if (errors.length) {
21+
return errors.map(e => {
22+
return `Failed to resolve loader: ${chalk.yellow(e.loader)}`
23+
}).concat(`\nYou may need to install the missing loader.`)
24+
}
25+
}

0 commit comments

Comments
 (0)