q使用webpack chain来设置webpack,使用方法如下:
import Config = requirer('webpack-chain')
// 声明一个Config实例,之后在实例上设置相关内容
const _config=new Config();
设置通用功能
// _setGeneral
_config.devtool('source-map')
.performance.hints(false)
.end() //返回最近的状态,这里返回config,即后面继续在config上进行设置
.set('fs', 'empty') // 设置一些暂不知道是什么作用的变量
.set('net', 'empty')
.set('tls', 'empty')
.set('child_process', 'empty');
对应的webpack配置
module.exports={
devtool: 'source-map',
performance: {
hints: 'error' // 打包文件超过25KB报错
},
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
}
设置入口
// _setEntry
_config.entry('index').add('src/index.js');
// webpack
module.export={
// 上面的配置...
entry: {
index: ['src/index.js']
}
}
设置出口
// _setOutput
_config.output.path(getProject('dist')).when(
isSite(),
(config)=>{
config.chunkFilename('static/js/[name].[fullhash:8].js');
config.publicPath('./');
config.filename('static/js/[name].[fullhash:8].js');
return config
},
(config)=>{
config.filename('index.js');
config.libraryTarget('commonjs');
return config
}
)
when接受三个参数,第一个是一个布尔值,后面是两个回调。true执行第一个回调,false执行第二个回调
对应webpack
// 对应第一个回调
module.exports={
// ...
output: {
chunkFilename: 'static/js/[name].[fullhash:8].chunk.js',
filename: 'static/js/[name].[fullhash:8].js',
publicPath: './',
pathinfo: true
}
}
设置resolve
_config.resolve.modules
.add(getProjectPath('node_modules'))
.add('node_modules')
.end() // 回到resolve
.extensions.merge(['.js', '.ts', '.tsx', '.json'])
.end()
.alias.set('src', getProjectPath('src'))
.set('theme', getProjectPath('src/ui/theme'))
设置了resolve的modules、extensions和alias。对应的webpack配置:
module.exports = {
// ...
resolve: {
modules: ['src', path.join(cwd, 'node_modules'), 'node_modules'],
extensions: ['.js', '.ts', '.tsx', '.json'],
alias: {
src: path.join(cwd, 'src'),
theme: path.join(cwd, 'src/ui/theme')
}
}
}
resolve.modules
设置modules会改变模块解析路径,会根据给定的数组来解析。比如这里的解析顺序为src>>当前目录下的node_modules>>node_modules
。具体就是,比如src下有个文件
// test-module.js
module.exports={}
在另一个文件
const tm=require('test-module');
这样打包的时候就会直接解析到这个模块
resolve.extensions
按顺序解析这些后缀名,能引入文件的时候不带扩展。node.js默认的解析是js > json > node
。此项会覆盖默认数组,如果要访问默认的,在数组里添加...
resolve.alias
为常用路径添加别名,比如在src/utils有很多常用模块,就可以添加一个配置
module.exports={
resolve:{
alias:{
utils: path.resolve(__dirname,'src/utils');
}
}
}
这样在使用的时候,就可以使用别名:
import { getProjectPath } from 'utils/getProjectPath'
参考: resolve
plugins
yarn add copy-webpack-plugin \ add-asset-html-webpack-plugin \ case-sensitive-paths-webpack-plugin \ clean-webpack-plugin \ duplicate-package-checker-webpack-plugin \ extract-text-webpack-plugin \ fork-ts-checker-webpack-plugin \ html-webpack-plugin \ mini-css-extract-plugin \ progress-bar-webpack-plugin \ script-ext-html-webpack-plugin \ terser-webpack-plugin \ tslint-plugin-prettier \ uglifyjs-webpack-plugin \ webpack-manifest-plugin \ webpack-filter-warnings-plugin \ react-dev-utils \ webpackbar \ progress-bar-webpack-plugin -D
copy-webpack-plugin
看说明这应该是一个拷贝一些文件的插件,具体的后续在研究。
const paths = {
publicPath: path.join(__dirname, '../../../public/'),
appHtml: path.join(__dirname, '../../../public/index.html'),
};
_config.plugin('CopyWebpackPlugin').use(
new CopyWebpackPlugin([
`${paths.publicPath}/style.css`,
`${paths.publicPath}/favicon.ico`,
`${paths.publicPath}/loading.svg`,
`${paths.publicPath}/loading.gif`,
])
)
module.exports = {
plugin: [
new CopyWebpackPlugin({
patterns: [
{
from: '/root/ENVIRONEMNT/node/GM_PRO/q/packages/q-scripts/public/style.css',
},
'/root/ENVIRONEMNT/node/GM_PRO/q/packages/q-scripts/public/favicon.ico',
'/root/ENVIRONEMNT/node/GM_PRO/q/packages/q-scripts/public/loading.svg',
'/root/ENVIRONEMNT/node/GM_PRO/q/packages/q-scripts/public/loading.gif'
]
}),
]
}
会转化成一个数组,数组里是一系列对象,对象包含from
和to
等参数。如果直接使用字符串,默认为from
html-webpack-plugin
根据模板生成html的插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path')
_config.plugin('HtmlWebpackPlugin').use(
new HtmlWebpackPlugin({
inject: true, // 默认就是true,可以不填。会决定插入webpack打包的js的位置。可选值: true|'head'|'body'|false
template: path.resolve(__dirname, '../index.html'),
minify: {
removeRedundantAttributes: true, // 如果匹配HTML4.01中的默认值,则优化掉
collapseWhitespace: true, // 去除多余空格换行以优化文档树,SCRIPT, STYLE, PRE or TEXTAREA不会优化
useShortDoctype: true, // 将非HTML 5 Doc(如hmlt 4.01)换成更短的HTML5 Doctype,这会对文档造成影响
removeEmptyAttributes: true, // 移除标签中为空的属性
removeStyleLinkTypeAttributes: true,// Remove type="text/css" from style and link tags. Other type attribute values are left intact(完好无损)
keepClosingSlash: true, // 保持单元素尾部斜杠,如 <br />不会被优化为<br>
removeComments: true, // 去除注释
minifyCSS: true,
minifyJS: true,
minifyURLs: true, // 压缩CSS,JSS,URLs
},
title: 'xzdryのtitle' // 需要在index.html里写占位符
})
)
对应的webpack配置格式一样,这里就不贴了。相关的参考文档:
- HTML Webpack Plugin
- Experimenting with HTML minifier,minify里相关的选项具体说明和示例
- minifyCSS(uses clean-css),minifyJS(uses Terser),minifyURLs(uses relateurl)
效果:
<!-- removeRedundantAttributes的效果 -->
<input type="text"> <!-- 优化为<input> -->
<input type="password"><!-- 不会优化 -->
<!-- removeRedundantAttributes的效果 -->
<div> x x x </div>
<textarea name="" id="" cols="30" rows="10">
a a a
dsad
</textarea>
<!-- useShortDoctype效果 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- useShortDoctype效果 -->
<!-- removeEmptyAttributes效果 -->
<p id="" STYLE="" title=""></p>
<!-- removeEmptyAttributes效果 -->
<!-- removeStyleLinkTypeAttributes -->
<link rel="stylesheet" href="" type="text/css">
<!-- removeStyleLinkTypeAttributes -->
<!-- keepClosingSlash -->
<br />
<!-- keepClosingSlash -->
<!-- title的效果 -->
<title><%= htmlWebpackPlugin.options.title %></title>
<!-- title的效果 -->
优化后
<input> <input type="password"><div>x x x</div><textarea name="" cols="30" rows="10">
a a a
dsad
</textarea><!doctype html><p></p><link rel="stylesheet" href=""><br/><title>xzdry的HtmlWbpackPlugin</title>
mini-css-extract-plugin
将css提取到单独的文件中,为每个包含css的js文件创建一个css文件,需要配合loader一起使用
_config.plugin('MiniCssExtractPlugin').use(new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:8].css'
}))
对应webpack配置
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugin: [
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:8].css'
})
]
}
webpack-manifest-plugin
此插件不在官网插件列表里。参考webpack-manifest-plugin
会生成一个清单,比如index.js对应的打包后的带有hash的js。虽然暂时不知道这个清单的作用
_config.plugin('WebpackManifestPlugin').use(new WebpackManifestPlugin({
filename: 'asset-manifest.json'
}))
ignore-plugin
webpack内置插件,忽略第三方包的插件,比如moment只用到了中文,打包的时候排除掉非中文。参考webpack IgnorePlugin。未验证
_config.plugin('IgnorePlugin').use(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/))
watch-ignore-plugin
在watch mode
下忽略监视指定的文件
_config.plugin('WatchIgnorePlugin').use(new webpack.WatchIgnorePlugin([/\.js$/, /\.d\.ts$/]))
对应webpack
module.exports={
plugin: [
new webpack.WatchIgnorePlugin({
paths: [/\.js$/, /\.d\.ts$/]
})
]
}
webpack-filter-waring-plugin
忽略指定的webpack waring,可以传正则或正则数组。官网还有字符串和函数的示例,实测不行,原因未知。参考:webpack-filter-warnings-plugin
_config.plugin('export').use(
new FilterWarningsPlugin({
exclude: /export .* was not found in/,
}),
);
_config.plugin('export2').use(
new FilterWarningsPlugin({
exclude: /.* is not exported from/,
}),
);
_config.plugin('multiple versions').use(
new FilterWarningsPlugin({
exclude: /ansi-regex|strip-ansi/,
}),
);
// 配合performance.hints开启警告使用,把开启的警告在过滤掉
_config.plugin('my test').use(
new FilterWarningsPlugin({
exclude: /limit/,
}),
)
webpack
module.exports = {
plugin: [
// webpack-chain会生成4个插件,合成一个正则数组传过去也可行
new FilterWarningsPlugin({
exclude: /limit/
}),
new FilterWarningsPlugin({
exclude: /export .* was not found in/
}),
new FilterWarningsPlugin({
exclude: /.* is not exported from/
}),
new FilterWarningsPlugin({
exclude: /ansi-regex|strip-ansi/
})
]
}
webpackbar
win下用progress-bar-webpack-plugin,linux下用webpackbar
这里贴一下WebpackBar的配置
if (!isCIEnvironment()) {
if (process.platform === 'win32') {
_config.plugin('progress').use(require('progress-bar-webpack-plugin'));
} else {
_config.plugin('progress').use(require('webpackbar'), [
{
color: 'green',
reporters: ['fancy'],
},
]);
}
}
// webpack
module.exports={
plugin:[
// 此plugin还提供了reporter生命周期钩子函数
new WebpackBar({
color: '#9900ff',
}),
new MyPlugin()
]
}
这里使用了一个自定义的Plugin来使打包时间长一些看到进度条的细节,plugin实现如下:
class MyPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync('My Plugin', async (stats) => {
await new Promise(res => setTimeout(res, 20000))
console.log('this is my plugin');
});
}
}
module.exports = MyPlugin;