@honor-minigame/cli
Version:
honor minigame pack cli
264 lines (252 loc) • 8.39 kB
JavaScript
import path from 'path'
import CopyPlugin from 'copy-webpack-plugin'
import ZipWebpackPlugin from '../plugins/webpack-zip-plugin.js'
import MainWebpackPlugin from '../plugins/webpack-main-plugin.js'
import { merge } from 'webpack-merge'
import { info, error } from '../../utils/logger.js'
import { update } from '../lib/manifest.js'
import * as paths from '../lib/paths.js'
import exConfig from '../lib/exConfig.js'
import { FILE_EXT_IGNORES, MANIFEST, ENTRY_NAME, FILE_EXT } from '../lib/constanst.js'
import prettyjson from 'prettyjson'
import NodePolyfillPlugin from 'node-polyfill-webpack-plugin'
import prettierCode from './pretty-loader.js'
import TerserPlugin from 'terser-webpack-plugin'
import webpackConfig from './webpack.config.js'
import { require } from '../lib/require.js'
/**
* 基于给定的参数生成Webpack配置
*
* @param {boolean} isRelease - 是否为发布模式
* @param {Object} entry - 入口文件配置
* @param {boolean} amd - 是否支持AMD模块
* @returns {Object} 生成的Webpack配置对象
*/
export function base(isRelease, entry, amd) {
const ignoreRes = []
const config = merge(webpackConfig, {
mode: isRelease ? 'none' : 'development',
optimization: {
minimize: isRelease ? true : false,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: false // 可选:设置为 true 可以移除 console 命令
},
format: {
beautify: isRelease ? false : true, // 设置为 true 会输出格式良好的代码
comments: true // 若需要保留注释,设置为 true 或 'all',保留注释,否则Unity分包加载失败
}
},
extractComments: false // 若不希望将注释提取到单独的文件中,设置为 false
})
]
},
context: paths.PROJECT_PATH,
output: {
path: paths.BUILD,
},
module: {
rules: [
{
test: /\.js$/,
include: [paths.SRC],
exclude: (filePath) => {
return (
filePath.includes('node_modules') || filePath.includes('@babel')
)
}
},
{
test: /^(?!.*\.(js|json)$).*$/i,
use: [
{
loader: require.resolve('file-loader'),
options: {
context: paths.SRC,
esModule: false,
name(resourcePath, resourceQuery) {
return '[path][name].[ext]'
}
}
}
]
}
],
exprContextRecursive: true,
unknownContextCritical: true,
unknownContextRecursive: true,
wrappedContextRecursive: true,
noParse: /\.json$/
},
resolve: {
extensions: FILE_EXT,
modules: [
paths.SRC,
'node_modules'
],
preferRelative: true,
alias: { // 如果有动态导入的模块,可以使用该方法添加
// '@qgame/adapter': require.resolve('@qgame/adapter', { paths: [__dirname] })
}
},
devtool: isRelease ? false : 'cheap-module-source-map',
stats: 'errors-only',
entry: Object.assign({
game: paths.ENTRY
}, entry),
plugins: [
new NodePolyfillPlugin(),
new CopyPlugin({
patterns: [
{
from: paths.SRC,
// 使用 globOptions.ignore 替代旧版 ignore
globOptions: {
ignore: [
// 使用 glob 语法 **/* 匹配所有子目录
...FILE_EXT_IGNORES.map(ext => `**/*${ext}`),
...ignoreRes.map(pattern => `**/${pattern}`)
]
},
// transform 函数保持原有逻辑
transform(content, path) {
if (path.includes(MANIFEST)) { // 更现代的写法替代 indexOf
return update({ content, isRelease })
}
return content
}
}
]
})
]
})
// 若amd设置为false,则关闭amd配置,表示不支持amd define转换,默认为true
if (!amd) {
config.amd = false
}
// 对小游戏工程目录的webpack配置做postHook处理
exConfig(config, {
context: paths.PROJECT_PATH,
src: paths.SRC,
build: paths.BUILD
})
return config
}
/**
* 原整包打包webpack配置生成
*
* @param {string} entry - 入口文件路径
* @param {boolean} isRelease - 是否为发布模式
* @param {Object} externals - 外部依赖配置
* @param {boolean} inject - 是否注入分包模块的依赖
* @param {boolean} amd - 是否使用AMD模块
* @returns {Object} 合并后的Webpack配置对象
*/
export function singleConfig(entry, isRelease, externals, inject, amd) {
// 格式化微小相关的代码,便于调试和排查问题
prettierCode(paths.SRC)
const baseConfig = base(isRelease, entry, amd)
const injectPlugins = []
// 是否注入对分包模块的依赖,如果不注入,由CP用户注入,能力开放给CP用户
// const injectPlugins = inject ? [
// new InjectPlugin(() => { // 打原整包时,通过在主入口 src/game.js 注入其它分包的依赖,并结合externals来实现兼容
// return Object.keys(externals).reduce((acc, cur) => `require('${cur}');${acc}`, '')
// }, {
// entryName: ENTRY_NAME,
// entryOrder: ENTRY_ORDER.Last
// })] : []
// const compileStartTime = (new Date()).valueOf()
return merge(baseConfig, {
externals,
plugins: [
new MainWebpackPlugin({
singlePackage: true
}),
...injectPlugins
]
})
}
/**
* 生成分包的Webpack配置对象
*
* @param {string} entry - 入口文件路径
* @param {boolean} isRelease - 是否为发布版本
* @param {string} packageName - 包名称
* @param {Array} externals - 外部依赖
* @param {Array} subpackages - 子包配置
* @param {Object} manifest - 清单文件
* @param {string} buildType - 构建类型
* @param {boolean} amd - 是否使用AMD模块
* @returns {Object} 合并后的Webpack配置对象
*/
export function multiConfig(entry, isRelease, packageName, externals, subpackages, manifest, buildType, amd) {
const baseConfig = base(isRelease, entry, amd)
const compileStartTime = (new Date()).valueOf()
return merge(baseConfig, {
externals,
plugins: [
new MainWebpackPlugin({
singlePackage: false,
subpackages
}),
new ZipWebpackPlugin({
isRelease,
packageName,
singlePackage: false, // 打新分包,为false必须提供subpackages
subpackages,
manifest,
buildType,
compileStartTime
})
]
})
}
/**
* 检查webpack编译完成后是否有错误
* @param {Object} err webpack错误
* @param {Object} stats 编译状态
*/
export function checkError(err, stats) {
if (err) { // webpack错误,配置文件出错等
error(err.stack || err)
if (err.details) {
error(err.details)
}
return true
}
const statsJson = stats.toJson()
if (stats.hasWarnings()) { // 编译警告, 只打印前十个警告
let warns = statsJson.warnings
if (warns.length > 10) {
warns = warns.splice(0, 10)
info('编译结果warnings超过10个,只打印前10个!!!', statsJson.warnings.length)
}
const warnings = warns.map((warning) => {
const { moduleIdentifier, moduleName, loc, message } = warning
return { moduleIdentifier, moduleName, loc, message }
})
info(prettyjson.render(warnings))
}
if (stats.hasErrors()) { // 编译错误,譬如缺失Module,语法错误等
const errors = statsJson.errors.map((er) => {
const { moduleIdentifier, moduleName, loc, message, stack } = er
let errMsg = message
if (!message) {
errMsg = er
}
// 找不到模块代码不影响rpk打包
if (errMsg.includes('Module not found')) {
const tip = `【不影响rpk打包】请检查对应模块 ${moduleName}下的代码!`
info(prettyjson.render({ moduleIdentifier, moduleName, loc, errMsg, tip }))
} else {
return { moduleIdentifier, moduleName, loc, errMsg, stack }
}
}).filter(Boolean)
if (errors.length) {
error(prettyjson.render(errors))
return true
}
}
}