vue搭建多页面开发环境
vue搭建多页面开发环境
自从习惯开发了单页面应用,对多页面的页面间的相互跳转间没有过渡效果、难维护极度反感。但是最近公司技术老大说,当一个应用越来越大的时候单页面模式应付不来,但是没讲怎么应付不来,所以还得自己去复习一遍这两者的区别:

这样对比的话,单页面的优势确实很大,但当我自己去打开某宝,某东的移动端页面时,确实它们都是多页面应用。为什么?我能想到的就几点:
1.单页面使用的技术对低版本的浏览器不友好,大公司还得兼顾使用低版本浏览器的用户啊
2.功能模块开发来说,比如说单页面的业务公用组件,有时候你都不知道分给谁开发
3.seo优化吧(PS:既然是大应用应该很多人都知道,为什么还要做搜索引擎优化)
--------------------------------------------------华丽分割线------------------------------------------------------------------------------------
公司开发移动端使用的技术是vue,其实老大在要求使用多页面开发的时候,已经搭了一个vue多页面的脚手架供给我们去使用,但是我去看了看源码的时候写得很一般,所以决定自己重新去写过。
思路:
由于vue-cli已经写好了单页面的webpack文件,不去改动之前是它默认的一个页面引用打包的资源。既然是多页面,那么把webpack入口文件改成多个就好了啊。未改动时的webpack.base.conf.js(这个JS的功能主要在于全局配置,比如入口文件,出口文件,解析规则等)

1 // 把箭头部分的入口文件改为以下
2 entry: {
3 'index': '..../main.js' // 注意省略号是实际开发时的项目路径
4 'product': '..../main.js'
5 }
但是这样做效率得多低下,每增加一个新页面就要手动去添加新的入口,所以这里把入口文件封装为一个函数:
1 /**
2 * 获取多页面入口文件
3 * @globPath 文件路径
4 */
5 const glob = require('glob')
6 function getEntries(globPath) {
7 const entries = glob.sync(globPath).reduce((result, entry) => {
8 const moduleName = path.basename(path.dirname(entry)) // 获取模块名称
9 result[moduleName] = entry
10 return result
11 }, {})
12 return entries
13 }
注意在使用nodejs的glob模块之前,记得先下载依赖
测试一下这个函数

然后把webpack.base.config.js改为如下:
1 'use strict'
2 const path = require('path')
3 const utils = require('./utils')
4 const config = require('../config')
5 const vueLoaderConfig = require('./vue-loader.conf')
6
7 function resolve (dir) {
8 return path.join(__dirname, '..', dir)
9 }
10
11 const glob = require('glob')
12 function getEntries (globPath){
13 const entries = glob.sync(globPath).reduce((result, entry) => {
14 const moduleName = path.basename(path.dirname(entry)) // 获取模块名称
15 result[moduleName] = entry
16 return result
17 }, {})
18 return entries
19 }
20
21 const entries = getEntries('./src/modules/**/*.js')
22
23 module.exports = {
24 context: path.resolve(__dirname, '../'),
25 entry: entries, // 改动部分
26 output: {
27 path: config.build.assetsRoot,
28 filename: '[name].js',
29 publicPath: process.env.NODE_ENV === 'production'
30 ? config.build.assetsPublicPath
31 : config.dev.assetsPublicPath
32 },
33 resolve: {
34 extensions: ['.js', '.vue', '.json'],
35 alias: {
36 'vue$': 'vue/dist/vue.esm.js',
37 '@': resolve('src'),
38 }
39 },
40 module: {
41 rules: [
42 {
43 test: /\.vue$/,
44 loader: 'vue-loader',
45 options: vueLoaderConfig
46 },
47 {
48 test: /\.js$/,
49 loader: 'babel-loader',
50 include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
51 },
52 {
53 test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
54 loader: 'url-loader',
55 options: {
56 limit: 10000,
57 name: utils.assetsPath('img/[name].[hash:7].[ext]')
58 }
59 },
60 {
61 test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
62 loader: 'url-loader',
63 options: {
64 limit: 10000,
65 name: utils.assetsPath('media/[name].[hash:7].[ext]')
66 }
67 },
68 {
69 test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
70 loader: 'url-loader',
71 options: {
72 limit: 10000,
73 name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
74 }
75 }
76 ]
77 },
78 node: {
79 // prevent webpack from injecting useless setImmediate polyfill because Vue
80 // source contains it (although only uses it if it's native).
81 setImmediate: false,
82 // prevent webpack from injecting mocks to Node native modules
83 // that does not make sense for the client
84 dgram: 'empty',
85 fs: 'empty',
86 net: 'empty',
87 tls: 'empty',
88 child_process: 'empty'
89 }
90 }
注意我的多页面目录:

