一、vue-cli3单页面构建方案一、vue-cli3单页面构建方案一、vue-cli3单页面构建方案1、在目标文件夹内执行
vue ui ; 一个ui版界面,用于创建vue项目;
vue ui ; 一个ui版界面,用于创建vue项目;2、打开router文件夹内的index,看情况配置router的模式,是默认的hash还是history?ps:个人推介history模式,因为内嵌如app的H5页面的话,有可能某些app是不允许页面上带有'#'的,而hash会在url上利用#来做路由转发。ps:history模式在发布到服务器上需要nginx配置一下。详情请自行百度。
const router = new VueRouter({
base: '/',
mode: 'history', //还可设置为'hash'模式
routes
})
const router = new VueRouter({
base: '/',
mode: 'history', //还可设置为'hash'模式
routes
})3、在根目录新建vue.config.js,覆盖webpack配置,将如下内容copy到文件中,作为初始配置
// const webpack = require('webpack')

module.exports = {

lintOnSave: false, // 禁止eslint

devServer: {

open: true, // 构建完成自动打开浏览器

},


configureWebpack: {

plugins: [

// 全局配置node_modules中的模块,使用时无需引入

new webpack.ProvidePlugin({

$: "jquery",

jQuery: "jquery",

"windows.jQuery": "jquery"

})

]


},


// webpack 链接 API,用于生成和修改 webapck 配置

chainWebpack: (config) => {

// 取消 chunks,每个页面只对应一个单独的 JS / CSS

config.optimization.splitChunks({

cacheGroups: {}

});


// config

//
.plugin('webpack-bundle-analyzer')

//
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)

},


pluginOptions: {


}
}
// const webpack = require('webpack')

module.exports = {

lintOnSave: false, // 禁止eslint

devServer: {

open: true, // 构建完成自动打开浏览器

},


configureWebpack: {

plugins: [

// 全局配置node_modules中的模块,使用时无需引入

new webpack.ProvidePlugin({

$: "jquery",

jQuery: "jquery",

"windows.jQuery": "jquery"

})

]


},


// webpack 链接 API,用于生成和修改 webapck 配置

chainWebpack: (config) => {

// 取消 chunks,每个页面只对应一个单独的 JS / CSS

config.optimization.splitChunks({

cacheGroups: {}

});


// config

//
.plugin('webpack-bundle-analyzer')

//
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)

},


