基于Vue.js的大型报告页项目实现过程及问题总结(一)
2017-11-02 14:19
651 查看
今年5月份的时候做了一个测评报告项目,需要在网页正常显示的同时且可打印为pdf,当时的技术方案采用jquery+template的方式,因为是固定模板所以并没有考虑报告的模块化区分,九月底产品提出新的需求,由于报告页数动辄上千页,所以希望用户自行选择内容生成报告,这个时候原项目就不够灵活了,与小伙伴商量决定将这个项目使用vue进行重构,对报告模块进行细分封装组件复用,大概一个月的工期,中途遇到n多坑,趁着今天有时间将实现思路整理出来并将出现的问题总结一下
整体的实现思维导图如下:
需要考虑的:
1.可生成PDF版且可打印
2.根据后台获取的json生成包含相应模块的报告
3.组件内基于echarts封装图表的引用
4.目录模块的页码定位
5.如何进行模块内的细分(如1.2.1.3);
6.webpack对多页面编译的配置
Ps:转PDF插件使用的是OpenHtmlToPdf具体配置方法可自行百度,在这里不过多赘述。
关于pdf的一点小坑(知识点朋友们!):
网页打印A4纸的尺寸是(1123*793),在使用OpenHtmlToPdf时无法使用css3百分之八十的属性,像translate等,还有就是margin-top不会生效,使用padding-top代替吧,打印生无法请求ajax,如需打印请将数据先存储到本地再行打印,可根据不同浏览方式判断两种方案。
以下实现全部是基于Vue-cli快速构建的项目中实现的,vue-cli的安装网上有很多详细的教程不过多说了
1.新建项目,命令行执行代码:
命令输入后,会进入安装阶段,需要用户输入一些信息
Projectname(vuetest)项目名称,可以自己指定,也可直接回车,按照括号中默认名字(注意这里的名字不能有大写字母,如果有会报错Sorry,namecannolongercontaincapitalletters),阮一峰老师博客为什么文件名要小写,可以参考一下。
Projectdescription(AVue.jsproject)项目描述,也可直接点击回车,使用默认名字
Author(........)作者,不用说了,你想输什么就输什么吧
接下来会让用户选择
Runtime+Compiler:recommendedformostusers运行加编译,既然已经说了推荐,就选它了
Runtime-only:about6KBlightermin+gzip,buttemplates(oranyVue-specificHTML)areONLYallowedin.vuefiles-renderfunctionsarerequiredelsewhere仅运行时,已经有推荐了就选择第一个了
Installvue-router?(Y/n)是否安装vue-router,这是官方的路由,大多数情况下都使用,vue-router官网。这里就输入“y”后回车即可。
UseESLinttolintyourcode?(Y/n)是否使用ESLint管理代码,ESLint是个代码风格管理工具,是用来统一代码风格的,并不会影响整体的运行,这也是为了多人协作,新手就不用了,一般项目中都会使用。ESLint官网
接下来也是选择题PickanESLintpreset(Usearrowkeys)选择一个ESLint预设,编写vue项目时的代码风格,因为我选择了使用ESLint
Standard(https://github.com/feross/standard)标准,有些看不明白,什么标准呢,去给提示的standardgithub地址看一下,原来时js的标准风格
AirBNB(https://github.com/airbnb/javascript)JavaScript最合理的方法,这个github地址说的是JavaScript最合理的方法
none(configureityourself)这个不用说,自己定义风格
具体选择哪个因人而异吧,我选择标准风格
SetupunittestswithKarma+Mocha?(Y/n)是否安装单元测试,我选择安装
Setupe2etestswithNightwatch(Y/n)?是否安装e2e测试,我选择安装
完成
初始的目录结构大概是这样的
由于是多页面应用所以需要在src下建一个modle文件夹里面是两个不同的项目
注意:
这里的index.html是入口文件,一定不能少,这这里做中转默认进入demo1的页面
下面对多页面进行配置,主要操作config和build这两个文件夹
varpath=require('path')
varconfig=require('../config')
varutils=require('./utils')
varprojectRoot=path.resolve(__dirname,'../')
varglob=require('glob');
varentries=getEntry(['./src/demo1/index/*.js','./src/module/demo2/*.js']);//获得入口js文件
varenv=process.env.NODE_ENV
//checkenv&config/index.jstodecideweithertoenableCSSSourcemapsforthe
//variouspreprocessorloadersaddedtovue-loaderattheendofthisfile
varcssSourceMapDev=(env==='development'&&config.dev.cssSourceMap)
varcssSourceMapProd=(env==='production'&&config.build.productionSourceMap)
varuseCssSourceMap=cssSourceMapDev||cssSourceMapProd
module.exports={
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','.json'],
fallback:[path.join(__dirname,'../node_modules')],
alias:{
'vue$':'vue/dist/vue',
'src':path.resolve(__dirname,'../src'),
'common':path.resolve(__dirname,'../src/common'),
'components':path.resolve(__dirname,'../src/components')
}
},
resolveLoader:{
fallback:[path.join(__dirname,'../node_modules')]
},
module:{
loaders:[{
test:/\.vue$/,
loader:'vue'
},
{
test:/\.js$/,
loader:'babel',
include:projectRoot,
exclude:/node_modules/
},
{
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]')
}
}
]
},
vue:{
loaders:utils.cssLoaders({
sourceMap:useCssSourceMap
}),
postcss:[
require('autoprefixer')({
browsers:['last2versions']
})
]
}
}
functiongetEntry(globPath){
varentries={},
basename,tmp,pathname;
if(typeof(globPath)!="object"){
globPath=[globPath]
}
globPath.forEach((itemPath)=>{
glob.sync(itemPath).forEach(function(entry){
basename=path.basename(entry,path.extname(entry));
if(entry.split('/').length>4){
tmp=entry.split('/').splice(-3);
pathname=tmp.splice(0,1)+'/'+basename;//正确输出js和html的路径
entries[pathname]=entry;
}else{
entries[basename]=entry;
}
});
});
returnentries;
}
这里是根据目录生成对应的页面
varpath=require('path');
varconfig=require('../config')
varwebpack=require('webpack')
varmerge=require('webpack-merge')
varutils=require('./utils')
varbaseWebpackConfig=require('./webpack.base.conf')
varHtmlWebpackPlugin=require('html-webpack-plugin')
varglob=require('glob')
//addhot-reloadrelatedcodetoentrychunks
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-mapisfasterfordevelopment
devtool:'#eval-source-map',
plugins:[
newwebpack.DefinePlugin({
'process.env':config.dev.env
}),
//https://github.com/glenjamin/webpack-hot-middleware#installation--usagenewwebpack.optimize.OccurenceOrderPlugin(),
newwebpack.HotModuleReplacementPlugin(),
newwebpack.NoErrorsPlugin()
]
})
functiongetEntry(globPath){
varentries={},
basename,tmp,pathname;
if(typeof(globPath)!="object"){
globPath=[globPath]
}
globPath.forEach((itemPath)=>{
glob.sync(itemPath).forEach(function(entry){
basename=path.basename(entry,path.extname(entry));
if(entry.split('/').length>4){
tmp=entry.split('/').splice(-3);
pathname=tmp.splice(0,1)+'/'+basename;//正确输出js和html的路径
entries[pathname]=entry;
}else{
entries[basename]=entry;
}
});
});
returnentries;
}
varpages=getEntry(['./src/module/*.html','./src/module/**/*.html']);
for(varpathnameinpages){
//配置生成的html文件,定义路径等
varconf={
filename:pathname+'.html',
template:pages[pathname],//模板路径
inject:true,//js插入位置
//necessarytoconsistentlyworkwithmultiplechunksviaCommonsChunkPlugin
chunksSortMode:'dependency'
};
if(pathnameinmodule.exports.entry){
conf.chunks=['manifest','vendor',pathname];
conf.hash=true;
}
module.exports.plugins.push(newHtmlWebpackPlugin(conf));
}
ok,配置结束,一个基本的多页面应用已经成功建成
接下来就进入正题了,放在下一篇来写。。。。。。。
整体的实现思维导图如下:
需要考虑的:
1.可生成PDF版且可打印
2.根据后台获取的json生成包含相应模块的报告
3.组件内基于echarts封装图表的引用
4.目录模块的页码定位
5.如何进行模块内的细分(如1.2.1.3);
6.webpack对多页面编译的配置
Ps:转PDF插件使用的是OpenHtmlToPdf具体配置方法可自行百度,在这里不过多赘述。
关于pdf的一点小坑(知识点朋友们!):
网页打印A4纸的尺寸是(1123*793),在使用OpenHtmlToPdf时无法使用css3百分之八十的属性,像translate等,还有就是margin-top不会生效,使用padding-top代替吧,打印生无法请求ajax,如需打印请将数据先存储到本地再行打印,可根据不同浏览方式判断两种方案。
以下实现全部是基于Vue-cli快速构建的项目中实现的,vue-cli的安装网上有很多详细的教程不过多说了
1.新建项目,命令行执行代码:
vueinitwebpackvuetest
命令输入后,会进入安装阶段,需要用户输入一些信息
Projectname(vuetest)项目名称,可以自己指定,也可直接回车,按照括号中默认名字(注意这里的名字不能有大写字母,如果有会报错Sorry,namecannolongercontaincapitalletters),阮一峰老师博客
Projectdescription(AVue.jsproject)项目描述,也可直接点击回车,使用默认名字
Author(........)作者,不用说了,你想输什么就输什么吧
接下来会让用户选择
Runtime+Compiler:recommendedformostusers运行加编译,既然已经说了推荐,就选它了
Runtime-only:about6KBlightermin+gzip,buttemplates(oranyVue-specificHTML)areONLYallowedin.vuefiles-renderfunctionsarerequiredelsewhere仅运行时,已经有推荐了就选择第一个了
Installvue-router?(Y/n)是否安装vue-router,这是官方的路由,大多数情况下都使用,
UseESLinttolintyourcode?(Y/n)是否使用ESLint管理代码,ESLint是个代码风格管理工具,是用来统一代码风格的,并不会影响整体的运行,这也是为了多人协作,新手就不用了,一般项目中都会使用。
接下来也是选择题PickanESLintpreset(Usearrowkeys)选择一个ESLint预设,编写vue项目时的代码风格,因为我选择了使用ESLint
Standard(https://github.com/feross/standard)标准,有些看不明白,什么标准呢,去给提示的
AirBNB(https://github.com/airbnb/javascript)JavaScript最合理的方法,这个github地址说的是JavaScript最合理的方法
none(configureityourself)这个不用说,自己定义风格
具体选择哪个因人而异吧,我选择标准风格
SetupunittestswithKarma+Mocha?(Y/n)是否安装单元测试,我选择安装
Setupe2etestswithNightwatch(Y/n)?是否安装e2e测试,我选择安装
完成
初始的目录结构大概是这样的
由于是多页面应用所以需要在src下建一个modle文件夹里面是两个不同的项目
注意:
这里的index.html是入口文件,一定不能少,这这里做中转默认进入demo1的页面
<body> <script> location.href="module/demo1.html"; </script> </body>
下面对多页面进行配置,主要操作config和build这两个文件夹
/build build.js#构建生产代码 dev-client.js dev-server.js#执行本地服务器 utils.js#额外的通用方法 webpack.base.conf.js#默认的webpack配置 webpack.dev.conf.js#本地开发的webpack配置 webpack.prod.conf.js#构建生产的webpack配置 /config配置文件 dev.env.js index.js pord.env.js test.env.js /src assets#放资源 components#组件 /module#页面模块 /home#子页面 index.html#模版页面 index.js#js入口 //注意,这里的html和js的文件名要一致,如上面就是index /dist#最后打包生成的资源 /js /css /home
修改默认的webpack配置webpack.base.conf.js
生成需要的入口文件
varpath=require('path')
varconfig=require('../config')
varutils=require('./utils')
varprojectRoot=path.resolve(__dirname,'../')
varglob=require('glob');
varentries=getEntry(['./src/demo1/index/*.js','./src/module/demo2/*.js']);//获得入口js文件
varenv=process.env.NODE_ENV
//checkenv&config/index.jstodecideweithertoenableCSSSourcemapsforthe
//variouspreprocessorloadersaddedtovue-loaderattheendofthisfile
varcssSourceMapDev=(env==='development'&&config.dev.cssSourceMap)
varcssSourceMapProd=(env==='production'&&config.build.productionSourceMap)
varuseCssSourceMap=cssSourceMapDev||cssSourceMapProd
module.exports={
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','.json'],
fallback:[path.join(__dirname,'../node_modules')],
alias:{
'vue$':'vue/dist/vue',
'src':path.resolve(__dirname,'../src'),
'common':path.resolve(__dirname,'../src/common'),
'components':path.resolve(__dirname,'../src/components')
}
},
resolveLoader:{
fallback:[path.join(__dirname,'../node_modules')]
},
module:{
loaders:[{
test:/\.vue$/,
loader:'vue'
},
{
test:/\.js$/,
loader:'babel',
include:projectRoot,
exclude:/node_modules/
},
{
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]')
}
}
]
},
vue:{
loaders:utils.cssLoaders({
sourceMap:useCssSourceMap
}),
postcss:[
require('autoprefixer')({
browsers:['last2versions']
})
]
}
}
functiongetEntry(globPath){
varentries={},
basename,tmp,pathname;
if(typeof(globPath)!="object"){
globPath=[globPath]
}
globPath.forEach((itemPath)=>{
glob.sync(itemPath).forEach(function(entry){
basename=path.basename(entry,path.extname(entry));
if(entry.split('/').length>4){
tmp=entry.split('/').splice(-3);
pathname=tmp.splice(0,1)+'/'+basename;//正确输出js和html的路径
entries[pathname]=entry;
}else{
entries[basename]=entry;
}
});
});
returnentries;
}
修改本地开发的webpack配置webpack.dev.conf.js
这里是和本地服务器有关的配置
这里是根据目录生成对应的页面
varpath=require('path');
varconfig=require('../config')
varwebpack=require('webpack')
varmerge=require('webpack-merge')
varutils=require('./utils')
varbaseWebpackConfig=require('./webpack.base.conf')
varHtmlWebpackPlugin=require('html-webpack-plugin')
varglob=require('glob')
//addhot-reloadrelatedcodetoentrychunks
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-mapisfasterfordevelopment
devtool:'#eval-source-map',
plugins:[
newwebpack.DefinePlugin({
'process.env':config.dev.env
}),
//
newwebpack.HotModuleReplacementPlugin(),
newwebpack.NoErrorsPlugin()
]
})
functiongetEntry(globPath){
varentries={},
basename,tmp,pathname;
if(typeof(globPath)!="object"){
globPath=[globPath]
}
globPath.forEach((itemPath)=>{
glob.sync(itemPath).forEach(function(entry){
basename=path.basename(entry,path.extname(entry));
if(entry.split('/').length>4){
tmp=entry.split('/').splice(-3);
pathname=tmp.splice(0,1)+'/'+basename;//正确输出js和html的路径
entries[pathname]=entry;
}else{
entries[basename]=entry;
}
});
});
returnentries;
}
varpages=getEntry(['./src/module/*.html','./src/module/**/*.html']);
for(varpathnameinpages){
//配置生成的html文件,定义路径等
varconf={
filename:pathname+'.html',
template:pages[pathname],//模板路径
inject:true,//js插入位置
//necessarytoconsistentlyworkwithmultiplechunksviaCommonsChunkPlugin
chunksSortMode:'dependency'
};
if(pathnameinmodule.exports.entry){
conf.chunks=['manifest','vendor',pathname];
conf.hash=true;
}
module.exports.plugins.push(newHtmlWebpackPlugin(conf));
}
修改构建生产的webpack配置webpack.prod.conf.js
varpath=require('path')
varconfig=require('../config')
varutils=require('./utils')
varwebpack=require('webpack')
varmerge=require('webpack-merge')
varbaseWebpackConfig=require('./webpack.base.conf')
varExtractTextPlugin=require('extract-text-webpack-plugin')
varHtmlWebpackPlugin=require('html-webpack-plugin')
varCleanPlugin=require('clean-webpack-plugin')//webpack插件,用于清除目录文件
varglob=require('glob');
varenv=config.build.env
varwebpackConfig=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.htmlnewwebpack.DefinePlugin({
'process.env':env
}),
newwebpack.optimize.UglifyJsPlugin({
compress:{
warnings:false
}
}),
newCleanPlugin(['../dist']),//清空生成目录
newwebpack.optimize.OccurenceOrderPlugin(),
//extractcssintoitsownfile
newExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')),
//generatedistindex.htmlwithcorrectassethashforcaching.
//youcancustomizeoutputbyediting/index.html
//seehttps://github.com/ampedandwired/html-webpack-plugin//splitvendorjsintoitsownfile
newwebpack.optimize.CommonsChunkPlugin({
name:'vendor',
minChunks:function(module,count){
//anyrequiredmodulesinsidenode_modulesareextractedtovendor
return(
module.resource&&
/\.js$/.test(module.resource)&&
module.resource.indexOf(
path.join(__dirname,'../node_modules')
)===0
)
}
}),
//extractwebpackruntimeandmodulemanifesttoitsownfileinorderto
//preventvendorhashfrombeingupdatedwheneverappbundleisupdated
newwebpack.optimize.CommonsChunkPlugin({
name:'manifest',
chunks:['vendor']
})
]
})
if(config.build.productionGzip){
varCompressionWebpackPlugin=require('compression-webpack-plugin')
webpackConfig.plugins.push(
newCompressionWebpackPlugin({
asset:'[path].gz[query]',
algorithm:'gzip',
test:newRegExp(
'\\.('+
config.build.productionGzipExtensions.join('|')+
')$'
),
threshold:10240,
minRatio:0.8
})
)
}
module.exports=webpackConfig
functiongetEntry(globPath){
varentries={},
basename,tmp,pathname;
if(typeof(globPath)!="object"){
globPath=[globPath]
}
globPath.forEach((itemPath)=>{
glob.sync(itemPath).forEach(function(entry){
basename=path.basename(entry,path.extname(entry));
if(entry.split('/').length>4){
tmp=entry.split('/').splice(-3);
pathname=tmp.splice(0,1)+'/'+basename;//正确输出js和html的路径
entries[pathname]=entry;
}else{
entries[basename]=entry;
}
});
});
returnentries;
}
varpages=getEntry(['./src/module/*.html','./src/module/**/*.html']);
for(varpathnameinpages){
//配置生成的html文件,定义路径等
varconf={
filename:pathname+'.html',
template:pages[pathname],//模板路径
inject:true,//js插入位置
//necessarytoconsistentlyworkwithmultiplechunksviaCommonsChunkPlugin
chunksSortMode:'dependency'
};
if(pathnameinmodule.exports.entry){
conf.chunks=['manifest','vendor',pathname];
conf.hash=true;
}
module.exports.plugins.push(newHtmlWebpackPlugin(conf));
}
varpath=require('path')
varconfig=require('../config')
varutils=require('./utils')
varwebpack=require('webpack')
varmerge=require('webpack-merge')
varbaseWebpackConfig=require('./webpack.base.conf')
varExtractTextPlugin=require('extract-text-webpack-plugin')
varHtmlWebpackPlugin=require('html-webpack-plugin')
varCleanPlugin=require('clean-webpack-plugin')//webpack插件,用于清除目录文件
varglob=require('glob');
varenv=config.build.env
varwebpackConfig=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.htmlnewwebpack.DefinePlugin({
'process.env':env
}),
newwebpack.optimize.UglifyJsPlugin({
compress:{
warnings:false
}
}),
newCleanPlugin(['../dist']),//清空生成目录
newwebpack.optimize.OccurenceOrderPlugin(),
//extractcssintoitsownfile
newExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')),
//generatedistindex.htmlwithcorrectassethashforcaching.
//youcancustomizeoutputbyediting/index.html
//seehttps://github.com/ampedandwired/html-webpack-plugin//splitvendorjsintoitsownfile
newwebpack.optimize.CommonsChunkPlugin({
name:'vendor',
minChunks:function(module,count){
//anyrequiredmodulesinsidenode_modulesareextractedtovendor
return(
module.resource&&
/\.js$/.test(module.resource)&&
module.resource.indexOf(
path.join(__dirname,'../node_modules')
)===0
)
}
}),
//extractwebpackruntimeandmodulemanifesttoitsownfileinorderto
//preventvendorhashfrombeingupdatedwheneverappbundleisupdated
newwebpack.optimize.CommonsChunkPlugin({
name:'manifest',
chunks:['vendor']
})
]
})
if(config.build.productionGzip){
varCompressionWebpackPlugin=require('compression-webpack-plugin')
webpackConfig.plugins.push(
newCompressionWebpackPlugin({
asset:'[path].gz[query]',
algorithm:'gzip',
test:newRegExp(
'\\.('+
config.build.productionGzipExtensions.join('|')+
')$'
),
threshold:10240,
minRatio:0.8
})
)
}
module.exports=webpackConfig
functiongetEntry(globPath){
varentries={},
basename,tmp,pathname;
if(typeof(globPath)!="object"){
globPath=[globPath]
}
globPath.forEach((itemPath)=>{
glob.sync(itemPath).forEach(function(entry){
basename=path.basename(entry,path.extname(entry));
if(entry.split('/').length>4){
tmp=entry.split('/').splice(-3);
pathname=tmp.splice(0,1)+'/'+basename;//正确输出js和html的路径
entries[pathname]=entry;
}else{
entries[basename]=entry;
}
});
});
returnentries;
}
varpages=getEntry(['./src/module/*.html','./src/module/**/*.html']);
for(varpathnameinpages){
//配置生成的html文件,定义路径等
varconf={
filename:pathname+'.html',
template:pages[pathname],//模板路径
inject:true,//js插入位置
//necessarytoconsistentlyworkwithmultiplechunksviaCommonsChunkPlugin
chunksSortMode:'dependency'
};
if(pathnameinmodule.exports.entry){
conf.chunks=['manifest','vendor',pathname];
conf.hash=true;
}
module.exports.plugins.push(newHtmlWebpackPlugin(conf));
}
修改配置文件config
修改index.js
在build.js中会引用assetsRoot,这里就是对应的根目录,改成你想要输出的地址就好了。ps:这里是相对地址 assetsPublicPath会被引用插入到页面的模版中,这个是你资源的根目录
//seehttp://vuejs-templates.github.io/webpackfordocumentation.
varpath=require('path')
module.exports={
build:{
env:require('./prod.env'),
index:path.resolve(__dirname,'../dist/index.html'),
assetsRoot:path.resolve(__dirname,'../dist'),
assetsSubDirectory:'static',
assetsPublicPath:'../',
productionSourceMap:true,
//Gzipoffbydefaultasmanypopularstatichostssuchas
//SurgeorNetlifyalreadygzipallstaticassetsforyou.
//Beforesettingto`true`,makesureto:
//npminstall--save-devcompression-webpack-plugin
productionGzip:false,
productionGzipExtensions:['js','css']
},
dev:{
env:require('./dev.env'),
port:8080,
assetsSubDirectory:'static',
assetsPublicPath:'/',
proxyTable:{},
//CSSSourcemapsoffbydefaultbecauserelativepathsare"buggy"
//withthisoption,accordingtotheCSS-LoaderREADME
//(https://github.com/webpack/css-loader#sourcemaps)
//Inourexperience,theygenerallyworkasexpected,
//justbeawareofthisissuewhenenablingthisoption.
cssSourceMap:false
}
}
ok,配置结束,一个基本的多页面应用已经成功建成
接下来就进入正题了,放在下一篇来写。。。。。。。
相关文章推荐
- 基于Vue.js的大型报告页项目实现过程及问题总结(二)
- Android 4.0.4系统在线升级实现过程中的一些问题总结
- Cocos2d-x项目过程中遇到的一些问题总结
- 使用mssql2008新特性(存储过程参数类型使用"用户自定义表"来实现批量DML更新多表)解决项目里遇到的性能问题
- 项目开发过程前端开发中遇见的问题总结
- 【项目总结(一)】---视频摘要matlab的程序实现几个问题的总结
- [项目过程中所遇到的各种问题记录]学习篇——对工作以来的学习过的开源项目进行总结—动软代码生成工具
- Unity5.x 项目升级过程中常见问题解决方案总结
- 某教育平台项目开发之--使用SSM框架开发过程遇到的问题总结
- Android项目《Tom伴你行》开发过程中遇到的问题总结
- Apache 部署 Django 项目过程记录与问题总结
- 分布式部署过程中问题总结(EJB实现)
- 项目过程中遇到的问题及小知识点总结
- 【项目总结(一)】---视频摘要matlab的程序实现几个问题的总结
- Touch001项目实现过程中遇到的一个技术问题
- moss开发实施过程中遇到的问题总结:项目层面
- Unity5.x 项目升级过程中常见问题解决方案总结
- [项目过程中所遇到的各种问题记录]学习篇——对工作以来的学习过的开源项目进行总结—DiscuzNt
- 从eclipse导出,Android Studio导入项目过程出现的各种问题总结
- 大型电子政务项目问题总结