之前都是使用脚手架直接生成的webpack配置,然后根据需求适当调整便使用了。最近空闲下来,然后就想从零开始写一个webpack配置,在此记录一下配置过程以及遇到的一些问题吧。
- node环境、npm或者yarn包管理器
- 创建一个新文件夹,然后使用npm或者yarn初始化
- 添加webpack依赖,创建一个webpack.config.js文件。顺便创建文件目录等
- 根据需要安装插件,目前我所用的到插件有
{
"name": "interview",
"version": "1.0.0",
"description": "面试题记录",
"main": "index.js",
"scripts": {
"dev": "webpack serve --mode development",
"build": "webpack --mode production",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@babel/core": "^7.14.3",
"@babel/plugin-transform-runtime": "^7.14.3",
"@babel/preset-env": "^7.14.4",
"autoprefixer": "^10.2.6",
"babel-loader": "^8.2.2",
"babel-polyfill": "^6.26.0",
"css-loader": "^5.2.6",
"file-loader": "^6.2.0",
"glob": "^7.1.7",
"html-loader": "^2.1.2",
"node-sass": "^6.0.0",
"postcss": "^8.3.0",
"postcss-loader": "^5.3.0",
"postcss-px2rem": "^0.3.0",
"sass": "^1.34.0",
"sass-loader": "^11.1.1",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1",
"webpack-dev-server": "^3.11.2"
},
"devDependencies": {
"clean-webpack-plugin": "^4.0.0-alpha.0",
"copy-webpack-plugin": "^9.0.0",
"extract-text-webpack-plugin": "^3.0.2",
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^1.6.0",
"optimize-css-assets-webpack-plugin": "^6.0.0",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0"
}
}
- 其中一些loader,例如css-loader、style-loader等都是针对于css处理的,因为extract-text-webpack-plugin在webpack4中使用存在一些问题,而且官方建议使用mini-css-extract-plugin插件,所以我这里就使用官方推荐了。
- @babel/core、@babel/preset-env等是针对编译js所引入的包处理
- webpack-dev-server开发使用的本地服务,可以配置端口号、热更新等服务
遇到的问题:
px转rem插件无法处理sass改用webpack-px-to-rem- html无法进行热更新(将热更新关闭,使用页面自动刷新,比较耗费性能)
webpack.config.js文件内容
/*
* @Author: PrendsMoi
* @GitHub: https://github.com/PrendsMoi
* @Blog: https://liuhgxu.com
* @Description: webpack配置
* @FilePath: /interview/webpack.config.js
* @Date: 2021-05-30 11:27:51
* @LastEditors: PrendsMoi
* @LastEditTime: 2021-06-13 12:03:35
*/
const webpack = require('webpack')
const path = require('path')
const glob = require('glob')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
// 获取多页面
const getPages = (argv) => {
const isDev = argv.mode === 'development'
const views = glob.sync('src/views/**/*.html')
const viewJs = glob.sync('src/views/**/*.js')
const config = {
hash: true,
inject: true,
minify: {
removeComments: !isDev,
collapseWhitespace: !isDev
}
}
const entries = {}
const htmls = []
views.forEach(item => {
const fileInfo = path.parse(item)
console.log(viewJs.includes(`${fileInfo.dir}/${fileInfo.name}.js`))
if (viewJs.includes(`${fileInfo.dir}/${fileInfo.name}.js`)) {
entries[fileInfo.dir.split('/').slice(-1)[0]] = `./${item}`.replace('.html', '.js')
}
htmls.push(new HtmlWebpackPlugin({
...config,
filename: `${fileInfo.name}.html`,
template: `./${fileInfo.dir}/${fileInfo.name}.html`,
chunks: [ 'vendor', 'commons', fileInfo.name]
}))
})
const entry = Object.assign({'babel-polyfill': ['babel-polyfill'],commons: './src/app.js'}, entries)
return {
entries: entry,
htmls
}
}
module.exports = (env, argv) => ({
entry: getPages(argv).entries,
output: {
path: path.resolve(__dirname, 'dist'),
filename: (argv.mode === 'development') ? './js/[name].js' : './js/[name].[contenthash].js',
chunkFilename: (argv.mode === 'development') ? './js/[name].js' : './js/[name].[contenthash].js',
publicPath: (argv.mode === 'development') ? '' : './'
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
(argv.mode === 'development') ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: { importLoaders: 2 }
},
{
loader: 'sass-loader',
options: {
outputStyle: 'expanded'
}
},
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('autoprefixer')({
browsers: ['last 10 versions', 'ie >= 9'],
flexbox:true,
remove: false
}),
// require('postcss-px2rem')({remUnit: 75})
]
}
}
]
},
{
test: /\.(html)$/,
use: {
loader: 'html-loader',
options: {
sources: false
}
}
},
{
test: /\.js$/,
include: [
path.resolve(__dirname, 'src')
],
use: 'babel-loader'
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader'
}
]
},
{
test: /\.(woff2|woff|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'static/fonts/[name].[hash:7].[ext]'
}
}
]
},
resolve: {//解析模块可选项
},
plugins: [
...getPages(argv).htmls,
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({filename:(argv.mode === 'development') ? "css/[name].css" : 'css/[name].[hash].css', chunkFilename: '[id].css'}),
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, './src/assets'),
to: 'assets',
noErrorOnMissing: true
}
],
options: {}
}),
new webpack.LoaderOptionsPlugin({
options: {
postcss: [
require('postcss-px2rem')({remUnit: 37.5})
]
}
})
],
devtool: (argv.mode === 'development') ? "eval" : "nosources-source-map",
optimization: {
splitChunks: {
cacheGroups: {
commons: {
chunks: 'async',
name: 'commons',
minChunks: 2,
maxInitialRequests: 5,
// minSize: 0
},
vendor: {
test:/node_modules/,
chunks:'all',
name:'vendor',
priority:10
}
}
},
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: (argv.mode === 'development') ? true : false
}),
new OptimizeCSSAssetsPlugin({})
]
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true, //是否启用gzip
host: 'localhost',
port: 9000,
hot: true, // 热更新
open: true,
overlay: true,
inline: true,
watchContentBase: true
}
})
.babelrc文件
{
"presets": ["@babel/preset-env"],
"plugins": ["@babel/plugin-transform-runtime"]
}