Spaces:
Sleeping
Sleeping
| const fs = require('fs') | |
| const path = require('path') | |
| const { semver, warn, pauseSpinner, resumeSpinner } = require('@vue/cli-shared-utils') | |
| 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' | |
| let sassLoaderVersion | |
| try { | |
| sassLoaderVersion = semver.major(require('sass-loader/package.json').version) | |
| } catch (e) {} | |
| if (sassLoaderVersion < 8) { | |
| pauseSpinner() | |
| warn('A new version of sass-loader is available. Please upgrade for best experience.') | |
| resumeSpinner() | |
| } | |
| const defaultSassLoaderOptions = {} | |
| try { | |
| defaultSassLoaderOptions.implementation = require('sass') | |
| // since sass-loader 8, fibers will be automatically detected and used | |
| if (sassLoaderVersion < 8) { | |
| defaultSassLoaderOptions.fiber = require('fibers') | |
| } | |
| } catch (e) {} | |
| const { | |
| extract = isProd, | |
| sourceMap = false, | |
| loaderOptions = {} | |
| } = rootOptions.css || {} | |
| let { requireModuleExtension } = rootOptions.css || {} | |
| if (typeof requireModuleExtension === 'undefined') { | |
| if (loaderOptions.css && loaderOptions.css.modules) { | |
| throw new Error('`css.requireModuleExtension` is required when custom css modules options provided') | |
| } | |
| requireModuleExtension = true | |
| } | |
| 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 : {}) | |
| // use relative publicPath in extracted CSS based on extract location | |
| const cssPublicPath = 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) { | |
| loaderOptions.postcss = { | |
| 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 <style lang="module"> | |
| const vueModulesRule = baseRule.oneOf('vue-modules').resourceQuery(/module/) | |
| applyLoaders(vueModulesRule, true) | |
| // rules for <style> | |
| const vueNormalRule = baseRule.oneOf('vue').resourceQuery(/\?vue/) | |
| applyLoaders(vueNormalRule, false) | |
| // rules for *.module.* files | |
| const extModulesRule = baseRule.oneOf('normal-modules').test(/\.module\.\w+$/) | |
| applyLoaders(extModulesRule, true) | |
| // rules for normal CSS imports | |
| const normalRule = baseRule.oneOf('normal') | |
| applyLoaders(normalRule, !requireModuleExtension) | |
| function applyLoaders (rule, isCssModule) { | |
| if (shouldExtract) { | |
| rule | |
| .use('extract-css-loader') | |
| .loader(require('mini-css-extract-plugin').loader) | |
| .options({ | |
| hmr: !isProd, | |
| publicPath: cssPublicPath | |
| }) | |
| } else { | |
| rule | |
| .use('vue-style-loader') | |
| .loader(require.resolve('vue-style-loader')) | |
| .options({ | |
| sourceMap, | |
| shadowMode | |
| }) | |
| } | |
| const cssLoaderOptions = Object.assign({ | |
| sourceMap, | |
| importLoaders: ( | |
| 1 + // stylePostLoader injected by vue-loader | |
| 1 + // postcss-loader | |
| (needInlineMinification ? 1 : 0) | |
| ) | |
| }, loaderOptions.css) | |
| if (isCssModule) { | |
| cssLoaderOptions.modules = { | |
| localIdentName: '[name]_[local]_[hash:base64:5]', | |
| ...cssLoaderOptions.modules | |
| } | |
| } else { | |
| delete cssLoaderOptions.modules | |
| } | |
| rule | |
| .use('css-loader') | |
| .loader(require.resolve('css-loader')) | |
| .options(cssLoaderOptions) | |
| if (needInlineMinification) { | |
| rule | |
| .use('cssnano') | |
| .loader(require.resolve('postcss-loader')) | |
| .options({ | |
| sourceMap, | |
| plugins: [require('cssnano')(cssnanoOptions)] | |
| }) | |
| } | |
| rule | |
| .use('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(resolvedLoader) | |
| .options(Object.assign({ sourceMap }, options)) | |
| } | |
| } | |
| } | |
| createCSSRule('css', /\.css$/) | |
| createCSSRule('postcss', /\.p(ost)?css$/) | |
| createCSSRule('scss', /\.scss$/, 'sass-loader', Object.assign( | |
| {}, | |
| defaultSassLoaderOptions, | |
| loaderOptions.scss || loaderOptions.sass | |
| )) | |
| if (sassLoaderVersion < 8) { | |
| createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign( | |
| {}, | |
| defaultSassLoaderOptions, | |
| { | |
| indentedSyntax: true | |
| }, | |
| loaderOptions.sass | |
| )) | |
| } else { | |
| createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign( | |
| {}, | |
| defaultSassLoaderOptions, | |
| loaderOptions.sass, | |
| { | |
| sassOptions: Object.assign( | |
| {}, | |
| loaderOptions.sass && loaderOptions.sass.sassOptions, | |
| { | |
| indentedSyntax: true | |
| } | |
| ) | |
| } | |
| )) | |
| } | |
| createCSSRule('less', /\.less$/, 'less-loader', loaderOptions.less) | |
| createCSSRule('stylus', /\.styl(us)?$/, 'stylus-loader', Object.assign({ | |
| preferPathResolver: 'webpack' | |
| }, loaderOptions.stylus)) | |
| // inject CSS extraction plugin | |
| if (shouldExtract) { | |
| webpackConfig | |
| .plugin('extract-css') | |
| .use(require('mini-css-extract-plugin'), [extractOptions]) | |
| // minify extracted CSS | |
| if (isProd) { | |
| webpackConfig | |
| .plugin('optimize-css') | |
| .use(require('@intervolga/optimize-cssnano-plugin'), [{ | |
| sourceMap: rootOptions.productionSourceMap && sourceMap, | |
| cssnanoOptions | |
| }]) | |
| } | |
| } | |
| }) | |
| } | |