@edwardxyt/gws-cli
Version:
这是一个web脚手架工具,用于生成基于webpack5,生成typescript+react17+mobx5+reactRouter6的应用。初衷是要解决多入口,多环境。单独编译单独运行的脚手架。做到小而美。拒绝锦上添花。
289 lines (285 loc) • 9.82 kB
JavaScript
const webpack = require('webpack');
const fs = require("fs");
const path = require('path');
const detect = require('detect-port');
const dayjs = require('dayjs');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const ReactRefreshTypeScript = require('react-refresh-typescript');
const FriendlyErrorsWebpackPlugin = require('@soda/friendly-errors-webpack-plugin'); //终端日志美化工具
const chalk = require('chalk');
const log = console.log;
// 加载全局配置文件
log(chalk.white('webpackf:development') + ' - ' + chalk.green('加载全局文件'));
let rootDir = path.resolve(__dirname, '../');
let app_config = require('.')(rootDir, 'development');
module.exports = async () => {
{
// 端口监测
const port = app_config.devServer.port;
const _port = await detect(port);
if (port === _port) {
log(`
${chalk.blue(`== 启动webpack-dev-server ==`)}
端口号: ${chalk.yellow(`${port} 没有被占用,放心使用。`)}
服务器运行在: ${chalk.red(`http://${app_config.IP}:${port}`)}
`);
} else {
app_config.devServer.port = _port;
log(`
${chalk.blue(`== 启动webpack-dev-server ==`)}
端口号: ${chalk.yellow(`${port} 已占用, 尝试使用端口号: ${_port}!`)}
服务器运行在: ${chalk.red(`http://${app_config.IP}:${port}`)}
`);
}
}
return {
entry: {
app: [`${app_config.entryDir}/main.tsx`],
},
output: {
publicPath: '/',
filename: 'scripts/[name].[contenthash:8].js',
path: `${app_config.dist}/${app_config.entry}`,
chunkFilename: 'scripts/[name].[contenthash:8].chunk.js',
assetModuleFilename: 'media/[name].[hash][ext]',
globalObject: 'this',
library: {
name: `${app_config.entry}`,
type: 'umd',
umdNamedDefine: true,
auxiliaryComment: '这里是插入的注释',
},
},
target: 'web', // 配置 package.json 的 browserslist 字段会导致 webpack-dev-server 的热更新功能直接失效,为了避免这种情况需要给 webpack 配上 target 属性
devtool: 'cheap-module-source-map', // inline-source-map
mode: 'development',
resolve: app_config.resolve,
// externals: app_config.externals, // 注意抽包的类库不可以在此包含
stats: {
preset: 'minimal',
colors: true,
source: true,
moduleTrace: true,
errorDetails: true,
},
cache: {
type: 'filesystem', // cache.type:缓存类型,值为 memory 或 filesystem,分别代表基于内存的临时缓存,以及基于文件系统的持久化缓存
version: app_config.environmentHash,
cacheDirectory: path.resolve(app_config.node_module_dir, '.cacheD'),
store: 'pack',
buildDependencies: {
defaultWebpack: ['webpack/lib/'],
config: [__filename],
tsconfig: [path.resolve(app_config.rootDir, 'tsconfig.json')].filter(f =>
fs.existsSync(f)
),
},
},
infrastructureLogging: {
level: 'none',
},
optimization: {
splitChunks: {
cacheGroups: {
chartsVendor: {
test: app_config.library.chartsVendor.test,
priority: app_config.library.chartsVendor.priority,
name: 'chartsVendor',
chunks: 'all',
},
reactVendor: {
test: app_config.library.reactVendor.test,
priority: app_config.library.reactVendor.priority,
name: 'reactVendor',
chunks: 'all',
},
antdVendor: {
test: app_config.library.antdVendor.test,
priority: app_config.library.antdVendor.priority,
name: 'antdVendor',
chunks: 'all',
},
utilsVendor: {
test: app_config.library.utilsVendor.test,
priority: app_config.library.utilsVendor.priority,
name: 'utilsVendor',
chunks: 'all',
},
vendors: {
test: app_config.library.vendors.test,
priority: app_config.library.vendors.priority,
name: 'vendors',
chunks: 'all',
},
},
},
},
module: {
strictExportPresence: true, // 将缺失的导出提示成错误而不是警告
rules: [
{
enforce: 'pre',
exclude: /@babel(?:\/|\\{1,2})runtime/,
test: /\.(js|mjs|jsx|ts|tsx|css)$/,
loader: require.resolve('source-map-loader'),
},
{
test: /\.(tsx?|jsx|js)$/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true // cacheDirectory:babel-loader 在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率,所以开启该配置将这些公共文件缓存起来,下次编译就会加快很多
},
},
{
loader: 'ts-loader',
options: {
getCustomTransformers: () => ({
before: [ReactRefreshTypeScript()],
}),
transpileOnly: true,
},
}
],
exclude: /node_modules/,
},
{
test: /\.ejs$/,
loader: 'ejs-loader',
options: {
esModule: false,
},
exclude: /node_modules/,
},
{
test: /\.(le|c)ss$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
modules: {
mode: 'local',
localIdentName: '[name]__[local]--[hash:base64:8]',
},
},
},
{
loader: 'less-loader',
options: {
lessOptions: {
strictMath: true,
},
},
},
{
loader: 'postcss-loader',
},
],
},
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.svg$/],
type: 'asset/inline'
},
{
test: /\.md$/,
type: 'asset/source'
}
],
},
plugins: [
new FriendlyErrorsWebpackPlugin(),
new ESLintPlugin({
context: app_config.entryDir,
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.json'],
exclude: '/node_modules/',
emitError: true,
failOnWarning: true,
fix: true
}),
// 使用ProvidePlugin加载的模块在使用时将不再需要import和require进行引入
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
}),
new ReactRefreshWebpackPlugin(),
// HMR 实际上只开启 hot:true 就会自动识别有无声明该插件,没有则自动引入,但是怕有隐藏问题这里还是手动加上了
// new webpack.HotModuleReplacementPlugin(),
// 允许创建一个在编译时可以配置的全局常量
new webpack.DefinePlugin(app_config.inject),
// 打包时忽略本地化内容
// Moment.js是一个非常流行的库,它捆绑了大型locale文件
//如果你不使用Moment.js,你可以删除它:
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
}),
// 使用模板引擎生成html
new HtmlWebpackPlugin({
title: '生成的HTML文档的标题',
filename: 'index.html',
template: app_config.template_path,
templateParameters: {
helmet: '组件库',
COMPILED_AT: dayjs().format('YYYY-MM-DD HH:mm:ss'),
env: app_config.inject.__ENV__,
debug: app_config.inject.__DEBUG__,
api_path: app_config.inject.__API__,
meta: '',
},
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true, // 压缩内联 css
},
inject: true, // true或'body'所有javascript资源都将放置在body元素的底部
// favicon: path.resolve('public/favicon.ico'),
chunks: [
'chartsVendor',
'reactVendor',
'antdVendor',
'utilsVendor',
'vendors',
'app',
], // entry中的 app 入口才会被打包
}),
],
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': '*',
},
// allowedHosts: [], // 该选项允许将允许访问开发服务器的服务列入白名单。
compress: true, // 启用http compression(gzip)进行数据压缩传输
port: app_config.devServer.port,
host: app_config.IP,
client: {
logging: 'verbose',
progress: true,
overlay: {
// 当出现编译错误或警告时,在浏览器中显示全屏覆盖。
errors: true,
warnings: true,
},
},
historyApiFallback: true, // { index: `${app_config.dist}/${app_config.entry}/index.html`}
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: { '^/api': '' },
},
},
open: true,
hot: 'only', // HMR时 填true
},
performance: false, // Turn off performance processing
};
};