const fs = require('fs') const path = require('path') const { chalk, semver, loadModule } = require('@vue/cli-shared-utils') const isAbsoluteUrl = require('../util/isAbsoluteUrl') const findExisting = (context, files) => { for (const file of files) { if (fs.existsSync(path.join(context, file))) { return file } } } module.exports = (api, rootOptions) => { api.chainWebpack(webpackConfig => { const getAssetPath = require('../util/getAssetPath') const shadowMode = !!process.env.VUE_CLI_CSS_SHADOW_MODE const isProd = process.env.NODE_ENV === 'production' const { extract = isProd, sourceMap = false, loaderOptions = {} } = rootOptions.css || {} const shouldExtract = extract !== false && !shadowMode const filename = getAssetPath( rootOptions, `css/[name]${rootOptions.filenameHashing ? '.[contenthash:8]' : ''}.css` ) const extractOptions = Object.assign({ filename, chunkFilename: filename }, extract && typeof extract === 'object' ? extract : {}) // when project publicPath is a relative path // use relative publicPath in extracted CSS based on extract location const cssPublicPath = (isAbsoluteUrl(rootOptions.publicPath) || rootOptions.publicPath.startsWith('/')) ? rootOptions.publicPath : process.env.VUE_CLI_BUILD_TARGET === 'lib' // in lib mode, CSS is extracted to dist root. ? './' : '../'.repeat( extractOptions.filename .replace(/^\.[/\\]/, '') .split(/[/\\]/g) .length - 1 ) // check if the project has a valid postcss config // if it doesn't, don't use postcss-loader for direct style imports // because otherwise it would throw error when attempting to load postcss config const hasPostCSSConfig = !!(loaderOptions.postcss || api.service.pkg.postcss || findExisting(api.resolve('.'), [ '.postcssrc', '.postcssrc.js', 'postcss.config.js', '.postcssrc.yaml', '.postcssrc.json' ])) if (!hasPostCSSConfig) { // #6342 // NPM 6 may incorrectly hoist postcss 7 to the same level of autoprefixer // So we have to run a preflight check to tell the users how to fix it const autoprefixerDirectory = path.dirname(require.resolve('autoprefixer/package.json')) const postcssPkg = loadModule('postcss/package.json', autoprefixerDirectory) const postcssVersion = postcssPkg.version if (!semver.satisfies(postcssVersion, '8.x')) { throw new Error( `The package manager has hoisted a wrong version of ${chalk.cyan('postcss')}, ` + `please run ${chalk.cyan('npm i postcss@8 -D')} to fix it.` ) } loaderOptions.postcss = { postcssOptions: { plugins: [ require('autoprefixer') ] } } } // if building for production but not extracting CSS, we need to minimize // the embbeded inline CSS as they will not be going through the optimizing // plugin. const needInlineMinification = isProd && !shouldExtract const cssnanoOptions = { preset: ['default', { mergeLonghand: false, cssDeclarationSorter: false }] } if (rootOptions.productionSourceMap && sourceMap) { cssnanoOptions.map = { inline: false } } function createCSSRule (lang, test, loader, options) { const baseRule = webpackConfig.module.rule(lang).test(test) // rules for