小程序越早做越好_详解Webpack4多页应用打包方案

详解Webpack4多页应用打包方案     -daydayup   这篇文章主要介绍了详解Webpack4多页应用打包方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

学习了 webpack 之后,将自己的博客的前端进行重构,由于自己的博客是多页应用,所以研究了下多页应用的打包方案。在这里把最后配置的成果分享下,不足之处,请指正。(文字不多,全是代码,不是配置教程,所以没有特别详细的写,只是一个参考)

文件目录结构

项目目录结构

首先先看下我的项目的目录结构

myblog-webpack
 ├── dist // 打包输出文件夹
 ├── src // 源代码
 │ ├── api // 请求文件夹,存放封装的请求方法
 │ ├── assets // 静态资源文件夹
 │ ├── lib // 一些库
 │ ├── pages // 页面
 │ │ ├── about // 页面名称
 │ │ │ ├──  // html模板
 │ │ │ └── index.js // 入口js
 │ │ ├── category
 │ │ │ ├── 
 │ │ │ └── index.js
 │ │ ├── detail
 │ │ │ ├── 
 │ │ │ └── index.js
 │ │ ├── index
 │ │ │ ├── 
 │ │ │ └── index.js
 │ │ └── tag
 │ │ ├── 
 │ │ └── index.js
 │ ├── styles // 样式文件
 │ └── utils // 工具函数
 ├── package.json
 ├── README.md
 ├── package-lock.json
 ├── webpack.base.js // 公共配置
 ├── webpack.dev.js // 开发环境配置
 └── webpack.prod.js // 生产环境配置

打包输出文件目录结构

最终打包输出的目录如下

 ├── assets
 ├── css
 │ ├── commons672a1e57.css
 │ └── index6085d612.css
 ├── js
 │ ├── aboutfc723f0e.js
 │ ├── categorye4be3bd6.js
 │ ├── commons78f1dd3f.js
 │ ├── detail0df434c5.js
 │ ├── indexe1e985d9.js
 │ ├── markdown-it
 │ │ ├── highlight.vendors.js
 │ │ ├── markdown-it-integrated.js
 │ │ ├── markdown-it-integrated.min.js
 │ │ ├── markdown-it-integrated.min.js.LICENSE.txt
 │ │ └── markdown-it.vendors.js
 │ └── tagf1c1035c.js
 ├── 
 ├── 
 ├── 
 ├── favicon.ico
 ├── 
 └── 

webpack 配置文件

注意:文中各部分所需的包名,并没有书写,请在附录中查找!!!相关配置的意义可以查找官方文档

公共配置

动态获取 entry 和设置 html-webpack-plugin

多页应用的打包思路是 每个页面对应一个 entry ,一个 html-webpack-plugin ,但每次新增或删除页面需要改 webpack 配置,所以需要根据文件目录动态获取入口,来设置 html-webpack-plugin 。

利用一个库 glob 来实现对文件目录的读取 具体代码如下,相关配置的意义可以查找官方文档

