webpack多页面配置
项目目录结构如下:

config文件夹内代码如下:
index.js:
module.exports = { dev: { assetsSubDirectory: 'static', assetsPublicPath: '', devtool: 'cheap-module-eval-source-map', proxy: { '/api': { target: 'http://localhost:8888', changeOrigin: true, pathRewrite: { '^/api': '/api' } } }, // host: 'localhost', host:'0.0.0.0', port: 8888 }, prod: { assetsSubDirectory: 'static', assetsPublicPath: './', devtool: 'source-map' }, templatePc(data) { //PC sprite template return data.sprites.map(sprite => { return ( `.icon-${sprite.name} { width: ${sprite.px.width}; height: ${sprite.px.height}; background: url(${sprite.image}) ${sprite.px.offset_x} ${sprite.px.offset_y} no-repeat; background-size: ${sprite.px.total_width} ${sprite.px.total_height}; }\n`) }).join('') }, templateWeb(data) { //WEB sprite template return data.sprites.map(sprite => { return ( `.icon-${sprite.name} { width: ${sprite.width}pr; height: ${sprite.height}pr; background: url(${sprite.image}) ${sprite.offset_x}pr ${sprite.offset_y}pr no-repeat; background-size: ${sprite.total_width}pr ${sprite.total_height}pr; }\n`) }).join('') } }
utils.js内代码如下:
const glob = require('glob')
// const path = require('path')
exports.getEntry = function () {
const entry = {}
// 读取src目录所有page入口
glob.sync('../src/pages/*/*.js').forEach((name) => {
const start = name.indexOf('src/') + 4;
const end = name.length - 3;
const eArr = [];
const n = name.slice(start, end).split('/')[1];
eArr.push(name);
// eArr.push('@babel/polyfill'); // 引入这个,是为了用async await,一些IE不支持的属性能够受支持,兼容IE浏览器用的
entry[n] = eArr;
})
return entry;
}
exports.getEntry2 = function (globPath) {
var entries = {}, tmp, pathname
glob.sync(globPath).forEach(function (entry) {
tmp = entry.split('/').splice(-3)
pathname = tmp.splice(1, 1).toString().toLowerCase()
entries[pathname] = entry
})
return entries
}
webpack.config.base.js:
const path = require('path')
const config = require('./index')
const SpritesmithPlugin = require('webpack-spritesmith')
const utils = require('./utils')
function resolve(dir) {
return path.join(__dirname, '..', dir);
}
// const { getEntry } = require('./utils.js')
module.exports = {
context: path.resolve(__dirname, '../'),
// entry:getEntry(),
entry: utils.getEntry2("./src/pages/*/main.js"),
// entry: {
// main: './src/main.js'
// },
// entry:{
// index:'./src/pages/index/main.js',
// test:'./src/pages/test/main.js'
// },
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.prod.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.json', 'jsx'],
alias: {
'@': resolve('src'),
'@static': resolve('static')
},
modules: ['node_modules', resolve('src/assets/images')]
},
module: {
rules: [
{
test: /\.jsx?$/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}, {
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter')
}
}
],
exclude: [resolve('node_modules')],
include: [resolve('src')]
},
// {
// test: /\.html$/,
// loader: 'html-loader'
// },
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name]_[hash:8].[ext]'
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/[name]_[hash:8].[ext]'
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 100000,
name: 'fonts/[name]_[hash:8].[ext]'
}
}
]
},
plugins: [
new SpritesmithPlugin({
src: {
cwd: resolve('src/assets/images/icons'),
glob: '*.png'
},
target: {
image: resolve('src/assets/images/sprite.png'),
css: [
[resolve('src/assets/scss/_sprite.scss'), {
format: 'based_template'
}]
]
},
customTemplates: {
'based_template': config.templateWeb
},
apiOptions: {
cssImageRef: '../images/sprite.png'
},
spritesmithOptions: {
algorithm: 'top-down', //'top-down', 'left-right', 'diagonal', 'alt-diagonal', 'binary-tree'
padding: 10
}
})
],
externals: {
jquery: 'jQuery',
swiper: 'Swiper'
}
}
webpack.config.base.js:
const path = require('path')
const config = require('./index')
const webpackBaseConfig = require('./webpack.config.base')
const webpack = require('webpack')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')
const notifier = require('node-notifier')
const portfinder = require('portfinder')
const utils = require('./utils')
var pages = utils.getEntry2('./src/pages/**/index.html');
var htmls = [];
Object.keys(pages).forEach(name => {
var templateUrl = pages[name];
var templateThunks = [name]
htmls.push(new HtmlWebpackPlugin({
filename: name + '.html',
template: templateUrl, // 模板路径
inject: true,
chunks: templateThunks
}))
})
const webpackDevConfig = merge(webpackBaseConfig, {
mode: 'development',
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
sourceMap: true
}
},
'postcss-loader',
'sass-loader'
]
}
]
},
devtool: config.dev.devtool,
devServer: {
contentBase: path.join(__dirname, '../dist'),
clientLogLevel: 'warning',
historyApiFallback: true,
hot: true,
compress: true,
host: config.dev.host,
port: config.dev.port,
open: true,
overlay: {
warnings: true,
errors: true
},
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxy,
quiet: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
...htmls
// new HtmlWebpackPlugin({
// filename: 'index.html',
// template: './src/pages/index/index.html',
// inject: true,
// chunks:["index"]
// }),
// new HtmlWebpackPlugin({
// filename: 'test.html',
// template: './src/pages/test/index.html',
// inject: true,
// chunks:["test"]
// })
]
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
webpackDevConfig.devServer.port = port
webpackDevConfig.plugins.push(new FriendlyErrorsWebpackPlugin({
compilationSuccessInfo: {
messages: [`You application is running here ${webpackDevConfig.devServer.host}:${port}`]
},
onErrors: (severity, errors) => {
if (severity !== 'error') {
return
}
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: error.name,
subtitle: filename || '',
message: severity + ': ' + error.message
});
}
}))
resolve(webpackDevConfig)
}
})
})
webpack.config.prod.js:
const path = require('path')
const config = require('./index')
const webpackBaseConfig = require('./webpack.config.base')
const merge = require('webpack-merge')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') //extract css
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') //compress css
const TerserPlugin = require('terser-webpack-plugin') //compress js
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const utils = require('./utils')
var pages = utils.getEntry2('./src/pages/**/index.html');
var htmls = [];
Object.keys(pages).forEach(name => {
var templateUrl = pages[name];
var templateThunks = [name]
htmls.push(new HtmlWebpackPlugin({
filename: name + '.html',
template: templateUrl, // 模板路径
inject: true,
chunks: templateThunks
}))
})
const webpackProdConfig = merge(webpackBaseConfig, {
mode: 'development',
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'js/[name]_[chunkhash:8].js',
chunkFilename: 'js/[id]_[chunkhash:8].js',
publicPath: config.prod.assetsPublicPath
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'postcss-loader',
'sass-loader'
]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'image-webpack-loader',
enforce: 'pre'
}
]
},
devtool: config.prod.devtool,
optimization: {
concatenateModules: true,
splitChunks: {
chunks: 'all'
},
minimizer: [
new OptimizeCssAssetsPlugin(),
new TerserPlugin({
parallel: true,
cache: true,
terserOptions: {
compress: {
unused: true,
drop_debugger: true,
drop_console: true,
dead_code: true
}
}
}),
],
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name]_[contenthash:8].css',
chunkFilename: 'css/[name]_[contenthash:8].css',
}),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.optimize\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
},
canPrint: true
}),
...htmls,
// new HtmlWebpackPlugin({
// filename: '../dist/index.html',
// template: 'src/index.html',
// inject: true
// }),
new CopyWebpackPlugin([{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}]),
// new BundleAnalyzerPlugin()
]
})
module.exports = webpackProdConfig
package.json内script代码
"scripts": { "dev": "webpack-dev-server --inline --progress --config config/webpack.config.dev.js", "start": "npm run dev", "build": "webpack --progress --config config/webpack.config.prod.js" },
1、使用第三方库
1.1需要用到第三方库时需在页面引入,比如jq

1.2同时还在配置文件中解析
externals: { jquery: 'jQuery', swiper: 'Swiper' }
1.3最后在页面对应的main.js里使用时采用如下语法
import $ from 'jquery' $(".close_ly").click(function(){ $(".leyu_yspd,.toumingbi_yspd").hide() }) $(".head_onlineChat").click(function(){ $(".leyu_yspd,.toumingbi_yspd").show() })
2、引入样式
2.1直接在页面内对应的main.js里
import "@/assets/scss/select.scss"
3、引用组件
3.1在页面内使用
<%= require('html-loader!../../components/header.html') %>
注意这是EJS的语法,一定不能使用html-loader(html-loader会将模版以字符串方式解析)
// { // test: /\.html$/, // loader: 'html-loader' // },
4、图片引入
4.1页面引入图片
<img src="<%= require('../../assets/images/07.png') %>" alt="">
4.2组件内引入图片
<img src="../assets/images/03.png" alt="">

浙公网安备 33010602011771号