webpack点滴

初始化项目,安装webpack

mkdir my-project
cd my-project
npm init -y
npm install webpack webpack-cli --save-dev

webpack.config.js配置

const path = require('path')

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
mode: 'development' // production或none
}

entry

// 单入口
entry: './path/to/my/entry/file.js'

// 多入口
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}

output

output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}

// 多个入口起点,可使用[hash]、[chunkhash]、[name]、[id]、[query]
filename: '[name].bundle.js',

loader

module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' }
]
}

plugins

常用的plugins

Name Description
CommonsChunkPlugin 将chunks相同的模块代码提取成公共js
CleanWebpackPlugin 清理构建目录
MiniCssExtractPlugin 将CSS从bundle文件里提取成独立的CSS文件
CopyWebpackPlugin 将文件或目录拷贝到构建目录
HtmlWebpackPlugin 创建html文件以承载输出的bundle
UglifyjsWebpackPlugin 压缩js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'}),
new webpack.optimize.UglifyJsPlugin()
]

解析ES6

rules: [
{ test: /\.js$/, use: 'babel-loader' }
]

安装

npm i babel-loader @babel/core @babel/preset-env -D

配置

.babelrc
{
"presets": [
"@babel/preset-env"
]
}

解析Less

rules: [
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
]

解析图片

rules: [
{
test: /\.(png|jpg|jpeg|gif)$/,
use: ['file-loader']
}
]

可使用url-loader将小图片用base64引入。

文件监听

module.exports = {
watch: true
}

热更新

const webpack = require('webpack')
module.exports = {
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: './dist',
hot: true
},
mode: 'development'
}

命令

"scripts": {
"dev": "webpack-dev-server --open"
}

也可以使用webpack-dev-middleware实现热更新。

server.js
const express = require('express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')

const app = express()
const config = require('./webpack.config.js')
const compiler = webpack(config)

app.use(webpackDevMiddleware(compiler, {
publicPath: '/'
}))

app.listen(3000, function () {
console.log('Listening on port 3000');
})

命令

"scripts": {
"server": "node server.js"
}

文件指纹

  • hash: 和整个项目的构建相关,只要项目文件有修改,整个项目的hash值就会更改
  • chunkhash: 和打包的chunk相关,不同entry会生成不同的chunkhash
  • contenthash: 由文件内容生成

JS文件

output: {
filename: '[name][chunkhash:8].js'
}

CSS文件

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: '[name][contenthash:8].css',
})
],
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
]
}

图片、字体

// file-loader中的hash即为contenthash
rules: [
{
test: /\.(woff2?|eot|ttf|otf)$/,
use: [
loader: 'file-loader',
options: {
name: '[name][hash:8].[ext]'
}
]
}
]

代码压缩

JS文件

webpack4中已经内置并默认开启了uglifyjs-webpack-plugin,用于JS文件的压缩。

CSS文件

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: '[name][contenthash:8].css',
}),
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano')
})
]
}

HTML文件

通过设置html-webpack-plugin的压缩参数实现。

plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['index'],
minify: {
collapseWhitespace: true,
removeComments: true
}
})
]

清理构建目录

const { CleanWebpackPlugin } = require('clean-webpack-plugin')

// webpack's output.path directory will be removed
plugins: [
new CleanWebpackPlugin()
]

补齐CSS3前缀

安装

npm i postcss-loader autoprefixer -D
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
require('autoprefixer')({
browsers: ['> 1%', 'last 2 versions', 'not ie <= 8']
})
]
}
}
]

px转换成rem

{
loader: 'px2rem-loader',
options: {
remUnit: 75,
remPrecision: 8
}
}

在html文件中添加根元素font-size自动计算方法。

资源内联

通过raw-loader内联HTML和JS。

<head>
<title>INLINE</title>
${ require('raw-loader!./meta.html') }
<script>${ require('raw-loader!babel-loader!./base.js') }</script>
</head>

使用style-loader或html-inline-css-webpack-plugin内联CSS文件。

多页面应用

利用glob动态获取entry并设置html-webpack-plugin。

const glob = require('glob')

const setMultipage = () => {
const entry = {}
const htmlWebpackPlugins = []

const entryFiles = glob.sync(path.resolve(__dirname, 'src/*/index.js'))
entryFiles.forEach(entryFile => {
const match = entryFile.match(/src\/(.*)\/index.js/)
const pageName = match && match[1]

entry[pageName] = entryFile
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
template: `./src/${pageName}/index.html`,
filename: `${pageName}.html`,
chunks: [pageName]
})
)
})

return {
entry,
htmlWebpackPlugins
}
}

const { entry, htmlWebpackPlugins } = setMultipage()

module.exports = {
entry,
plugins: [
new CleanWebpackPlugin()
].concat(htmlWebpackPlugins)
}

待续 ~