const path = require('path')
const glob = require('glob')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const setMPA = () = {
 const entry = {}
 const htmlWebpackPlugins = []
 const entryFiles = glob.sync(path.join(__dirname, './src/pages/*/index.js')) // 匹配各页面的对应入口文件
 entryFiles.forEach((item) = {
 const pageName = item.match(/pages\/(.*)\/index.js/)[1] // 获取文件夹名,即页面名称
 entry[pageName] = item // 设置入口文件路径
 // 设置html-webpack-plugin数组
 htmlWebpackPlugins.push(
 new HtmlWebpackPlugin({
 `),//模板地址
 `, //输出文件名
 chunks: [pageName], // 插入的js chunk名称,和output有关
 inject: true, 
 favicon: path.join(__dirname, './src/assets/favicon.ico'), // 图标
 minify: { //压缩代码
 html5: true,
 colla凡科抠图eWhitespace: true,
 preserveLineBreaks: false,
 minifyCSS: true,
 minifyJS: true,
 removeComments: false
 return {
 entry,
 htmlWebpackPlugins
const { entry, htmlWebpackPlugins } = setMPA()

使用 ES6 和 async、await ,以及 eslint

使用 ES6 和 async、await 以及 eslint ,需要借助 babel-loader 和 eslint-loader ,其具体配置很简单

babel 相关的库: @babel/core 、 @babel/preset-env 、 @babel/plugin-transform-regenerator 、 @babel/plugin-transform-runtime 、 eslint 相关的库: babel-eslint 、 eslint

module.rules 的配置

 test: /\.js$/,
 use: ['babel-loader', 'eslint-loader']

.babelrc 文件的配置

 "presets": [
 "@babel/preset-env"
 "plugins": [ //设置支持async和await
 "@babel/plugin-transform-runtime",
 "@babel/plugin-transform-regenerator"

.eslintrc.js 的配置

module.exports = {
 parser: 'babel-eslint',
 extends: ['alloy'], // eslint标准请自行选择下载
 env: {
 browser: true,
 node: true
 rules: {
 'no-new': 'off',
 'no-proto': 'off'
 // 'no-console': 'error'

加载图片

利用 url-loader ,具体 module.rules 配置如下

 test: /\.(png|svg|jpg|gif)$/,
 use: [
 loader: 'url-loader',
 options: {
 esModule: false,
 name: '[name][hash:8].[ext]', //文件指纹
 limit: 10240, // 转base64
 outputPath: './assets/images/' // 图片文件输出目录和publicPath有关

清理打包目录和复制文件到打包目录

自动清理打包目录利用 clean-webpack-plugin 插件,复制文件利用 copy-webpack-plugin

const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const basePlugins = [
 ...htmlWebpackPlugins, //之前配置的htmlWebpackPlugin数组
 new CleanWebpackPlugin(), // 自动清理构建目录
 new CopyWebpackPlugin({
 patterns: [
 from: path.join(__dirname, 'src/lib/markdown-it'), // 源
 to: path.join(__dirname, 'dist/js/markdown-it') // 目标位置

.browserslistrc 配置

# Browsers that we support
last 2 version
iOS 7

开发环境配置

热更新以及 devServer

具体配置如下:

plugins: [...basePlugins, new webpack.HotModuleReplacementPlugin()], //热更新插件
devServer: {
 contentBase: 'dist', // 开启服务的目录
 hot: true, //热更新开启
 proxy: {
 '/api': {
 target: '/代理
 pathRewrite: { '^/api': '' }

CSS 相关配置

module.rules 的配置如下

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

出口

output: {
 filename: '[name].js',
 path: path.join(__dirname, 'dist')

生产环境配置

出口

output: {
 filename: 'js/[name][chunkhash:8].js', // 统一输出到js文件夹
 path: path.join(__dirname, 'dist'),
 publicPath: '/' // 服务路径

js 代码压缩

利用 terser-webpack-plugin 插件,配置 optimization

const TerserPlugin = require('terser-webpack-plugin')
optimization: {
 minimize: true,
 minimizer: [
 new TerserPlugin({
 include: [/\.js$/]

CSS 相关配置

CSS 代码压缩,利用 optimize-css-assets-webpack-plugin 和 cssnano

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
plugins: [
 new OptimizeCSSAssetsPlugin({
 assetNameRegExp: /\.css$/g,
 cssProcessor: require('cssnano')

CSS 分离单独文件,利用 mini-css-extract-plugin

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module: {
 rules: [
 ...baseModuleRules,
 test: /\.less$/,
 use: [
 loader: MiniCssExtractPlugin.loader,
 options: {
 esModule: true
 'css-loader',
 'less-loader'
 test: /\.css$/,
 use: [
 loader: MiniCssExtractPlugin.loader,
 options: {
 esModule: true
 'css-loader'
plugins: [
 ...basePlugins,
 new MiniCssExtractPlugin({
 filename: 'css/[name][contenthash:8].css' // 输出文件名和地址

PostCSS 插件 autoprefixer 自动补齐 CSS3 前缀

module: {
 rules: [
 ...baseModuleRules,
 test: /\.less$/,
 use: [
 loader: MiniCssExtractPlugin.loader,
 options: {
 esModule: true
 'css-loader',
 loader: 'postcss-loader',
 options: {
 plugins: () = [require('autoprefixer')]
 'less-loader'

分离公共文件(CSS和JS)

配置 optimization.splitChunks

optimization: {
 splitChunks: {
 cacheGrou凡科抠图: {
 commons: {
 name: 'commons',
 chunks: 'all',
 minChunks: 2 // 最少引用两次

使用相关注意

html-webpack-plugin 模板使用以及 html-loader

导入 html 片段,在相应位置写下面的代码就像,需要注意的是, html-loader 加载的 html 片段内部 %% 语法会失效

 %= require("html-loader!@/") % 

html 中图片的加载。在 html 中相关的 img 标签的图片, html-loader 加载时会自动调用 url-loader ,但是存在问题,加载出来的路径没有 "" 。为了避免这个问题,我就没有再 html-loader 加载的 html 片段中使用图片,而是直接再 html 模

板中直接用 require

 img src=" %= require('@/assets/logo362x82.png') % " alt="" / 

附录

配置文件完整版

webpack.base.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const path = require('path')
const glob = require('glob')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const setMPA = () = {
 const entry = {}
 const htmlWebpackPlugins = []
 const entryFiles = glob.sync(path.join(__dirname, './src/pages/*/index.js'))
 entryFiles.forEach((item) = {
 const pageName = item.match(/pages\/(.*)\/index.js/)[1]
 entry[pageName] = item
 htmlWebpackPlugins.push(
 new HtmlWebpackPlugin({
 `),
 `,
 chunks: [pageName],
 inject: true,
 favicon: path.join(__dirname, './src/assets/favicon.ico'),
 minify: {
 html5: true,
 colla凡科抠图eWhitespace: true,
 preserveLineBreaks: false,
 minifyCSS: true,
 minifyJS: true,
 removeComments: false
 return {
 entry,
 htmlWebpackPlugins
const { entry, htmlWebpackPlugins } = setMPA()
const baseModuleRules = [
 test: /\.js$/,
 use: ['babel-loader', 'eslint-loader']
 test: /\.(png|svg|jpg|gif)$/,
 use: [
 loader: 'url-loader',
 options: {
 esModule: false,
 name: '[name][hash:8].[ext]',
 limit: 10240,
 outputPath: './assets/images/'
const basePlugins = [
 ...htmlWebpackPlugins,
 new CleanWebpackPlugin(),
 new CopyWebpackPlugin({
 patterns: [
 from: path.join(__dirname, 'src/lib/markdown-it'),
 to: path.join(__dirname, 'dist/js/markdown-it')
module.exports = {
 entry,
 baseModuleRules,
 basePlugins

webpack.dev.js

const webpack = require('webpack')
const path = require('path')
const { entry, baseModuleRules, basePlugins } = require('./webpack.base.js')
module.exports = {
 mode: 'development',
 entry,
 output: {
 filename: '[name].js',
 path: path.join(__dirname, 'dist')
 module: {
 rules: [
 ...baseModuleRules,
 test: /\.less$/,
 use: ['style-loader', 'css-loader', 'less-loader']
 test: /\.css$/,
 use: ['style-loader', 'css-loader']
 resolve: {
 // 设置别名
 alias: {
 '@': path.join(__dirname, 'src') // 这样配置后 @ 可以指向 src 目录
 plugins: [...basePlugins, new webpack.HotModuleReplacementPlugin()],
 devServer: {
 contentBase: 'dist',
 hot: true,
 proxy: {
 '/api': {
 target: 'api': '' }

webpack.prod.js

const { entry, baseModuleRules, basePlugins } = require('./webpack.base.js')
const path = require('path')
const TerserPlugin = require('terser-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
 mode: 'production',
 entry,
 output: {
 filename: 'js/[name][chunkhash:8].js',
 path: path.join(__dirname, 'dist'),
 publicPath: '/'
 resolve: {
 // 设置别名
 alias: {
 '@': path.resolve('src') // 这样配置后 @ 可以指向 src 目录
 module: {
 rules: [
 ...baseModuleRules,
 test: /\.less$/,
 use: [
 loader: MiniCssExtractPlugin.loader,
 options: {
 esModule: true
 'css-loader',
 loader: 'postcss-loader',
 options: {
 plugins: () = [require('autoprefixer')]
 'less-loader'
 test: /\.css$/,
 use: [
 loader: MiniCssExtractPlugin.loader,
 options: {
 esModule: true
 'css-loader'
 plugins: [
 ...basePlugins,
 new MiniCssExtractPlugin({
 filename: 'css/[name][contenthash:8].css'
 new OptimizeCSSAssetsPlugin({
 assetNameRegExp: /\.css$/g,
 cssProcessor: require('cssnano')
 optimization: {
 minimize: true,
 minimizer: [
 new TerserPlugin({
 include: [/\.js$/]
 splitChunks: {
 cacheGrou凡科抠图: {
 commons: {
 name: 'commons',
 chunks: 'all',
 minChunks: 2
}

package.json文件

 "name": "myblog-webpack",
 "version": "1.0.0",
 "description": "",
 "main": ".eslintrc.js",
 "scripts": {
 "test": "echo \"Error: no test specified\" exit 1",
 "build": "webpack --config webpack.prod.js",
 "dev": "webpack-dev-server --config webpack.dev.js --open"
 "keywords": [],
 "author": "",
 "license": "ISC",
 "devDependencies": {
 "@babel/core": "^7.10.2",
 "@babel/plugin-transform-regenerator": "^7.10.3",
 "@babel/plugin-transform-runtime": "^7.10.3",
 "@babel/preset-env": "^7.10.2",
 "autoprefixer": "^9.8.4",
 "babel-eslint": "^10.1.0",
 "babel-loader": "^8.1.0",
 "clean-webpack-plugin": "^3.0.0",
 "copy-webpack-plugin": "^6.0.3",
 "css-loader": "^3.6.0",
 "cssnano": "^4.1.10",
 "eslint": "^7.2.0",
 "eslint-config-alloy": "^3.7.2",
 "eslint-loader": "^4.0.2",
 "file-loader": "^6.0.0",
 "glob": "^7.1.6",
 "html-loader": "^1.1.0",
 "html-webpack-plugin": "^4.3.0",
 "less-loader": "^6.1.2",
 "mini-css-extract-plugin": "^0.9.0",
 "optimize-css-assets-webpack-plugin": "^5.0.3",
 "postcss-loader": "^3.0.0",
 "style-loader": "^1.2.1",
 "terser-webpack-plugin": "^3.0.5",
 "url-loader": "^4.1.0",
 "webpack": "^4.43.0",
 "webpack-cli": "^3.3.11",
 "webpack-dev-server": "^3.11.0"
 "dependencies": {
 "axios": "^0.19.2"

到此这篇关于详解Webpack4多页应用打包方案的文章就介绍到这了,更多相关Webpack4多应用打包内容请搜索凡科以前的文章或继续浏览下面的