travel/admin/node_modules/@vue/cli-service/lib/config/css.js

254 lines
7.5 KiB
JavaScript
Raw Normal View History

2024-06-24 11:28:18 +08:00
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
}])
}
}
})
}