pluginOptions: {


}
}4、配置完这些后,npm run serve启动项目,会加载如下两个js
npm run serve
npm run serveapp.js:是所有单页面首次渲染都必须加载的js,内部合并了框架及js(如vue、vue-x、vue-router及非异步组件但引用了的node_modules中的模块),及所有页面公用的模块。about.js:是每个页面独立的js,这个跟router中引用模块的方式有关。具体详解如下:1、
import Home from '../views/Home.vue'
import Home from '../views/Home.vue'这种引用方式引用页面模版组件,就不会出现about.js文件,因为属于同步模块,当前件建的js会被打包进app.js。但是此种随着页面的增多,公用的app.js会越来越大。看情况在app.js大小接受的前提下权衡使用;2、
const routes = [
{

path: '/',

name: 'Home',

// component: Home

component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue') // webpack的魔法注释,将拆分出的js命名为home
},
{

path: '/about',

name: 'About',

// route level code-splitting

// this generates a separate chunk (about.[hash].js) for this route

// which is lazy-loaded when the route is visited.

component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const routes = [
{

path: '/',

name: 'Home',

// component: Home

component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue') // webpack的魔法注释,将拆分出的js命名为home
},
{

path: '/about',

name: 'About',

// route level code-splitting

// this generates a separate chunk (about.[hash].js) for this route

// which is lazy-loaded when the route is visited.

component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]这种引用方式就是异步引用模版组件,不会将当前组建的js打包进app.js,就不会出现1种的问题。因为只要没有加载到对应页面,就不会加载对应页面的js。对应页面的js会最为独立的js单独的动态引入,如同上图的about.js,在进入about页面时才会引入。3、如果在main.js中引入的node_modules包,则会直接打包进app.js,这个逃不掉。ps:最终结论,建议每个页面都异步引用页面模版。5、每个页面如果引了node_mudules就会存在相对应的vendors-home.js,如果没引入node_mudules的话,每个页面按需组件就不会存在vendors-home.js这个文件,如下图:
6、区分本地、测试、线上环境ps:官网提供一种方案,但是需要建立多个环境配置的配置文件,嫌麻烦,就不使用官方的方式,使用如下插件拆分环境:cross-env:https://github.com/kentcdodds/cross-envhttps://github.com/kentcdodds/cross-env
cnpm i cress-env --save-dev // 更改node环境变量插件
cnpm i cress-env --save-dev // 更改node环境变量插件之后在package.json中加入如下三行配置,即可区分本地、测试、线上环境
"scripts": {

"serve": "cross-env NODE_ENV=development vue-cli-service serve",

"test": "cross-env NODE_ENV=test vue-cli-service build",

"build": "cross-env NODE_ENV=production vue-cli-service build"
},
"scripts": {

"serve": "cross-env NODE_ENV=development vue-cli-service serve",

"test": "cross-env NODE_ENV=test vue-cli-service build",

"build": "cross-env NODE_ENV=production vue-cli-service build"
},在vue.config.js中执行如下代码即可打印出当前环境。
console.log(process.env.NODE_ENV)
console.log(process.env.NODE_ENV)在src目录下新建config目录,进入目录,新建gateway.config.js文件用于配置不同环境接口host,代码如下:gateway.config.js文件内容如下:
// 开发环境地址(npm run serve)
const devHost = {
// 接口地址域名相关
baseApi: 'https://abc.com',

}

// 测试环境地址(npm run test)
const testHost = {
// 接口地址域名相关
baseApi: 'https://abc.com',

}

// 线上环境地址(npm run build)
const proHost = {
// 接口地址域名相关
baseApi: 'https://abc1.com',

}

// 区分环境选择静态资源地址
const env = process.env.NODE_ENV

let exportConfig = ''
if (env === 'production') {
exportConfig = proHost
} else if (env === 'test') {
exportConfig = testHost
} else {
exportConfig = devHost
}

export default exportConfig
// 开发环境地址(npm run serve)
const devHost = {
// 接口地址域名相关
baseApi: 'https://abc.com',

}

// 测试环境地址(npm run test)
const testHost = {
// 接口地址域名相关
baseApi: 'https://abc.com',

}

// 线上环境地址(npm run build)
const proHost = {
// 接口地址域名相关
baseApi: 'https://abc1.com',

}

// 区分环境选择静态资源地址
const env = process.env.NODE_ENV

let exportConfig = ''
if (env === 'production') {
exportConfig = proHost
} else if (env === 'test') {
exportConfig = testHost
} else {
exportConfig = devHost
}

export default exportConfig结束:之后只需要在接口api的js文件中引入此文件即可。发布时区分环境打包。7、浅谈项目引入第三方插件方案ps:原则:移动端单个js大小不超过200k;pc端单个js不超过400k;1.vue模块化引入node_modules包插件:前提,各个页面都是异步加载,这样的好处是单个页面的js不会被打包进公共app.js中。之后在单个js中引入第三方库。但是据测试:这种模块化引入第三方插件,比cdn模式引入的js体积至少要大2呗,因为webpack内部对每个第三方库进行了二次处理,会增大js体积。权衡js大小使用。2.cdn模式引入第三方插件:提供这种方式,是因为有些库是不支持vue的,只支持cdn模式引入,而且比较轻量级,可以选择这种方案,异步cdn模式引入第三方插件,这些方式最下方脚手架示例中都有demo;8、项目中常用的打包插件及第三方库1.vue https://cn.vuejs.org
2.vue-router https://router.vuejs.org
3.vue-x https://vuex.vuejs.org
4.sass https://www.sass.hk
5.axios http://www.axios-js.com/
6.normalize.css http://necolas.github.io/normalize.css/
7.n-zepto https://npm.taobao.org/package/n-zepto
8.webpack-bundle-analyzer https://github.com/webpack-contrib/webpack-bundle-analyzer
https://cn.vuejs.orghttps://router.vuejs.orghttps://vuex.vuejs.orghttps://www.sass.hkhttp://www.axios-js.com/http://necolas.github.io/normalize.css/https://npm.taobao.org/package/n-zeptohttps://github.com/webpack-contrib/webpack-bundle-analyzer下方是vue-cli3内置插件(直接在vue.config.js中配置):
如下插件可参考vue-cli3官网配置方法:
https://cli.vuejs.org/zh/config/#css-sourcemaphttps://cli.vuejs.org/zh/config/#css-sourcemap9.autoprefixer:自动添加浏览器前缀。(如:-webkit-等)
10.url-loader:改变静态资源引用路径
11.ProvidePlugin:全局配置node_modules中的模块
具体配置方法如下(比较全的vue.config.js配置):
const webpack = require('webpack')

const processEnv = process.env.VUE_APP_ENV; // 区分环境(值:production、development、test)
const isPro = processEnv === 'production'; // 判断production环境

const outputDir = 'dist'; // 输出文件目录(默认dist)
const assetsDir = ''; // 配置放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录

// 区分环境选择cdn地址
let publicPath = '' // 静态资源引用路径
let fontPublicPath = '' // 字体图标引用的cdn路径
let imgPublicPath = '' // css引用图片的cdn路径(c2c/static/img)
if (processEnv === 'production') {

publicPath = 'https://abc.com/c2c/shop' // 正式环境静态资源css、js等cdn路径

fontPublicPath = `https://abc.com/c2c/shop/${assetsDir ? assetsDir + '/' : '/'}fonts` // 正式环境字体图标引用的cdn路径

imgPublicPath = `https://abc.com/c2c/shop/${assetsDir ? assetsDir + '/' : '/'}/img` // 正式环境css引用图片的cdn路径
} else if (processEnv === 'test') {

// publicPath = './' // 正式环境静态资源css、js等cdn路径

publicPath = 'https://bcd.com/c2c/shop/dist' // 测试环境静态资源css、js等cdn路径

fontPublicPath = ''

imgPublicPath = ''
} else {

publicPath = '/'

fontPublicPath = ''

imgPublicPath = ''
}

const devServerHost = 'localhost';
const devServerPort = '8080'; // 端口号
const devServerOpen = true; // 热启动后自动打开浏览器

module.exports = {


// 配置生成dist里面static的cdn资源路径(测试环境为./,正式环境走cdn路径)

publicPath: publicPath,


// 输出文件目录(默认dist)

outputDir,


// 配置放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录

assetsDir,


devServer: {

host: devServerHost,

port: devServerPort,

open: devServerOpen, // 构建完成自动打开浏览器



// eslint检测影响代码编译,注释调不会影响代码编译

// overlay: {

//
warnings: true,

//
errors: true

// }

},

lintOnSave: processEnv === 'development' ? true : false, // 开发环境开启eslint,测试和线上编辑代码禁止eslint


// webpack 配置,键值对象时会合并配置,为方法时会改写配置

configureWebpack: config => {

// 扩展资源,不将部分资源js等打入包内引用cdn资源

let externals = {

// 'swiper': 'Swiper',

};

config.externals = externals;


//警告 webpack 的性能提示

config.performance = {

hints: isPro ? 'warning' : false, // 本地开发不显示警告

// 入口起点的最大体积

maxEntrypointSize: 512000, // 500kib

// 生成文件的最大体积

maxAssetSize: 307200, // 300kib

// 只给出 js 文件的性能提示

assetFilter(assetFilename) {

return assetFilename.endsWith('.js');

}

};

},


// webpack 链接 API,用于生成和修改 webapck 配置

chainWebpack: (config) => {

// 取消 chunks,每个页面只对应一个单独的 JS / CSS

config.optimization.splitChunks({

cacheGroups: {}

});


// 全局配置node_modules中的模块,使用时无需引入

config.plugin('provide').use(webpack.ProvidePlugin, [{

$: "n-zepto",

Zepto: "n-zepto",

"window.Zepto": "n-zepto"

}]);


config.module

.rule('images')

.use('url-loader')

.loader('url-loader')

.tap(options => Object.assign(options, {

limit: 10240, // 小于10k,压缩图片 => base64

// limit: 3000,

publicPath: imgPublicPath,

name: `[name].[hash:8].[ext]`

}))


// 设置fonts字体文件引用的路径

config.module

.rule('fonts')

.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)

.use('url-loader')

.loader('file-loader')

.tap(options => Object.assign(options, {

limit: 5000,

publicPath: fontPublicPath,

name: '[name].[hash:8].[ext]'

}))



// npm run report;打印app.js的模块报告,查看各个模块;

if (processEnv === 'report') {

config

.plugin('webpack-bundle-analyzer')

.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)

}


},


// css配置处理

css: {

// 是否使用css分离插件 ExtractTextPlugin;true:页面css独立分割,false:页面css同一打包;

extract: true,

// 开启 CSS source maps(默认false)线上关闭,测试和本地开启

sourceMap: isPro ? false : true,

// css预设器配置项

loaderOptions: {

sass: {

// sass的公共方法和变量,需要预编译;

prependData: `

@import "@/assets/css/global.scss";

@import "@/assets/css/func.scss";

`

},

postcss: {

plugins: [

// 浏览器自动加前缀

require('autoprefixer')({

overrideBrowserslist: [

"Android 4.0",

"iOS 7",

"Chrome > 31",

"ff > 31",

"ie >= 8"

]

}),

]

}


},

// 启用 CSS modules for all css / pre-processor files.

requireModuleExtension: false

},


// 构建时开启多进程处理 babel 编译

parallel: require('os').cpus().length > 1,


pwa: {

iconPaths: {

favicon32: 'favicon.ico',

favicon16: 'favicon.ico',

appleTouchIcon: 'favicon.ico',

maskIcon: 'favicon.ico',

msTileImage: 'favicon.ico'

},


},


// 第三方插件配置

pluginOptions: {

// ...

}
}
const webpack = require('webpack')

const processEnv = process.env.VUE_APP_ENV; // 区分环境(值:production、development、test)
const isPro = processEnv === 'production'; // 判断production环境

const outputDir = 'dist'; // 输出文件目录(默认dist)
const assetsDir = ''; // 配置放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录

// 区分环境选择cdn地址
let publicPath = '' // 静态资源引用路径
let fontPublicPath = '' // 字体图标引用的cdn路径
let imgPublicPath = '' // css引用图片的cdn路径(c2c/static/img)
if (processEnv === 'production') {

publicPath = 'https://abc.com/c2c/shop' // 正式环境静态资源css、js等cdn路径

fontPublicPath = `https://abc.com/c2c/shop/${assetsDir ? assetsDir + '/' : '/'}fonts` // 正式环境字体图标引用的cdn路径

imgPublicPath = `https://abc.com/c2c/shop/${assetsDir ? assetsDir + '/' : '/'}/img` // 正式环境css引用图片的cdn路径
} else if (processEnv === 'test') {

// publicPath = './' // 正式环境静态资源css、js等cdn路径

publicPath = 'https://bcd.com/c2c/shop/dist' // 测试环境静态资源css、js等cdn路径

fontPublicPath = ''

imgPublicPath = ''
} else {

publicPath = '/'

fontPublicPath = ''

imgPublicPath = ''
}

const devServerHost = 'localhost';
const devServerPort = '8080'; // 端口号
const devServerOpen = true; // 热启动后自动打开浏览器

module.exports = {


// 配置生成dist里面static的cdn资源路径(测试环境为./,正式环境走cdn路径)

publicPath: publicPath,


// 输出文件目录(默认dist)

outputDir,


// 配置放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录

assetsDir,


devServer: {

host: devServerHost,

port: devServerPort,

open: devServerOpen, // 构建完成自动打开浏览器



// eslint检测影响代码编译,注释调不会影响代码编译

// overlay: {

//
warnings: true,

//
errors: true

// }

},

lintOnSave: processEnv === 'development' ? true : false, // 开发环境开启eslint,测试和线上编辑代码禁止eslint


// webpack 配置,键值对象时会合并配置,为方法时会改写配置

configureWebpack: config => {

// 扩展资源,不将部分资源js等打入包内引用cdn资源

let externals = {

// 'swiper': 'Swiper',

};

config.externals = externals;


//警告 webpack 的性能提示

config.performance = {

hints: isPro ? 'warning' : false, // 本地开发不显示警告

// 入口起点的最大体积

maxEntrypointSize: 512000, // 500kib

// 生成文件的最大体积

maxAssetSize: 307200, // 300kib

// 只给出 js 文件的性能提示

assetFilter(assetFilename) {

return assetFilename.endsWith('.js');

}

};

},


// webpack 链接 API,用于生成和修改 webapck 配置

chainWebpack: (config) => {

// 取消 chunks,每个页面只对应一个单独的 JS / CSS

config.optimization.splitChunks({

cacheGroups: {}

});


// 全局配置node_modules中的模块,使用时无需引入

config.plugin('provide').use(webpack.ProvidePlugin, [{

$: "n-zepto",

Zepto: "n-zepto",

"window.Zepto": "n-zepto"

}]);


config.module

.rule('images')

.use('url-loader')

.loader('url-loader')

.tap(options => Object.assign(options, {

limit: 10240, // 小于10k,压缩图片 => base64

// limit: 3000,

publicPath: imgPublicPath,

name: `[name].[hash:8].[ext]`

}))


// 设置fonts字体文件引用的路径

config.module

.rule('fonts')

.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)

.use('url-loader')

.loader('file-loader')

.tap(options => Object.assign(options, {

limit: 5000,

publicPath: fontPublicPath,

name: '[name].[hash:8].[ext]'

}))



// npm run report;打印app.js的模块报告,查看各个模块;

if (processEnv === 'report') {

config

.plugin('webpack-bundle-analyzer')

.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)

}


},


