webpack的配置
webpack.common.js
webpack.dev.js
webpack.prod.js
webpack.umdcommon.js
webpack.umd.js
startapp.js,buildapp.js都是对webpack的封装,而2个命令都有一些公共的配置,公共的配置写在webpack.common.js文件中
webpack.common.js
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 HappyPack = require('happypack');
const WebpackBar = require('webpackbar');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const runtimePath = process.argv[8];
const APP_PATH = path.resolve(runtimePath, 'src'); // 项目src目录
const { getPostCssConfigPath } = require('../util');
module.exports = {
plugins: {
HtmlWebpackPlugin,
MiniCssExtractPlugin,
CopyWebpackPlugin,
},
config: {
/**
* 入口
*/
entry: {
index: path.join(runtimePath, 'src', 'index.js'),
},
/**
* 出口
*/
output: {
filename:
process.env.NODE_ENV === 'production'
? '[name].[chunkhash].bundle.js'
: '[name].[hash].bundle.js',
chunkFilename:
process.env.NODE_ENV === 'production'
? '[name].[chunkhash].bundle.js'
: '[name].[hash].bundle.js',
path: path.resolve(runtimePath, 'dist'),
publicPath: '/',
},
plugins: [
// html模板
new HtmlWebpackPlugin({
title: '', // 模板html的title
filename: 'index.html', // 模板名称
template: path.join(runtimePath, 'src', 'index.html'),// 模板的地址
hash: true, // 防止缓存
minify: {
removeAttributeQuotes: true, // 压缩 去掉引号
},
chunks: ['index'],
}),
// 该插件会根据模块的相对路径生成一个四位数的hash作为模块id, 建议用于生产环境
new webpack.HashedModuleIdsPlugin(),
// 将css放入单独的文件
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
}),
// 在单独的进程上运行TypeScript类型检查器的Webpack插件
new ForkTsCheckerWebpackPlugin({
tsconfig: path.join(runtimePath, 'tsconfig.json'),
checkSyntacticErrors: true,
}),
// jsx和js的babel解析
new HappyPack({
id: 'babel',
loaders: [
'cache-loader',
{
loader: 'babel-loader',
query: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
// 使用corejs3来进行polyfill
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-class-properties',
],
},
},
],
}),
// ts和tsx的解析
new HappyPack({
id: 'ts',
loaders: [
{
loader: 'ts-loader',
options: {
transpileOnly: true,
happyPackMode: true,
configFile: path.join(runtimePath, 'tsconfig.json'),
},
},
],
}),
// css的解析
new HappyPack({
id: 'css',
loaders: [
'cache-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
options: {
config: {
path: getPostCssConfigPath(runtimePath),
},
},
},
],
}),
// less的解析
new HappyPack({
id: 'less',
loaders: [
'cache-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
options: {
config: {
path: getPostCssConfigPath(runtimePath),
},
},
},
{
loader: 'less-loader',
query: {
javascriptEnabled: true,
},
},
],
}),
new WebpackBar({ reporters: ['profile'], profile: true }),
],
optimization: {
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: ['happypack/loader?id=babel'],
},
{
test: /\.m?tsx?$/,
exclude: /(node_modules|bower_components)/,
include: [APP_PATH],
use: ['happypack/loader?id=ts'],
},
{
test: /\.css$/,
include: [
APP_PATH,
/highlight.js/,
/photoswipe.css/,
/default-skin.css/,
/swiper.min.css/,
/antd/,
/antd-mobile/,
/normalize.css/,
],
use: [
process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader,
'happypack/loader?id=css',
],
},
{
test: /\.less$/,
include: [APP_PATH, /normalize.less/],
use: [
process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader,
'happypack/loader?id=less',
],
},
{
test: /\.(png|svg|jpg|gif|ico)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
},
},
],
},
{
test: /\.(csv|tsv)$/,
use: ['csv-loader'],
},
{
test: /\.xml$/,
use: ['xml-loader'],
},
{
test: /\.ejs/,
loader: ['ejs-loader?variable=data'],
},
{
test: /\.ya?ml$/,
use: ['json-loader', 'yaml-loader'],
},
],
},
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.less', '.css', '.json'], // 后缀名自动补全
},
},
};
// 配置postcss的时候寻找postcss.config.js配置文件
getPostCssConfigPath(runtimePath) {
if (fs.existsSync(path.join(runtimePath, 'postcss.config.js'))) {
return path.join(runtimePath, 'postcss.config.js');
}
return path.join(__dirname, 'postcss.config.js');
}
在公共的配置中使用了很多loader和插件,也对loader部分进行了优化,优化这块主要使用了happypack,同时也加入了对less的解析,也使用了postcss-loader进行了autoprefixer的操作,其他的配置都是一些基础的配置,这里就不多做介绍了。需要说明的是文件导出2个key,分别是plugins和config
这个公共文件写好是之后,接下来就是实现dev和prod这两个配置文件了
webpack.dev.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const commandArgs = require('../commandArgs');
const argsMap = commandArgs.initCommandArgs();
const customConfigPath = argsMap.get('--customconfig')[0];
let customModule;
const curModule = merge(common.config, {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
publicPath: '/',
host: 'localhost',
compress: true,
port: 8000,
clientLogLevel: 'none', //不再输出繁琐的信息
historyApiFallback: true,
overlay: true, //浏览器全屏显示错误信息
hot: true, // 启动模块热更新 HMR
open: true, // 开启自动打开浏览器页面
},
plugins: [
new webpack.DefinePlugin({
process: {
env: {
NODE_ENV: JSON.stringify('development'),
REAP_PATH: JSON.stringify(process.env.REAP_PATH),
},
},
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
],
});
const define = argsMap.get('--define')[0] || '';
if (customConfigPath) {
customModule = require(customConfigPath);
if (customModule && customModule.getConfig) {
customModule.getConfig({
webpack,
curModule,
plugins: common.plugins,
define: commandArgs.toCommandArgs(define),
});
}
}
module.exports = curModule;
这里会对dev环境进行单独的参数设置,主要就是webpack-dev-server的设置
webpack.prod.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const common = require('./webpack.common.js');
const commandArgs = require('../commandArgs');
const argsMap = commandArgs.initCommandArgs();
const customConfigPath = argsMap.get('--customconfig')[0];
let customModule;
const curModule = merge(common.config, {
mode: 'production',
plugins: [
new CleanWebpackPlugin(),
new webpack.DefinePlugin({
process: {
env: {
NODE_ENV: JSON.stringify('production'),
REAP_PATH: JSON.stringify(process.env.REAP_PATH),
},
},
}),
],
});
const define = argsMap.get('--define')[0] || '';
if (customConfigPath) {
customModule = require(customConfigPath);
if (customModule && customModule.getConfig) {
customModule.getConfig({
webpack,
curModule,
plugins: common.plugins,
define: commandArgs.toCommandArgs(define),
});
}
}
module.exports = curModule;
这里会对prod环境进行单独的参数设置。
不管是dev还是prod最后都会寻找参数中customCinfigPath这个路径下是否有用户的配置文件,如果用户没有传这个参数,那么就会寻找ctbuild.config.js这个配置文件,这里会把webpack,和当前配置,所有插件和其他命令行参数传递给getConfig这个方法,用户在配置文件中在对传递过去的配置进行一个修改,达到自定义配置的效果。
这里说一下怎么使用webpack解析typescript,首先大家要明白一点,webpack.dev.js和webpack.prod.js都是去编译宿主工程而不是packge工程,如果宿主工程使用的是typescript进行编写,那么我们使用ts-loader和fork-ts-checker-webpack-plugin插件来进行解析就可以,详细请看上方代码部分。
接下来在介绍一下babel.config.js文件,这个文件是用来配置babel解析的,这个配置文件放在包工程的根目录下,这个文件在执行startapp、buildapp和buildpackage的时候都会用到。
babel.config.js
const presets = [
[
'@babel/preset-env',
{
// 模式是使用了才进行polyfill
useBuiltIns: 'usage',
// 使用corejs3来进行polyfill
corejs: { version: 3, proposals: true },
},
],
'@babel/preset-react',
];
const 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: true }],
];
module.exports = { presets, plugins };
接下来会对startapp.js、buildapp.js、buildpackage.js和buildpackagets.js进行详细的讲解