webpack 多页应用配置的基本思路是采用多入口配置,然后多次调用 html-webpack-plugin 来生成 html 文件。src下的目录,module下可配置每个单页面
1.webpack.base.conf.js修改(配置多个页面的js入口)
var path = require('path')
var config = require('../config')
var utils = require('./utils')
var projectRoot = path.resolve(__dirname, '../')
var autoprefixer = require('autoprefixer');
var glob = require('glob');
var entries = getEntry('./src/module/**/*.js'); // 获得入口js文件
var env = process.env.NODE_ENV
// check env & config/index.js to decide weither to enable CSS Sourcemaps for the
// various preprocessor loaders added to vue-loader at the end of this file
var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap)
var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap)
var useCssSourceMap = cssSourceMapDev || cssSourceMapProd
var autoprefixerConf = autoprefixer({ browsers: ['last 2 versions', 'Android >= 4.0', 'iOS >= 6'] });
module.exports = {
// entry: {
// app: './src/main.js'
// },
entry: entries,
output: {
path: config.build.assetsRoot,
publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
filename: '[name].js'
},
resolve: {
extensions: ['', '.js', '.vue', '.css'],
fallback: [path.join(__dirname, '../node_modules')],
alias: {
'vue$': 'vue/dist/vue',
'src': path.resolve(__dirname, '../src'),
'assets': path.resolve(__dirname, '../src/assets'),
'components': path.resolve(__dirname, '../src/components')
}
},
resolveLoader: {
fallback: [path.join(__dirname, '../node_modules')]
},
module: {
preLoaders: [],
loaders: [{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.js$/,
loader: 'babel',
include: projectRoot,
exclude: /node_modules/
},
{
test: /\.sass$/,
loaders: ['style', 'css', 'sass']
},
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url',
query: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url',
query: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
},
{
test: /.(mov|mp4)$/,
loader: 'url'
}
]
},
// js 中引入的样式处理
postcss: [autoprefixerConf],
// eslint: {
// formatter: require('eslint-friendly-formatter')
// },
vue: {
loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }),
postcss: [autoprefixerConf]
}
}
function getEntry(globPath) {
var entries = {},
basename, tmp, pathname;
glob.sync(globPath).forEach(function(entry) {
basename = path.basename(entry, path.extname(entry));
tmp = entry.split('/').splice(-3);
pathname = tmp.splice(0, 1) + '\/' + basename; // 正确输出js和html的路径
entries[pathname] = entry;
});
return entries;
}
2.webpack.dev.conf.js修改 (多页面模板的配置)
var path = require('path')
var config = require('../config')
var webpack = require('webpack')
var merge = require('webpack-merge')
var utils = require('./utils')
var baseWebpackConfig = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var glob = require('glob');
// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})
module.exports = merge(baseWebpackConfig, {
module: {
loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
},
// eval-source-map is faster for development
devtool: '#eval-source-map',
plugins: [
new webpack.DefinePlugin({
'process.env': config.dev.env
}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
]
})
function getEntry(globPath) {
var entries = {},
basename, tmp, pathname;
glob.sync(globPath).forEach(function (entry) {
basename = path.basename(entry, path.extname(entry));
tmp = entry.split('/').splice(-3);
pathname = tmp.splice(0, 1) + '/' + basename; // 正确输出js和html的路径
entries[pathname] = entry;
});
return entries;
}
var pages = getEntry('./src/module/**/*.html');
for (var pathname in pages) {
// 配置生成的html文件,定义路径等
var conf = {
filename: pathname + '.html',
template: pages[pathname], // 模板路径
chunks: [pathname, 'vendor', 'manifest'], // 每个html引用的js模块
inject: true // js插入位置
};
// 需要生成几个html文件,就配置几个HtmlWebpackPlugin对象
module.exports.plugins.push(new HtmlWebpackPlugin(conf));
}
3.webpack.prod.conf.js修改
var path = require('path')
var config = require('../config')
var utils = require('./utils')
var webpack = require('webpack')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var env = process.env.NODE_ENV === 'testing' ? require('../config/test.env') : config.build.env
var glob = require('glob');
module.exports = merge(baseWebpackConfig, {
module: {
loaders: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true
})
},
devtool: config.build.productionSourceMap ? '#source-map' : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
vue: {
loaders: utils.cssLoaders({
sourceMap: config.build.productionSourceMap,
extract: true
})
},
plugins: [
// http://vuejs.github.io/vue-loader/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new webpack.optimize.OccurenceOrderPlugin(),
// extract css into its own file
new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors', // 将公共模块提取,生成名为`vendors`的chunk
chunks: ['index','info'], //提取哪些模块共有的部分
minChunks: 2 // 提取至少2个模块共有的部分
}),
// // extract webpack runtime and module manifest to its own file in order to
// // prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
})
]
})
if (config.build.productionGzip) {
var CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,
minRatio: 0.8
})
)
}
function getEntry(globPath) {
var entries = [],
basename, tmp, pathname;
glob.sync(globPath).forEach(function(entry) {
basename = path.basename(entry, path.extname(entry));
tmp = entry.split('/').splice(-3);
pathname = tmp.splice(0, 1) + '/' + basename; // 正确输出js和html的路径
entries[pathname] = entry;
});
return entries;
}
var pages = getEntry('./src/module/**/*.html');
for (var pathname in pages) {
// 配置生成的html文件,定义路径等
var conf = {
filename: pathname + '.html',
template: pages[pathname], // 模板路径
chunks: [pathname, 'vendor', 'manifest'], // 每个html引用的js模块
inject: true, // js插入位置
minify: { //压缩HTML文件
removeComments: true, //移除HTML中的注释
collapseWhitespace: false, //删除空白符与换行符
removeAttributeQuotes: true //去除属性引用
}
};
// 需要生成几个html文件,就配置几个HtmlWebpackPlugin对象
module.exports.plugins.push(new HtmlWebpackPlugin(conf));
}
附上package.json
{
"name": "vue-cli-mulit",
"version": "1.0.0",
"description": "A Vue.js project",
"author": "yaoyao",
"private": true,
"scripts": {
"dev": "node build/dev-server.js",
"build": "node build/build.js",
"unit": "karma start test/unit/karma.conf.js --single-run",
"e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e",
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
},
"dependencies": {
"axios": "^0.18.0",
"clipboard": "^2.0.4",
"element-ui": "^2.6.1",
"jsonp": "^0.2.1",
"mint-ui": "^2.2.13",
"node-sass": "^4.12.0",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"vue": "^2.0.1",
"vue-rem": "^1.0.3",
"weixin-js-sdk": "^1.4.0-test"
},
"devDependencies": {
"autoprefixer": "^6.4.0",
"babel-core": "^6.0.0",
"babel-eslint": "^7.0.0",
"babel-loader": "^6.0.0",
"babel-plugin-component": "^1.1.1",
"babel-plugin-transform-runtime": "^6.0.0",
"babel-preset-es2015": "^6.0.0",
"babel-preset-stage-2": "^6.0.0",
"babel-register": "^6.0.0",
"chai": "^3.5.0",
"chromedriver": "^2.21.2",
"connect-history-api-fallback": "^1.3.0",
"cross-spawn": "^4.0.2",
"css-loader": "^0.25.0",
"eslint": "^3.7.1",
"eslint-config-standard": "^6.1.0",
"eslint-friendly-formatter": "^2.0.5",
"eslint-loader": "^1.5.0",
"eslint-plugin-html": "^1.3.0",
"eslint-plugin-promise": "^2.0.1",
"eslint-plugin-standard": "^2.0.1",
"eventsource-polyfill": "^0.9.6",
"express": "^4.13.3",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.9.0",
"function-bind": "^1.0.2",
"glob": "^7.1.1",
"html-webpack-plugin": "^2.8.1",
"http-proxy-middleware": "^0.17.2",
"inject-loader": "^2.0.1",
"isparta-loader": "^2.0.0",
"jquery": "^3.4.1",
"json-loader": "^0.5.4",
"karma": "^1.3.0",
"karma-coverage": "^1.1.1",
"karma-mocha": "^1.2.0",
"karma-phantomjs-launcher": "^1.0.0",
"karma-sinon-chai": "^1.2.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "0.0.26",
"karma-webpack": "^1.7.0",
"lolex": "^1.4.0",
"mocha": "^3.1.0",
"nightwatch": "^0.9.8",
"opn": "^4.0.2",
"ora": "^0.3.0",
"phantomjs-prebuilt": "^2.1.3",
"postcss-px2rem-exclude": "^0.0.6",
"selenium-server": "2.53.1",
"shelljs": "^0.7.4",
"sinon": "^1.17.3",
"sinon-chai": "^2.8.0",
"url-loader": "^0.5.7",
"vue-clipboard2": "^0.3.1",
"vue-loader": "^9.4.0",
"vue-resource": "^1.0.3",
"vue-router": "^2.0.1",
"vue-style-loader": "^1.0.0",
"webpack": "^1.13.2",
"webpack-dev-middleware": "^1.8.3",
"webpack-hot-middleware": "^2.12.2",
"webpack-merge": "^0.14.1"
}
}
项目打包好后 在dist文件下会生成两个文件,module和static,
module下就是一个一个的html页面了。