zoro-cli
Version:
https://github.com/vuejs/vue-cli
271 lines (233 loc) • 7.64 kB
JavaScript
const path = require('path')
const PnpWebpackPlugin = require('pnp-webpack-plugin')
const { resolveCwd } = require('zoro-cli-util/resolve')
const cwd = process.cwd()
module.exports = ({ api, options, envUtil, args, pkg }) => {
const { node } = options
const isProd = envUtil.isProduction()
// const useThreads = isProd && options.parallel
api.chainWebpack(webpackConfig => {
const isLegacyBundle = args.modern && !args.modernBuild
const { context = cwd, baseUrl, inlineLimit = 1024 * 10 } = options
const { output, resolve } = webpackConfig
// context
webpackConfig.context(context)
// output
output.path(api.resolve(args.dest || options.outputDir))
let filename = `[name]${isLegacyBundle ? '-legacy' : ''}`
if (isProd) {
filename += options.filenameHashing ? '.[contenthash:8]' : ''
}
filename += '.js'
output.filename(filename)
if (baseUrl) {
output.publicPath(baseUrl)
}
if (args.watch || args.w) {
webpackConfig.watch(true)
}
// resolve
// resolve.symlinks = false may cause HMR to fail https://github.com/vuejs/vue-cli/issues/1559#issuecomment-413427651
// resolve.symlinks = true may cause module resolution to fail when using tools that symlink packages (like npm link)
// so to cover the most common use case, set it to true
resolve.set('symlinks', true)
resolve.extensions.merge(['.js', '.jsx', '.ts', '.tsx', '.vue', '.json'])
resolve.modules.add('node_modules')
resolve.alias
.set('root', api.resolve('.'))
.set('src', api.resolve('src'))
.set('tests', api.resolve('tests'))
.set('test', api.resolve('test'))
.set('mock', api.resolve('mock'))
.set('axios', 'axios/dist/axios.min')
.set(
'vue$',
options.runtimeCompiler
? 'vue/dist/vue.esm.js'
: 'vue/dist/vue.runtime.esm.js',
)
webpackConfig.resolveLoader.modules.add('node_modules')
// Ignored files should not have calls to import/require.
webpackConfig.module.noParse(
/^(vue|vue-router|vuex|vuex-router-sync|react|react-dom)$/,
)
// pnp
if (pkg && pkg.installConfig && pkg.installConfig.pnp) {
api.configureWebpack(() => ({
resolve: {
plugins: [PnpWebpackPlugin],
},
resolveLoader: {
plugins: [PnpWebpackPlugin.moduleLoader(module)],
},
}))
}
/**
* loaders begin
*/
// js is handled by babel
// vue
if (resolveCwd('vue')) {
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved */
const vueLoaderCacheConfig = api.genCacheConfig('vue-loader', {
'vue-loader': require('vue-loader/package.json').version,
'@vue/component-compiler-utils': require('@vue/component-compiler-utils/package.json')
.version,
'vue-template-compiler': require('vue-template-compiler/package.json')
.version,
})
const vueRule = webpackConfig.module
.rule('vue')
.test(/\.vue$/)
.use('cache-loader')
.loader('cache-loader')
.options(vueLoaderCacheConfig)
.end()
// if (useThreads) {
// vueRule.use('thread-loader').loader('thread-loader')
// }
vueRule
.use('vue-loader')
.loader('vue-loader')
.options(
{
compilerOptions: {
preserveWhitespace: false,
},
...vueLoaderCacheConfig,
},
)
webpackConfig.plugin('vue-loader').use(require('vue-loader/lib/plugin'))
/* eslint-enable import/no-extraneous-dependencies, import/no-unresolved */
}
// static assets
const { outputImgDir, outputMediaDir, outputFontsDir } = options
const baseFileName = options.filenameHashing
? '[name].[hash:8].[ext]'
: '[name].[ext]?[hash:8]'
// html
if (options.html) {
webpackConfig.module
.rule('html')
.test(/\.html?$/)
.use('file-loader')
.loader('file-loader')
.options({ name: '[name].[ext]' })
}
// images
webpackConfig.module
.rule('images')
.test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
.use('url-loader')
.loader('url-loader')
.options({
limit: inlineLimit,
name: path.posix.join(outputImgDir, baseFileName),
})
// svg
// do not base64-inline SVGs.
// https://github.com/facebookincubator/create-react-app/pull/1180
webpackConfig.module
.rule('svg')
.test(/\.(svg)(\?.*)?$/)
.use('file-loader')
.loader('file-loader')
.options({
name: path.posix.join(outputImgDir, baseFileName),
})
// media
webpackConfig.module
.rule('media')
.test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/)
.use('url-loader')
.loader('url-loader')
.options({
limit: inlineLimit,
name: path.posix.join(outputMediaDir, baseFileName),
})
// fonts
webpackConfig.module
.rule('fonts')
.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)
.use('url-loader')
.loader('url-loader')
.options({
limit: inlineLimit,
name: path.posix.join(outputFontsDir, baseFileName),
})
// Other common pre-processors
webpackConfig.module
.rule('pug')
.test(/\.pug$/)
.use('pug-plain-loader')
.loader('pug-plain-loader')
.end()
/**
* loaders end
*/
// shims
// node
if (!node) {
webpackConfig.node.merge({
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// process is injected via DefinePlugin, although some 3rd party
// libraries may require a mock to work properly (#934)
process: 'mock',
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
})
}
/**
* plugins begin
*/
// define
webpackConfig.plugin('define').use(require('webpack/lib/DefinePlugin'), [
{
'process.env': {
NODE_ENV: JSON.stringify(envUtil.getNodeEnv()),
MOCK: JSON.stringify(process.env.MOCK),
},
},
])
webpackConfig
.plugin('case-sensitive-paths')
.use(require('case-sensitive-paths-webpack-plugin'))
// analyze
if (args.analyze) {
webpackConfig
.plugin('analyze')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [
{
analyzerMode: 'static',
reportFilename: path.join('..', '_webpack_analyze_', 'report.html'),
openAnalyzer: false,
generateStatsFile: true,
statsFilename: path.join('..', '_webpack_analyze_', 'stats.json'),
statsOptions: null,
logLevel: 'silent',
},
])
}
// friendly error plugin displays very confusing errors when webpack
// fails to resolve a loader, so we provide custom handlers to improve it
const { transformer, formatter } = require('../util/resolveLoaderError')
webpackConfig
.plugin('friendly-errors')
.use(require('friendly-errors-webpack-plugin'), [
{
additionalTransformers: [transformer],
additionalFormatters: [formatter],
},
])
/**
* plugins end
*/
})
}