Vue-cli4 has been upgraded, click me to view
Based on vue-cli3.0 to build a fully functional mobile terminal shelf, the main functions include
- webpack package extension
- css: sass support, normalize.css, _mixin.scss, _variables.scss
- vw, rem layout
- Cross-domain settings
- eslint settings
- cdn introduced
- Routing design, login interception
- axios, api design
- Vuex state management
Project address: vue-cli3-H5
Demo address: zhouyupeng.github.io/vuecli3H5/#...
webpack package extension
After vue-cli3.*, the directory structure has been greatly changed, and the previous build and config folders have been removed. To achieve configuration changes, add vue.config.js to the root directory for configuration
css: sass support, normalize.css, _mixin.scss, _variables.scss
The css preprocessor used is sass. For css mixin, variables are introduced globally, and normalize.css is introduced to make the style of HTML elements appear to be highly consistent across browsers. vue.config.js configuration
css: {
// css ExtractTextPlugin
extract:isProduction ? true:false,
// CSS source maps?
sourceMap: false,
//css
// CSS modules for all css/pre-processor files.
modules: false,
sass: {
data: '@import "style/_mixin.scss";@import "style/_variables.scss";'//
}
}
}
vw, rem layout
For the mobile terminal adaptation scheme, the NetEase News method is used, using the vw + rem layout
/**
750px
1rem=100px html width: 7.5rem html font-size=deviceWidth/7.5
**/
html {
font-size: 13.33333vw
}
@media screen and (max-width: 320px) {
html {
font-size: 42.667PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 321px) and (max-width:360px) {
html {
font-size: 48PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 361px) and (max-width:375px) {
html {
font-size: 50PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 376px) and (max-width:393px) {
html {
font-size: 52.4PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 394px) and (max-width:412px) {
html {
font-size: 54.93PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 413px) and (max-width:414px) {
html {
font-size: 55.2PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 415px) and (max-width:480px) {
html {
font-size: 64PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 481px) and (max-width:540px) {
html {
font-size: 72PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 541px) and (max-width:640px) {
html {
font-size: 85.33PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 641px) and (max-width:720px) {
html {
font-size: 96PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 721px) and (max-width:768px) {
html {
font-size: 102.4PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 769px) {
html {
font-size: 102.4PX;
font-size: 13.33333vw
}
}
@media screen and (min-width: 769px) {
html {
font-size: 102.4PX;
#app {
margin: 0 auto
}
}
}
vue.config.js configuration
loaderOptions: {
postcss: {
// rem
plugins: [
require('postcss-px2rem')({
remUnit: 100
})
]
}
}
Cross-domain settings during development
devServer: {
open: true,//
host: '127.0.0.1',
port: 8088,//
https: false,
hotOnly: false,
proxy: 'https://easy-mock.com/'//
}
After configuration, the baseUrl of axios of the local development environment should be written as'', which is an empty string. When publishing online, if the front-end code is not placed under the same source as the back- end api , the back-end needs to do cross-domain processing.
eslint standard setting
The JavaScript standard code specification is used. A good coding style can help reduce friction between teams, and the code will be more refreshing to read and more readable. Don't feel annoying, just say it if you use it. This is the full text of the JavaScript standard code specification
Custom configuration, modify in .eslintrc.js, here is the configuration I gave, 4 spaces indented, do not check the ending semicolon, close the single var statement, you can configure it yourself
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
indent: [
'error',
4,
{
SwitchCase: 1
}
],
semi: 0,// ,
//
quotes: ['error', 'single'],
//
'space-before-function-paren': 0,
// var
'one-var': 0
}
cdn introduced
For vue, vue-router, vuex, axios and other libraries that are not frequently changed, we let webpack not package them. By introducing cdn, the code size can be reduced, and the bandwidth of the server can also be reduced. The 360 cdn is used here. , accompanied by a public review article cdn point I
vue.config.js configuration
const externals = {
vue: 'Vue',
'vue-router': 'VueRouter',
vuex: 'Vuex',
'mint-ui': 'MINT',
axios: 'axios'
}
const cdn = {
//
dev: {
css: [
'https://lib.baomitu.com/mint-ui/2.2.13/style.min.css'
],
js: []
},
//
build: {
css: [
'https://lib.baomitu.com/mint-ui/2.2.13/style.min.css'
],
js: [
'https://lib.baomitu.com/vue/2.6.6/vue.min.js',
'https://lib.baomitu.com/vue-router/3.0.1/vue-router.min.js',
'https://lib.baomitu.com/vuex/3.0.1/vuex.min.js',
'https://lib.baomitu.com/axios/0.18.0/axios.min.js',
'https://lib.baomitu.com/mint-ui/2.2.13/index.js'
]
}
}
configureWebpack: config => {
if (isProduction) {
//externals
Object.assign(config, {
externals: externals
})
} else {
// ...
}
},
chainWebpack: config => {
// vue-cli webpack
// CDN htmlWebpackPlugin public/index.html
config.plugin('html').tap(args => {
if (process.env.NODE_ENV === 'production') {
args[0].cdn = cdn.build
}
if (process.env.NODE_ENV === 'development') {
args[0].cdn = cdn.dev
}
return args
})
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<!-- DNS -->
<link rel="dns-prefetch" href="//lib.baomitu.com"/>
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=0,minimal-ui,viewport-fit=cover"/>
<link rel="icon" href="<%= BASE_URL %>favicon.ico"/>
<!-- CDN CSS vue.config.js -->
<% for (var i in
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
<link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style"/>
<link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet"/>
<% } %>
<title>vuedemo</title>
</head>
<body>
<noscript>
<strong>We're sorry but vuedemo doesn't work properly without JavaScript
enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- CDN JS vue.config.js -->
<% for (var i in
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
<!-- built files will be auto injected -->
</body>
</html>
Routing design, login interception
const router = new Router({
routes: [
{
path: '/',
name: 'home',
component: Home,
meta: {
auth: false,//
keepAlive: true//
}
},
{
path: '/about',
name: 'about',
component: () =>
import(/* webpackChunkName: "about" */'./views/About.vue'),
meta: {
auth: true,
keepAlive: true
}
},
{
path: '/login',
name: 'login',
component: () =>
import(/* webpackChunkName: "login" */'./views/login.vue'),
meta: {
auth: false,
keepAlive: true
}
},
{
path: '*',//
redirect: '/',
meta: {
//auth: true,
//keepAlive: true
}
}
]
})
//
router.beforeEach((to, from, next) => {
let auth = to.meta.auth
let token = store.getters['login/token'];
if (auth) {//
if (token) {
next()
} else {
next({
path: '/login',
query: {
redirect: to.fullPath
}
})
}
} else {
next()
}
})
Set whether you need to log in and whether to cache the current component in the meta. The login permission is judged in the router.beforeEac routing hook function. If there is no login, jump to the login page, and pass the current page to the past, and then jump back to this page after logging in.
The page cache is processed in app.vue
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
axios, api design
The design of axios is mainly request interceptor, respone interceptor, and secondary encapsulation of get and post
axios.defaults.timeout = 12000//
axios.defaults.baseURL = process.env.VUE_APP_BASE_API
axios.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded;charset=UTF-8'//post
//axios
axios.interceptors.request.use(
config => {
// token
let token = store.getters['login/token'];
token && (config.headers.token = token)
Indicator.open(' ')
return config
},
error => {
return Promise.error(error)
}
)
//axios respone
axios.interceptors.response.use(
response => {
// 200
// respone
Indicator.close()
if (response.status === 200 && response.data.code === 0) {
return Promise.resolve(response)
} else {
Toast({
message: response.data.msg,
position: 'middle',
duration: 2000
});
return Promise.reject(response)
}
},
error => {
Indicator.close()
const responseCode = error.response.status
switch (responseCode) {
//401
case 401:
break
//404
case 404:
Toast({
message: ' ',
position: 'middle',
duration: 2000
});
break
default:
Toast({
message: error.response.data.message,
position: 'middle',
duration: 2000
});
}
return Promise.reject(error.response)
}
)
/**
* get get
* @param {String} url [ url ]
* @param {Object} params [ ]
*/
function get (url, params = {}) {
return new Promise((resolve, reject) => {
axios
.get(url, {
params: params
})
.then(res => {
resolve(res.data)
})
.catch(err => {
reject(err.data)
})
})
// return axios.get();
}
/**
* post post
* @param {String} url [ url ]
* @param {Object} params [ ]
*/
function post (url, params) {
return new Promise((resolve, reject) => {
axios
.post(url, qs.stringify(params))
.then(res => {
resolve(res.data)
})
.catch(err => {
reject(err.data)
})
})
// return axios.post();
}
In order to facilitate the management of the api path, all requests are placed in the api folder, such as
import { get, post } from '@/axios/http.js'
function getIndex (params) {
return get('/mock/5cb48c7ed491cd741c54456f/base/index', params)
}
function login(params) {
return post('/mock/5cb48c7ed491cd741c54456f/base/login', params)
}
export {
getIndex,
login
}
other
Remove console.log
Install the uglifyjs-webpack-plugin plugin
// console
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
drop_console: true,
drop_debugger: false,
pure_funcs: ['console.log']// console
}
},
sourceMap: false,
parallel: true
})
)
Set alias directory alias
Files in various places are often quoted in the project, and it can be more convenient to import after configuration
config.resolve.alias
.set('assets', '@/assets')
.set('components', '@/components')
.set('view', '@/view')
.set('style', '@/style')
.set('api', '@/api')
.set('store', '@/store')
Environment variables and patterns
In the front-end development process of a product, generally speaking, it will undergo local development, test scripts, development self-test, test environment, and pre-launch environment before it can be officially released. Corresponding to each environment may be different, such as server address, interface address, websorket address... etc. When switching between environments, different configuration parameters are needed, so environment variables and modes can be used to facilitate our management.
.env #
.env.local # git
.env.[mode] #
.env.[mode].local # git
At the beginning of the custom variable VUE_APP_, there are two special variables:
- NODE_ENV-will be one of "development", "production" or "test". The specific value depends on the mode in which the application is running.
- BASE_URL-will match the baseUrl option in vue.config.js, which is the base path to which your application will be deployed.
As we defined .env
NODE_ENV = 'development'
BASE_URL = '/'
VUE_APP_BASE_API = ''
.env.production
NODE_ENV = 'production'
BASE_URL = './'
VUE_APP_BASE_API = 'https://easy-mock.com/'
In the project, you can use process.env.VUE_APP_*, such as process.env.VUE_APP_BASE_API to get the defined value
Import filter globally
Write the filters used in multiple places in one js, and reuse the code.
//
const formatTimer = function(val, hours) {
if (val) {
var dateTimer = new Date(val * 1000)
var y = dateTimer.getFullYear()
var M = dateTimer.getMonth() + 1
var d = dateTimer.getDate()
var h = dateTimer.getHours()
var m = dateTimer.getMinutes()
M = M >= 10 ? M : '0' + M
d = d >= 10 ? d : '0' + d
h = h >= 10 ? h : '0' + h
m = m >= 10 ? m : '0' + m
if (hours) {
return y + '-' + M + '-' + d + ' ' + h + ':' + m
} else {
return y + '-' + M + '-' + d
}
}
}
export default {
formatTimer
}
main.js introduction
import filters from './filters/index'
//
Object.keys(filters).forEach(item => {
Vue.filter(item, filters[item])
})
use
{{1555851774 | formatTimer()}}
Use mock.js in vue
To view the articles I wrote before, click on me
Wepback's visual resource analysis tool plug-in---webpack-bundle-analyzer
Used to analyze which modules introduce which codes, and optimize the code purposefully
In the packaging environment, use the command npm run build --report
if (process.env.npm_config_report) {
config.plugins.push(new BundleAnalyzerPlugin())
}
Code address
Project address: vue-cli3-H5
Demo address: zhouyupeng.github.io/vuecli3H5/#...