zoro-cli
Version:
https://github.com/vuejs/vue-cli
165 lines (148 loc) • 4.65 kB
JavaScript
const path = require('path')
const globby = require('globby')
const { error } = require('zoro-cli-util/logger')
function genNestedEntry(entryDir) {
const entry = {}
const arr = globby.sync(['**/*.{js,jsx,ts,tsx}'], {
cwd: entryDir,
gitignore: true,
})
arr.forEach(rawName => {
const key = rawName.replace(/.(js|jsx|ts|tsx)$/, '')
entry[key] = path.join(entryDir, rawName)
})
return entry
}
module.exports = ({ api, options, envUtil, args }) => {
if (options.target !== 'app') return
api.chainWebpack(webpackConfig => {
const isProd = envUtil.isProduction()
const { entryDir } = options
// entry
if (entryDir) {
webpackConfig.entryPoints.clear()
const entry = genNestedEntry(entryDir)
Object.keys(entry).forEach(name => {
webpackConfig
.entry(name)
// use absolute path for windows
.add(path.resolve(options.outputJsDir, entry[name]))
})
}
// code splitting
if (isProd || args.split) {
const cacheGroups = {
vendors: false,
default: false,
}
let split = options.split || args.split
if (typeof split !== 'string') {
split = 'common'
}
if (split === 'vendors') {
cacheGroups.vendors = {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial',
}
} else if (split === 'common') {
cacheGroups.common = {
name: 'common',
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
chunks: 'initial',
}
} else {
error('"split" must be specified to one of ["vendors", "common"]')
}
// code splitting
webpackConfig.optimization.splitChunks({
cacheGroups,
})
}
const fs = require('fs')
// HTML
const nohtml = options.nohtml || args.nohtml
if (!nohtml) {
const { metadata = {} } = options
const htmlPath = api.resolve('src/assets/template/index.html')
Object.keys(webpackConfig.entryPoints.entries() || {}).forEach(entry => {
const htmlOptions = {
filename: path.posix.join(
options.outputHtmlDir || '',
`${entry}.html`,
),
chunks: ['vendors', 'common', entry],
NODE_ENV: process.env.NODE_ENV,
...metadata.base,
...metadata[entry],
}
// template path
const entryHtmlPath = htmlPath.replace('index', entry)
if (fs.existsSync(entryHtmlPath)) {
htmlOptions.template = entryHtmlPath
} else if (fs.existsSync(htmlPath)) {
htmlOptions.template = htmlPath
}
// minify HTML all the time
Object.assign(htmlOptions, {
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: false,
collapseBooleanAttributes: true,
removeScriptTypeAttributes: true,
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency',
})
webpackConfig
.plugin(`html-${entry}`)
.use(require('html-webpack-plugin'), [htmlOptions])
})
}
// FIXME: inject preload/prefetch to HTML
// const PreloadPlugin = require('preload-webpack-plugin')
// webpackConfig.plugin('preload').use(PreloadPlugin, [
// {
// rel: 'preload',
// include: 'initial',
// fileBlacklist: [/\.map$/, /hot-update\.js$/],
// },
// ])
// webpackConfig.plugin('prefetch').use(PreloadPlugin, [
// {
// rel: 'prefetch',
// include: 'asyncChunks',
// },
// ])
// copy static assets in public/
if (fs.existsSync(api.resolve('public'))) {
const copyTo = api.resolve(args.dest || options.outputDir)
webpackConfig.plugin('copy').use(require('copy-webpack-plugin'), [
[
{
from: api.resolve('public'),
to: copyTo,
ignore: ['.DS_Store', '.gitkeep'],
},
],
])
}
// profile
if (args.profile) {
webpackConfig
.plugin('profile')
.use(require('webpack/lib/debug/ProfilingPlugin'), [
{
// do not nested folder here, the plugin is stuid to generate intermediate folders
outputPath: '_webpack_profile_events.json',
},
])
}
})
}