// css配置处理

css: {

// 是否使用css分离插件 ExtractTextPlugin;true:页面css独立分割,false:页面css同一打包;

extract: true,

// 开启 CSS source maps(默认false)线上关闭,测试和本地开启

sourceMap: isPro ? false : true,

// css预设器配置项

loaderOptions: {

sass: {

// sass的公共方法和变量,需要预编译;

prependData: `

@import "@/assets/css/global.scss";

@import "@/assets/css/func.scss";

`

},

postcss: {

plugins: [

// 浏览器自动加前缀

require('autoprefixer')({

overrideBrowserslist: [

"Android 4.0",

"iOS 7",

"Chrome > 31",

"ff > 31",

"ie >= 8"

]

}),

]

}


},

// 启用 CSS modules for all css / pre-processor files.

requireModuleExtension: false

},


// 构建时开启多进程处理 babel 编译

parallel: require('os').cpus().length > 1,


pwa: {

iconPaths: {

favicon32: 'favicon.ico',

favicon16: 'favicon.ico',

appleTouchIcon: 'favicon.ico',

maskIcon: 'favicon.ico',

msTileImage: 'favicon.ico'

},


},


// 第三方插件配置

pluginOptions: {

// ...

}
}9、一个基础配置较为完善的基于vue-cli3的单页面项目方案脚手架:
项目脚手架集合project-init
其中的cli-start-spa文件夹,内部readme有项目细节。项目脚手架集合project-init