@ctsj/build
Version:
一个基于webpack的打包工具
284 lines (277 loc) • 7.86 kB
JavaScript
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const UselessFilesCleanWebpackPlugin = require('useless-files-clean-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const WebpackBar = require('webpackbar');
const commandArgs = require('../commandArgs');
const Util = require('../util');
const { getPostCssConfigPath, isDev, isProd } = require('../util');
const argIndex = isDev() ? 8 : 6;
const runtimePath = commandArgs.toCommandArgs(process.argv[argIndex]).get('runtimepath');
const APP_PATH = path.resolve(runtimePath, 'src'); // 项目src目录
const devLoaders = isDev() ? [] : ['thread-loader'];
const babelConfig = {
presets: [
[
'@babel/preset-env',
// {
// useBuiltIns: 'usage',
// corejs: { version: 3, proposals: true },
// },
],
'@babel/preset-react',
],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-proposal-function-bind',
'@babel/plugin-proposal-optional-chaining',
['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { loose: false }],
isDev() ? 'react-refresh/babel' : null,
].filter((t) => t),
cacheDirectory: isProd(),
};
module.exports = {
plugins: {
HtmlWebpackPlugin,
MiniCssExtractPlugin,
CopyWebpackPlugin,
CssMinimizerPlugin,
TerserPlugin,
UselessFilesCleanWebpackPlugin,
CompressionPlugin,
},
config: {
/**
* 入口
*/
entry: {
// 判断入口文件是.js,.jsx,.tsx
index: Util.getEntryIndex(runtimePath),
},
/**
* 出口
*/
output: {
filename: isProd() ? '[name].[chunkhash].bundle.js' : '[name].[contenthash].bundle.js',
chunkFilename: isProd() ? '[name].[chunkhash].bundle.js' : '[name].[contenthash].bundle.js',
path: path.resolve(runtimePath, 'dist'),
publicPath: '/',
clean: true,
},
plugins: (isProd()
? [
new webpack.optimize.ModuleConcatenationPlugin(),
new CompressionPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + ['js', 'css'].join('|') + ')$'),
threshold: 10240,
minRatio: 0.8,
}),
]
: []
).concat([
new HtmlWebpackPlugin({
title: '',
filename: 'index.html',
template: path.join(runtimePath, 'src', 'index.html'),
hash: true, // 防止缓存
minify: {
removeAttributeQuotes: true, // 压缩 去掉引号
},
chunks: ['index'],
}),
// new webpack.HashedModuleIdsPlugin(),
new MiniCssExtractPlugin({
filename: isDev() ? '[name].css' : '[name].[contenthash].css',
chunkFilename: isDev() ? '[name].css' : '[name].[contenthash].css',
ignoreOrder: false,
}),
new webpack.ProvidePlugin({
_: 'lodash',
$: 'jquery',
}),
new ForkTsCheckerWebpackPlugin({
typescript: {
configFile: path.join(runtimePath, 'tsconfig.json'),
// checkSyntacticErrors: true,
},
}),
new WebpackBar({ reporters: ['profile'], profile: true }),
new UselessFilesCleanWebpackPlugin({
root: APP_PATH,
out: path.join(runtimePath, 'lessFiles'),
clean: false,
exclude: ['*.gitignore', 'node_modules'],
log: 'console',
}),
]),
optimization: isDev()
? {
splitChunks: false,
}
: {
minimize: !isDev(), // true,
minimizer: isDev() ? [] : [new TerserPlugin(), new CssMinimizerPlugin()],
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
module: {
rules: [
{
test: /\.m?jsx?$/,
exclude: /(node_modules|bower_components)/,
// include: [APP_PATH],
use: [
...devLoaders,
{
loader: 'babel-loader',
options: babelConfig,
},
],
},
{
test: /\.m?tsx?$/,
exclude: /(node_modules|bower_components)/,
// include: [APP_PATH],
use: [
...devLoaders,
{
loader: 'babel-loader',
options: babelConfig,
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
happyPackMode: true,
configFile: path.join(runtimePath, 'tsconfig.json'),
},
},
],
},
{
test: /\.css$/,
include: [
APP_PATH,
/highlight.js/,
/photoswipe.css/,
/default-skin.css/,
/swiper.min.css/,
/antd/,
/antd-mobile/,
/normalize.css/,
],
use: [
isDev()
? 'style-loader'
: {
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
config: getPostCssConfigPath(runtimePath),
},
},
},
],
},
{
test: /\.less$/,
include: [APP_PATH, /normalize.less/],
use: [
isDev()
? 'style-loader'
: {
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
config: getPostCssConfigPath(runtimePath),
},
},
},
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true,
},
},
},
],
},
{
test: /\.(png|svg|jpg|gif|ico)$/,
type: 'asset/resource',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
},
{
test: /\.(csv|tsv)$/,
use: ['csv-loader'],
},
{
test: /\.xml$/,
use: ['xml-loader'],
},
{
test: /\.ejs/,
use: [
{
loader: 'ejs-loader',
options: {
variable: 'data',
},
},
],
},
{
test: /\.ya?ml$/,
use: ['json-loader', 'yaml-loader'],
},
{
test: /\.md$/,
use: ['raw-loader'],
},
],
},
resolve: {
modules: [/* path.join(runtimePath, 'node_modules'), */ 'node_modules'],
extensions: ['.js', '.jsx', '.ts', '.tsx', '.css', '.less', '.sass', '.json'], // 后缀名自动补全
},
},
};