From 0a5c79be524c838228fbfd8760a83258fafcc940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 4 Nov 2019 09:26:34 +0100 Subject: [PATCH] Enforces require.resolve for loaders (#4532) * Enforces require.resolve for loaders * Updates the lockfile * Fixes more things * Adds an extra check * test(loaders): fix the tests * style(cli): fix the linting * style(cli): fix the linting (on windows) * Update package.json * Updates the lockfile * chore: sync dependency versions * chore: sync dependency versions * chore: don't introduce unnecessary changes in yarn.lock * extraneous space --- packages/@vue/babel-preset-app/package.json | 3 +++ packages/@vue/cli-plugin-babel/index.js | 6 ++--- packages/@vue/cli-plugin-babel/package.json | 2 ++ .../__tests__/tsPluginBabel.spec.js | 6 ++--- packages/@vue/cli-plugin-typescript/index.js | 14 ++++++---- .../@vue/cli-plugin-typescript/package.json | 2 ++ .../@vue/cli-service/__tests__/css.spec.js | 5 +++- packages/@vue/cli-service/lib/config/base.js | 26 ++++++++++++------- packages/@vue/cli-service/lib/config/css.js | 17 ++++++++---- packages/@vue/cli-service/package.json | 18 +++++++++++++ packages/@vue/cli-ui/index.js | 2 +- 11 files changed, 74 insertions(+), 27 deletions(-) diff --git a/packages/@vue/babel-preset-app/package.json b/packages/@vue/babel-preset-app/package.json index 41cdbb8dbf..50f38b4225 100644 --- a/packages/@vue/babel-preset-app/package.json +++ b/packages/@vue/babel-preset-app/package.json @@ -37,5 +37,8 @@ "babel-plugin-module-resolver": "^3.2.0", "core-js": "^3.3.2", "core-js-compat": "^3.3.2" + }, + "peerDependencies": { + "@babel/core": "*" } } diff --git a/packages/@vue/cli-plugin-babel/index.js b/packages/@vue/cli-plugin-babel/index.js index ac55104372..182b2f539b 100644 --- a/packages/@vue/cli-plugin-babel/index.js +++ b/packages/@vue/cli-plugin-babel/index.js @@ -45,7 +45,7 @@ module.exports = (api, options) => { }) .end() .use('cache-loader') - .loader('cache-loader') + .loader(require.resolve('cache-loader')) .options(api.genCacheConfig('babel-loader', { '@babel/core': require('@babel/core/package.json').version, '@vue/babel-preset-app': require('@vue/babel-preset-app/package.json').version, @@ -61,7 +61,7 @@ module.exports = (api, options) => { if (useThreads) { const threadLoaderConfig = jsRule .use('thread-loader') - .loader('thread-loader') + .loader(require.resolve('thread-loader')) if (typeof options.parallel === 'number') { threadLoaderConfig.options({ workers: options.parallel }) @@ -70,6 +70,6 @@ module.exports = (api, options) => { jsRule .use('babel-loader') - .loader('babel-loader') + .loader(require.resolve('babel-loader')) }) } diff --git a/packages/@vue/cli-plugin-babel/package.json b/packages/@vue/cli-plugin-babel/package.json index b5caf6284b..742b2e899c 100644 --- a/packages/@vue/cli-plugin-babel/package.json +++ b/packages/@vue/cli-plugin-babel/package.json @@ -24,6 +24,8 @@ "@vue/babel-preset-app": "^4.0.5", "@vue/cli-shared-utils": "^4.0.5", "babel-loader": "^8.0.6", + "cache-loader": "^4.1.0", + "thread-loader": "^2.1.3", "webpack": "^4.0.0" }, "peerDependencies": { diff --git a/packages/@vue/cli-plugin-typescript/__tests__/tsPluginBabel.spec.js b/packages/@vue/cli-plugin-typescript/__tests__/tsPluginBabel.spec.js index 55c98790c1..42b1af65d9 100644 --- a/packages/@vue/cli-plugin-typescript/__tests__/tsPluginBabel.spec.js +++ b/packages/@vue/cli-plugin-typescript/__tests__/tsPluginBabel.spec.js @@ -16,9 +16,9 @@ test('using correct loader', () => { const config = service.resolveWebpackConfig() // eslint-disable-next-line no-shadow const rule = config.module.rules.find(rule => rule.test.test('foo.ts')) - expect(rule.use[0].loader).toMatch('cache-loader') - expect(rule.use[1].loader).toMatch('babel-loader') - expect(rule.use[2].loader).toMatch('ts-loader') + expect(rule.use[0].loader).toMatch(require.resolve('cache-loader')) + expect(rule.use[1].loader).toMatch(require.resolve('babel-loader')) + expect(rule.use[2].loader).toMatch(require.resolve('ts-loader')) }) const creatorOptions = { diff --git a/packages/@vue/cli-plugin-typescript/index.js b/packages/@vue/cli-plugin-typescript/index.js index e01d681cda..a6f8aef9e6 100644 --- a/packages/@vue/cli-plugin-typescript/index.js +++ b/packages/@vue/cli-plugin-typescript/index.js @@ -28,7 +28,7 @@ module.exports = (api, projectOptions) => { } addLoader({ - loader: 'cache-loader', + loader: require.resolve('cache-loader'), options: api.genCacheConfig('ts-loader', { 'ts-loader': require('ts-loader/package.json').version, 'typescript': require('typescript/package.json').version, @@ -38,7 +38,7 @@ module.exports = (api, projectOptions) => { if (useThreads) { addLoader({ - loader: 'thread-loader', + loader: require.resolve('thread-loader'), options: typeof projectOptions.parallel === 'number' ? { workers: projectOptions.parallel } @@ -48,11 +48,15 @@ module.exports = (api, projectOptions) => { if (api.hasPlugin('babel')) { addLoader({ - loader: 'babel-loader' + // TODO: I guess the intent is to require the `babel-loader` provided by the Babel vue + // plugin, but that means we now rely on the hoisting. It should instead be queried + // against the plugin itself, or through a peer dependency. + // eslint-disable-next-line node/no-extraneous-require + loader: require.resolve('babel-loader') }) } addLoader({ - loader: 'ts-loader', + loader: require.resolve('ts-loader'), options: { transpileOnly: true, appendTsSuffixTo: ['\\.vue$'], @@ -61,7 +65,7 @@ module.exports = (api, projectOptions) => { } }) // make sure to append TSX suffix - tsxRule.use('ts-loader').loader('ts-loader').tap(options => { + tsxRule.use('ts-loader').loader(require.resolve('ts-loader')).tap(options => { options = Object.assign({}, options) delete options.appendTsSuffixTo options.appendTsxSuffixTo = ['\\.vue$'] diff --git a/packages/@vue/cli-plugin-typescript/package.json b/packages/@vue/cli-plugin-typescript/package.json index f9fbda6819..c4eea0d009 100644 --- a/packages/@vue/cli-plugin-typescript/package.json +++ b/packages/@vue/cli-plugin-typescript/package.json @@ -25,8 +25,10 @@ "dependencies": { "@types/webpack-env": "^1.13.9", "@vue/cli-shared-utils": "^4.0.5", + "cache-loader": "^4.1.0", "fork-ts-checker-webpack-plugin": "^1.5.1", "globby": "^9.2.0", + "thread-loader": "^2.1.3", "ts-loader": "^6.2.0", "tslint": "^5.16.0", "webpack": "^4.0.0", diff --git a/packages/@vue/cli-service/__tests__/css.spec.js b/packages/@vue/cli-service/__tests__/css.spec.js index 6704ee3a27..77629de1df 100644 --- a/packages/@vue/cli-service/__tests__/css.spec.js +++ b/packages/@vue/cli-service/__tests__/css.spec.js @@ -44,7 +44,10 @@ const findLoaders = (config, lang, index) => { if (!rule) { throw new Error(`rule not found for ${lang}`) } - return rule.use.map(({ loader }) => loader.replace(/-loader$/, '')) + return rule.use.map(({ loader }) => { + const match = loader.match(/([^\\/]+)-loader/) + return match ? match[1] : loader + }) } const findOptions = (config, lang, _loader, index) => { diff --git a/packages/@vue/cli-service/lib/config/base.js b/packages/@vue/cli-service/lib/config/base.js index d38d06c498..a9c17adcf4 100644 --- a/packages/@vue/cli-service/lib/config/base.js +++ b/packages/@vue/cli-service/lib/config/base.js @@ -77,11 +77,11 @@ module.exports = (api, options) => { .rule('vue') .test(/\.vue$/) .use('cache-loader') - .loader('cache-loader') + .loader(require.resolve('cache-loader')) .options(vueLoaderCacheConfig) .end() .use('vue-loader') - .loader('vue-loader') + .loader(require.resolve('vue-loader')) .options(Object.assign({ compilerOptions: { whitespace: 'condense' @@ -98,7 +98,7 @@ module.exports = (api, options) => { .rule('images') .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/) .use('url-loader') - .loader('url-loader') + .loader(require.resolve('url-loader')) .options(genUrlLoaderOptions('img')) // do not base64-inline SVGs. @@ -107,7 +107,7 @@ module.exports = (api, options) => { .rule('svg') .test(/\.(svg)(\?.*)?$/) .use('file-loader') - .loader('file-loader') + .loader(require.resolve('file-loader')) .options({ name: genAssetSubPath('img') }) @@ -116,33 +116,41 @@ module.exports = (api, options) => { .rule('media') .test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/) .use('url-loader') - .loader('url-loader') + .loader(require.resolve('url-loader')) .options(genUrlLoaderOptions('media')) webpackConfig.module .rule('fonts') .test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i) .use('url-loader') - .loader('url-loader') + .loader(require.resolve('url-loader')) .options(genUrlLoaderOptions('fonts')) // Other common pre-processors --------------------------------------------- + const maybeResolve = name => { + try { + return require.resolve(name) + } catch (error) { + return name + } + } + webpackConfig.module .rule('pug') .test(/\.pug$/) .oneOf('pug-vue') .resourceQuery(/vue/) .use('pug-plain-loader') - .loader('pug-plain-loader') + .loader(maybeResolve('pug-plain-loader')) .end() .end() .oneOf('pug-template') .use('raw') - .loader('raw-loader') + .loader(maybeResolve('raw-loader')) .end() .use('pug-plain-loader') - .loader('pug-plain-loader') + .loader(maybeResolve('pug-plain-loader')) .end() .end() diff --git a/packages/@vue/cli-service/lib/config/css.js b/packages/@vue/cli-service/lib/config/css.js index 96db04d7c9..0b4b9f6ef7 100644 --- a/packages/@vue/cli-service/lib/config/css.js +++ b/packages/@vue/cli-service/lib/config/css.js @@ -128,7 +128,7 @@ module.exports = (api, rootOptions) => { } else { rule .use('vue-style-loader') - .loader('vue-style-loader') + .loader(require.resolve('vue-style-loader')) .options({ sourceMap, shadowMode @@ -155,13 +155,13 @@ module.exports = (api, rootOptions) => { rule .use('css-loader') - .loader('css-loader') + .loader(require.resolve('css-loader')) .options(cssLoaderOptions) if (needInlineMinification) { rule .use('cssnano') - .loader('postcss-loader') + .loader(require.resolve('postcss-loader')) .options({ sourceMap, plugins: [require('cssnano')(cssnanoOptions)] @@ -171,14 +171,21 @@ module.exports = (api, rootOptions) => { if (hasPostCSSConfig) { rule .use('postcss-loader') - .loader('postcss-loader') + .loader(require.resolve('postcss-loader')) .options(Object.assign({ sourceMap }, loaderOptions.postcss)) } if (loader) { + let resolvedLoader + try { + resolvedLoader = require.resolve(loader) + } catch (error) { + resolvedLoader = loader + } + rule .use(loader) - .loader(loader) + .loader(resolvedLoader) .options(Object.assign({ sourceMap }, options)) } } diff --git a/packages/@vue/cli-service/package.json b/packages/@vue/cli-service/package.json index 4a4a2c601b..bd943027ca 100644 --- a/packages/@vue/cli-service/package.json +++ b/packages/@vue/cli-service/package.json @@ -75,6 +75,7 @@ "thread-loader": "^2.1.3", "url-loader": "^2.2.0", "vue-loader": "^15.7.0", + "vue-style-loader": "^4.1.0", "webpack": "^4.0.0", "webpack-bundle-analyzer": "^3.6.0", "webpack-chain": "^6.0.0", @@ -84,6 +85,23 @@ "peerDependencies": { "vue-template-compiler": "^2.0.0" }, + "peerDependenciesMeta": { + "less-loader": { + "optional": true + }, + "pug-plain-loader": { + "optional": true + }, + "raw-loader": { + "optional": true + }, + "sass-loader": { + "optional": true + }, + "stylus-loader": { + "optional": true + } + }, "devDependencies": { "fibers": ">= 3.1.1 <5.0.0", "sass": "^1.19.0", diff --git a/packages/@vue/cli-ui/index.js b/packages/@vue/cli-ui/index.js index 02cb14e15f..0f7722cb89 100644 --- a/packages/@vue/cli-ui/index.js +++ b/packages/@vue/cli-ui/index.js @@ -23,7 +23,7 @@ exports.clientAddonConfig = function ({ id, port = 8042 }) { .rule('gql') .test(/\.(gql|graphql)$/) .use('gql-loader') - .loader('graphql-tag/loader') + .loader(require.resolve('graphql-tag/loader')) .end() }, devServer: {