---------------------------------------华丽分割线----------------------------------------------------------------------
公共配置搞完之后是打包文件:webpack.prod.conf.js,打包文件的修改主要是输出文件的配置,因为要对应入口文件的文件夹,还有就是一个页面对应一个htmlwebpackplugin配置,这个配置是加在文件的plugins里面的,按照上面的消除手动加入配置的思路这里也加入htmlwebpackplugin的配置函数
1 /** 2 * 页面打包 3 * @entries 打包文件 4 * @config 参数配置 5 * @module 使用的主体 6 */ 7 const HtmlWebpackPlugin = require('html-webpack-plugin') 8 function pack (entries, module) { 9 for (const path in entries) { 10 const conf = { 11 filename: `modules/${path}/index.html`, 12 template: entries[path], // 模板路径 13 inject: true, 14 chunks: ['manifest', 'vendor', path] // 必须先引入公共依赖 15 } 16 module.plugins.push(new HtmlWebpackPlugin(conf)) 17 } 18 }
最终打包文件改为如下
1 'use strict' 2 const path = require('path') 3 const utils = require('./utils') 4 const webpack = require('webpack') 5 const config = require('../config') 6 const merge = require('webpack-merge') 7 const baseWebpackConfig = require('./webpack.base.conf') 8 const CopyWebpackPlugin = require('copy-webpack-plugin') 9 const HtmlWebpackPlugin = require('html-webpack-plugin') 10 const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 13 14 const env = require('../config/prod.env') 15 16 17 const glob = require('glob') 18 function getEntries (globPath){ 19 const entries = glob.sync(globPath).reduce((result, entry) => { 20 const moduleName = path.basename(path.dirname(entry)) // 获取模块名称 21 result[moduleName] = entry 22 return result 23 }, {}) 24 return entries 25 } 26 27 const entries = getEntries('./src/modules/**/*.html') // 获取多页面所有入口文件 28 29 const webpackConfig = merge(baseWebpackConfig, { 30 module: { 31 rules: utils.styleLoaders({ 32 sourceMap: config.build.productionSourceMap, 33 extract: true, 34 usePostCSS: true 35 }) 36 }, 37 devtool: config.build.productionSourceMap ? config.build.devtool : false, 38 output: { 39 path: config.build.assetsRoot, 40 filename: 'modules/[name]/[name].[chunkhash].js', 41 // publicPath: '/' // 改为相对路径 42 // chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 43 }, 44 plugins: [ 45 // http://vuejs.github.io/vue-loader/en/workflow/production.html 46 new webpack.DefinePlugin({ 47 'process.env': env 48 }), 49 new UglifyJsPlugin({ 50 uglifyOptions: { 51 compress: { 52 warnings: false 53 } 54 }, 55 sourceMap: config.build.productionSourceMap, 56 parallel: true 57 }), 58 // extract css into its own file 59 new ExtractTextPlugin({ 60 filename: utils.assetsPath('css/[name].[contenthash].css'), 61 // Setting the following option to `false` will not extract CSS from codesplit chunks. 62 // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. 63 // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 64 // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 65 allChunks: true, 66 }), 67 // Compress extracted CSS. We are using this plugin so that possible 68 // duplicated CSS from different components can be deduped. 69 new OptimizeCSSPlugin({ 70 cssProcessorOptions: config.build.productionSourceMap 71 ? { safe: true, map: { inline: false } } 72 : { safe: true } 73 }), 74 // generate dist index.html with correct asset hash for caching. 75 // you can customize output by editing /index.html 76 // see https://github.com/ampedandwired/html-webpack-plugin 77 // keep module.id stable when vendor modules does not change 78 new webpack.HashedModuleIdsPlugin(), 79 // enable scope hoisting 80 new webpack.optimize.ModuleConcatenationPlugin(), 81 // split vendor js into its own file 82 new webpack.optimize.CommonsChunkPlugin({ 83 name: 'vendor', 84 minChunks (module) { 85 // any required modules inside node_modules are extracted to vendor 86 return ( 87 module.resource && 88 /\.js$/.test(module.resource) && 89 module.resource.indexOf( 90 path.join(__dirname, '../node_modules') 91 ) === 0 92 ) 93 } 94 }), 95 // extract webpack runtime and module manifest to its own file in order to 96 // prevent vendor hash from being updated whenever app bundle is updated 97 new webpack.optimize.CommonsChunkPlugin({ 98 name: 'manifest', 99 minChunks: Infinity 100 }), 101 // This instance extracts shared chunks from code splitted chunks and bundles them 102 // in a separate chunk, similar to the vendor chunk 103 // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk 104 new webpack.optimize.CommonsChunkPlugin({ 105 name: 'app', 106 async: 'vendor-async', 107 children: true, 108 minChunks: 3 109 }), 110 111 // copy custom static assets 112 new CopyWebpackPlugin([ 113 { 114 from: path.resolve(__dirname, '../static'), 115 to: config.build.assetsSubDirectory, 116 ignore: ['.*'] 117 } 118 ]) 119 ] 120 }) 121 122 if (config.build.productionGzip) { 123 const CompressionWebpackPlugin = require('compression-webpack-plugin') 124 125 webpackConfig.plugins.push( 126 new CompressionWebpackPlugin({ 127 asset: '[path].gz[query]', 128 algorithm: 'gzip', 129 test: new RegExp( 130 '\\.(' + 131 config.build.productionGzipExtensions.join('|') + 132 ')$' 133 ), 134 threshold: 10240, 135 minRatio: 0.8 136 }) 137 ) 138 } 139 140 if (config.build.bundleAnalyzerReport) { 141 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 142 webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 143 } 144 145 146 function pack (entries, module) { 147 for (const path in entries) { 148 const conf = { 149 filename: `modules/${path}/index.html`, 150 template: entries[path], // 模板路径 151 inject: true, 152 chunks: ['manifest', 'vendor', path] // 必须先引入公共依赖 153 } 154 module.plugins.push(new HtmlWebpackPlugin(conf)) 155 } 156 } 157 158 pack(entries, webpackConfig) 159 module.exports = webpackConfig
然后启动npm run build尝试打包文件

OK,多页面的打包完成
参考:http://blog.csdn.net/u013291076/article/details/53667382
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
转载自

浙公网安备 33010602011771号