zoro-cli
Version:
https://github.com/vuejs/vue-cli
194 lines (174 loc) • 5.74 kB
JavaScript
const fs = require('fs')
const path = require('path')
const { resolveCwd } = require('zoro-cli-util/resolve')
/* eslint-disable-next-line no-unused-vars */
const findExisting = (context, files) => {
/* eslint-disable no-restricted-syntax, no-await-in-loop */
for (const file of files) {
if (fs.existsSync(path.join(context, file))) {
return file
}
}
return false
/* eslint-enable no-restricted-syntax, no-await-in-loop */
}
module.exports = ({ api, options, envUtil, args }) => {
api.chainWebpack(webpackConfig => {
const { target } = options
const {
modules: enableModules = false,
extract = true,
sourceMap = false,
loaderOptions = {},
} = options.css || {}
const isProd = envUtil.isProduction()
// do no extract when build lib, will use standalone script to gen extracted css
const shouldExtract =
target !== 'lib' && ((isProd && extract !== false) || args.split)
let hash = ''
if (!isProd) {
hash = '.[hash:8]'
} else {
hash = options.filenameHashing ? '.[contenthash:8]' : ''
}
const filename = `[name]${hash}.css`
const extractOptions = {
filename,
chunkFilename: filename,
...(extract && typeof extract === 'object' ? extract : {}),
}
// 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 = !!(
// api.service.pkg.postcss ||
// findExisting(api.resolve('.'), [
// '.postcssrc',
// '.postcssrc.js',
// 'postcss.config.js',
// '.postcssrc.yaml',
// '.postcssrc.json',
// ])
// )
const hasPostCSSConfig = true
function createCSSRule(lang, test, loader, _options) {
const baseRule = webpackConfig.module
.rule(lang)
.test(test)
// https://github.com/webpack-contrib/style-loader/issues/312#issuecomment-406444631
.sideEffects(true)
function applyLoaders(rule, modules) {
if (shouldExtract) {
/* eslint-disable import/no-unresolved */
rule
.use('extract-css-loader')
.loader(require('mini-css-extract-plugin').loader)
/* eslint-enable import/no-unresolved */
} else {
const styleLoader = resolveCwd('vue')
? 'vue-style-loader'
: 'style-loader'
rule
.use(styleLoader)
.loader(styleLoader)
.options({
sourceMap,
...loaderOptions.style,
})
}
const cssLoaderOptions = {
root: api.resolve('.'),
minimize: isProd,
sourceMap,
importLoaders:
1 + // stylePostLoader injected by vue-loader
hasPostCSSConfig +
!!loader,
...loaderOptions.css,
}
if (modules) {
const { localIdentName = '[name]_[local]_[hash:base64:5]' } =
loaderOptions.css || {}
Object.assign(cssLoaderOptions, {
modules,
localIdentName,
})
}
rule
.use('css-loader')
.loader('css-loader')
.options(cssLoaderOptions)
if (hasPostCSSConfig) {
rule
.use('postcss-loader')
.loader('postcss-loader')
.options({ sourceMap, ...loaderOptions.postcss })
}
if (loader) {
rule
.use(loader)
.loader(loader)
.options({ sourceMap, ..._options })
}
}
// 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, enableModules)
}
createCSSRule('css', /\.css$/)
createCSSRule('postcss', /\.p(ost)?css$/)
createCSSRule('scss', /\.scss$/, 'sass-loader', loaderOptions.sass)
createCSSRule('sass', /\.sass$/, 'sass-loader', {
indentedSyntax: true,
...loaderOptions.sass,
})
createCSSRule('less', /\.less$/, 'less-loader', loaderOptions.less)
createCSSRule('stylus', /\.styl(us)?$/, 'stylus-loader', {
preferPathResolver: 'webpack',
...loaderOptions.stylus,
})
// inject CSS extraction plugin
if (shouldExtract) {
/* eslint-disable import/no-unresolved */
webpackConfig
.plugin('extract-css')
.use(require('mini-css-extract-plugin'), [extractOptions])
/* eslint-enable import/no-unresolved */
}
if (isProd) {
// optimize CSS (dedupe)
// cssnano 3
const cssProcessorOptions = {
safe: true,
autoprefixer: { disable: true },
mergeLonghand: false,
}
if (options.productionSourceMap && sourceMap) {
cssProcessorOptions.map = { inline: false }
}
/* eslint-disable import/no-unresolved */
webpackConfig
.plugin('optimize-css')
.use(require('optimize-css-assets-webpack-plugin'), [
{
canPrint: false,
cssProcessorOptions,
},
])
/* eslint-enable import/no-unresolved */
}
})
}