Project address vuE-CLI3-project welcome star

The original address www.ccode.live/lentoo/list…

1. Create a VUE project

Most of you already know how to create projects, so you can skip this section and move on to the next.

1.1 installation @ vue/cli

# Global install VUE-CLI scaffolding
npm install -g @vue/cli
Copy the code

Wait until the installation is complete to start the next step

1.2 Initializing the Project

vue create vue-cli3-project
Copy the code
  1. Select a preset

babel
eslint

We chose Manually select features

Press Enter to select the plug-in

  1. Plug-in option

Babel, Router, Vuex, Css preprocessor, Linter/Formatter check, Unit test framework

  1. Routing Mode selection

Whether to use routing in History mode (Yes)

  1. Select a CSS preprocessor (Sass/SCSS)

  1. Select an ESLint configuration

ESLint + Standard Config. I prefer this code specification

  1. When will the selection take placeeslintcheck

The option (Lint on save) to save is to check

If you are using the vscode editor, you can configure the eslint plugin for automatic code formatting

  1. Do you want to save the default configuration? (y)

If yes, the next time you create a VUE project, you can use this default file directly without having to configure it.

Wait for dependencies to complete

2. Automatically register global components

Create a global directory under the Components directory to place components that need to be registered globally.

Index.js simply imports main.vue and exports the component object

components
index.js

// components/index.js
import Vue from 'vue'

// Automatically loads.js files in the global directory
const componentsContext = require.context('./global'.true, /\.js$/)

componentsContext.keys().forEach(component= > {
  const componentConfig = componentsContext(component)
  /** * compatible with import export and require module.export */
  const ctrl = componentConfig.default || componentConfig
  Vue.component(ctrl.name, ctrl)
})
Copy the code

Finally, import the index.js file from main.js

3. Routes are imported automatically

To add a new page, you need to configure the information for that page in the Routing configuration.

How do we make routing cleaner if we have more and more pages?

3.1 Splitting routes

Split routes based on service modules

Export an array of routing configurations in each submodule

Import all submodules in the root index.js

3.2 Automatically Scan for submodule routes and import them

As our business grew bigger and bigger, every time we added a new business module, we would add a new sub-routing module under the route and import it in index.js.

So how do you simplify this operation?

With the auto-scan global component registration above, we can also automatically scan submodule routes and import them

4. Use Node to generate components

As a front-end developer, wouldn’t it be a waste to have something so good in Node if it didn’t work?

.vue
template
script
style
index.js

So can we use Node to help us do this? Just tell Node the name of the component it generated for me. Let Node do the rest

4.1 Generate components from Node

  • Install thechalkThis plugin can make our console output statements color-coded
npm install chalk --save-dev
Copy the code

Create a scripts folder in the root directory,

Add a new generatecomponent.js file to place the code that generated the component,

Add a template.js file that holds the code for the component template

  • template.js
// template.js
module.exports = {
  vueTemplate: compoenntName= > {
    return `<template>
  <div class="${compoenntName}">
    ${compoenntName}Component </div> </template> <script> export default {name: '${compoenntName}'
}
</script>
<style lang="scss" scoped>
.${compoenntName} {

}
</style>
`
  },
  entryTemplate: `import Main from './main.vue'
export default Main`
}

Copy the code
  • generateComponent.js`
// generateComponent.js`
const chalk = require('chalk')
const path = require('path')
const fs = require('fs')
const resolve = (. file) = >path.resolve(__dirname, ... file)const log = message= > console.log(chalk.green(`${message}`))
const successLog = message= > console.log(chalk.blue(`${message}`))
const errorLog = error= > console.log(chalk.red(`${error}`))
const { vueTemplate, entryTemplate } = require('./template')

const generateFile = (path, data) = > {
  if (fs.existsSync(path)) {
    errorLog(`${path}The file already exists)
    return
  }
  return new Promise((resolve, reject) = > {
    fs.writeFile(path, data, 'utf8', err => {
      if (err) {
        errorLog(err.message)
        reject(err)
      } else {
        resolve(true)
      }
    })
  })
}
log('Please enter the name of the component to build. If you want to build global components, prefix global/.')
let componentName = ' '
process.stdin.on('data'.async chunk => {
  const inputName = String(chunk).trim().toString()
  /** * Component directory path */
  const componentDirectory = resolve('.. /src/components', inputName)

  /** * Vue component path */
  const componentVueName = resolve(componentDirectory, 'main.vue')
  /** * entry file path */
  const entryComponentName = resolve(componentDirectory, 'index.js')
  
  const hasComponentDirectory = fs.existsSync(componentDirectory)
  if (hasComponentDirectory) {
    errorLog(`${inputName}The component directory already exists, please re-enter ')
    return
  } else {
    log(The Component directory is being generated${componentDirectory}`)
    await dotExistDirectoryCreate(componentDirectory)
    // fs.mkdirSync(componentDirectory);
  }
  try {
    if (inputName.includes('/')) {
      const inputArr = inputName.split('/')
      componentName = inputArr[inputArr.length - 1]}else {
      componentName = inputName
    }
    log('Creating vUE files${componentVueName}`)
    await generateFile(componentVueName, vueTemplate(componentName))
    log('An Entry file is being generated${entryComponentName}`)
    await generateFile(entryComponentName, entryTemplate)
    successLog('Generated successfully')}catch (e) {
    errorLog(e.message)
  }

  process.stdin.emit('end')
})
process.stdin.on('end', () => {
  log('exit')
  process.exit()
})
function dotExistDirectoryCreate (directory) {
  return new Promise((resolve) = > {
    mkdirs(directory, function () {
      resolve(true)})})}// Create a directory recursively
function mkdirs (directory, callback) {
  var exists = fs.existsSync(directory)
  if (exists) {
    callback()
  } else {
    mkdirs(path.dirname(directory), function () {
      fs.mkdirSync(directory)
      callback()
    })
  }
}

Copy the code
  • Configuration package. Json
"new:comp": "node ./scripts/generateComponent"
Copy the code
  • perform

NPM run new:comp

If yarn is used, it is yarn new:comp

4.2 Generate page components from Node

Now that we can generate components from Node, we can also generate page components from the same logic. You only need to modify the logic that generates the component code slightly. Create a new generateView.js file in the scripts directory

// generateView.js
const chalk = require('chalk')
const path = require('path')
const fs = require('fs')
const resolve = (. file) = >path.resolve(__dirname, ... file)const log = message= > console.log(chalk.green(`${message}`))
const successLog = message= > console.log(chalk.blue(`${message}`))
const errorLog = error= > console.log(chalk.red(`${error}`))
const { vueTemplate } = require('./template')

const generateFile = (path, data) = > {
  if (fs.existsSync(path)) {
    errorLog(`${path}The file already exists)
    return
  }
  return new Promise((resolve, reject) = > {
    fs.writeFile(path, data, 'utf8', err => {
      if (err) {
        errorLog(err.message)
        reject(err)
      } else {
        resolve(true)
      }
    })
  })
}
log('Please enter the name of the page component to be generated, it will be generated in the views/ directory')
let componentName = ' '
process.stdin.on('data'.async chunk => {
  const inputName = String(chunk).trim().toString()
  /** * Vue page component path */
  let componentVueName = resolve('.. /src/views', inputName)
  // If it does not end with.vue, it is automatically added
  if(! componentVueName.endsWith('.vue')) {
    componentVueName += '.vue'
  }
  /** * Vue component directory path */
  const componentDirectory = path.dirname(componentVueName)

  const hasComponentExists = fs.existsSync(componentVueName)
  if (hasComponentExists) {
    errorLog(`${inputName}The page component already exists, please re-enter ')
    return
  } else {
    log(The Component directory is being generated${componentDirectory}`)
    await dotExistDirectoryCreate(componentDirectory)
  }
  try {
    if (inputName.includes('/')) {
      const inputArr = inputName.split('/')
      componentName = inputArr[inputArr.length - 1]}else {
      componentName = inputName
    }
    log('Creating vUE files${componentVueName}`)
    await generateFile(componentVueName, vueTemplate(componentName))
    successLog('Generated successfully')}catch (e) {
    errorLog(e.message)
  }

  process.stdin.emit('end')
})
process.stdin.on('end', () => {
  log('exit')
  process.exit()
})
function dotExistDirectoryCreate (directory) {
  return new Promise((resolve) = > {
    mkdirs(directory, function () {
      resolve(true)})})}// Create a directory recursively
function mkdirs (directory, callback) {
  var exists = fs.existsSync(directory)
  if (exists) {
    callback()
  } else {
    mkdirs(path.dirname(directory), function () {
      fs.mkdirSync(directory)
      callback()
    })
  }
}
Copy the code
  • Configure package.json to add onescriptsThe script
"new:view": "node ./scripts/generateView"
Copy the code
  • perform

NPM run new: View if NPM is used

If yarn is used, it is yarn new:view

5. Axios encapsulation

  • Install axios
npm install axios --save
// or
yarn add axios
Copy the code

5.1 Configuring Different Environments

Create three new environment variable files in the root directory

dev
dev
test
test

# // .env
NODE_ENV = "development"
BASE_URL = "https://easy-mock.com/mock/5c4c50b9888ef15de01bec2c/api"
Copy the code

Then create a new vue.config.js in the root directory

// vue.config.js module.exports = { chainWebpack: Config => {// Here is the environment configuration, different environment corresponding to different BASE_URL, so that the AXIOS request address is different config.plugin('define').tap(args => {
      args[0]['process.env'].BASE_URL = JSON.stringify(process.env.BASE_URL)
      return args
    })
  }
}
Copy the code

Then create an API folder in the SRC directory and create an index.js to configure axios configuration information

// src/api/index.js import axios from 'axios' import router from '.. /router' import {Message} from 'elemental-ui' const service = axios.create({// set timeout: 60000, baseURL: Process.env.base_url}) // For post requests, we need a request header, so we can do a default setting here // that is, set the post request header to application/x-www-form-urlencoded; charset=UTF-8 service.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'' export default serviceCopy the code

5.2 Request response Encapsulation

import axios from 'axios' import router from '.. /router' import {Message} from 'elemental-ui' const service = axios.create({// set timeout: 60000, baseURL: Process. The env. BASE_URL})/intercept * before * * * request for processing needs to * before the request operation/service. The interceptors. Request. Use (config = > {const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = token } return config }, (error) => {return promise.reject (error)}) /** * Request response interception * is used to process operations that need to be performed after the request is returned */ Service. The interceptors. Response. Use (response = > {const responseCode = response. The status / / if the returned a status code of 200, shows that interface request is successful, If (responseCode === 200) {return promise. resolve(response)} else {return Promise.reject(response)}}, error => {// the server returns something that does not start with 2, Const responseCode = error.response.status switch (responseCode) {// 401: not logged in case 401: / / jump to login page of the router. The replace ({path: '/ login, query: {redirect: router. CurrentRoute. FullPath}}) break / / 403: Token expired case 403: // Error Message Message({type: 'error', Message: }) // Clear token localstorage. removeItem('token') // redirect to the login page and pass the fullPath of the page to be accessed, SetTimeout (() => {router.replace({path: '/login', query: {redirect: The router. CurrentRoute. FullPath}})}, 1000) break / / 404 request there is no case 404: Message ({Message: 'there is no network request, type: 'error'}) break / / other errors, directly thrown error default: Message ({Message: error. The response. The data. The Message, type: 'error' }) } return Promise.reject(error) }) export default serviceCopy the code

The Message method is a Message prompt component provided by Element-UI that you can replace with your own Message prompt component

5.3 Handling Network Disconnection

Add processing logic to response interception

service.interceptors.response.use(response= > {
  const responseCode = response.status
  // If the returned status code is 200, the interface request succeeds and data can be obtained normally
  // Otherwise, an error is thrown
  if (responseCode === 200) {
    return Promise.resolve(response.data)
  } else {
    return Promise.reject(response)
  }
}, error => {
  // The network is disconnected or the request times out
  if(! error.response) {// Request timeout status
    if (error.message.includes('timeout')) {
      console.log('Out of time')
      Message.error('Request timed out. Please check network connection.')}else {
      // You can display the disconnected component
      console.log('Disconnected')
      Message.error('Request failed, please check network connection')}return
  }
  // Omit other code
  return Promise.reject(error)
})
Copy the code

5.4 Uploading Encapsulated Images

// src/api/index.js
export const uploadFile = formData= > {
  const res = service.request({
    method: 'post'.url: '/upload'.data: formData,
    headers: { 'Content-Type': 'multipart/form-data'}})return res
}
Copy the code

call

async uploadFile (e) {
  const file = document.getElementById('file').files[0]
  const formdata = new FormData()
  formdata.append('file', file)
  await uploadFile(formdata)
}
Copy the code

5.5 Requesting to Display the Loading Effect

let loading = null
service.interceptors.request.use(config= > {
  // Display the load box before the request
  loading = Loading.service({
    text: 'Loading...... '
  })
  // Omit other code
  return config
}, (error) => {
  return Promise.reject(error)
})
service.interceptors.response.use(response= > {
  // Close the load box after requesting a response
  if (loading) {
    loading.close()
  }
 // Omit other code
}, error => {
  // Close the load box after requesting a response
  if (loading) {
    loading.close()
  }
  // Omit other code
  return Promise.reject(error)
})
Copy the code

6. Use opportunely Mixins

6.1 Encapsulating store Common methods

Consider a scenario where we encapsulate a function to get a news list with Vuex

import Vue from 'vue'
import Vuex from 'vuex'
import { getNewsList } from '.. /api/news'
Vue.use(Vuex)
const types = {
  NEWS_LIST: 'NEWS_LIST'
}
export default new Vuex.Store({
  state: {
    [types.NEWS_LIST]: []
  },
  mutations: {
    [types.NEWS_LIST]: (state, res) = > {
      state[types.NEWS_LIST] = res
    }
  },
  actions: {
    [types.NEWS_LIST]: async ({ commit }, params) => {
      const res = await getNewsList(params)
      return commit(types.NEWS_LIST, res)
    }
  },
  getters: {
    getNewsResponse (state) {
      return state[types.NEWS_LIST]
    }
  }
})
Copy the code

And then on the news list page, we call Action and getters with mapAction and mapGetters and we need to write this code

import { mapActions, mapGetters } from 'vuex'computed: { ... mapGetters(['getNewsResponse']) }, methods: { ... mapActions(['NEWS_LIST'])}Copy the code

Suppose, on another page, we need to call the interface to get the news list again, so we have to write the above code again, right?

Copy and paste is dry there?

If an interface suddenly takes an argument, wouldn’t every code that uses the interface have to take that argument?

Copy and paste for a while cool, demand a change you cool

Since it is repetitive code, we must reuse it, where the mixins provided by Vue come in handy

  • Packaging news – a mixin. Js insrcSo let’s create onemixinsDirectory to manage all mixinsnews-mixin.js
import { mapActions, mapGetters } from 'vuex'
export default {
  computed: {
    ...mapGetters(['getNewsResponse'])},methods: {
    ...mapActions(['NEWS_LIST'])}}Copy the code

You can then call this method directly by introducing the mixin in the component you want to use. No matter how many pages, once you introduce this mixin, you can use it directly.

If the requirements change, you only need to modify the mixin file

// news/index.vue
import Vue from 'vue'
import newsMixin from '@/mixins/news-mixin'
export default {
  name: 'news'.mixins: [newsMixin],
  data () {
    return{}},async created () {
    await this.NEWS_LIST()
    console.log(this.getNewsResponse)
  }
}
Copy the code

6.2 extensions

In addition to the common way to encapsulate VUex, there are many other things that can encapsulate vuex. Examples include paging objects, tabular data, common methods, and so on. Can see a lot

If you use it frequently in multiple places, consider packaging it as a mixin, but make sure to comment it out. Otherwise, someone will scold you behind your back!! ~ ~ you understand

7. To optimize

7.1 gzip compression

  • The installationcompression-webpack-pluginThe plug-in
npm install compression-webpack-plugin --save-dev
// or
yarn add compression-webpack-plugin --dev
Copy the code
  • Add the configuration in vue.config.js
// vue.config.js
const CompressionPlugin = require('compression-webpack-plugin'Module.exports = {chainWebpack: config => {// config.plugin(module. Exports = {chainWebpack: config => {// config.plugin('define').tap(args => {
      args[0]['process.env'].BASE_URL = JSON.stringify(process.env.BASE_URL)
      return args
    })
    if (process.env.NODE_ENV === 'production'{/ /#region Enables GZip compression
      config
        .plugin('compression')
        .use(CompressionPlugin, {
          asset: '[path].gz[query]',
          algorithm: 'gzip'.test: new RegExp('\ \. (' + ['js'.'css'].join('|') + '$'),
          threshold: 10240,
          minRatio: 0.8,
          cache: true
        })
        .tap(args => { })

      // #endregion}}}Copy the code

NPM run build can see generated.gz file OK. If your server uses Nginx, nginx also needs to be configured to enable GZIP

7.2 Third-party Libraries Reference CDN

For vue, VUE-Router, Vuex, AXIos, element-UI and other libraries that are not frequently changed, we let WebPack not pack them. Introducing them through CDN can reduce the size of the code, reduce the bandwidth of the server, and cache these files to the client. The client will load faster.

  • configurationvue.config.js
const CompressionPlugin = require('compression-webpack-plugin'Module. Exports = {chainWebpack: config => {// omit other code ···· //#region Ignores files packed by the build environment

      var externals = {
        vue: 'Vue',
        axios: 'axios'.'element-ui': 'ELEMENT'.'vue-router': 'VueRouter',
        vuex: 'Vuex'
      }
      config.externals(externals)
    const cdn = {
        css: [
          // element-ui css
          '//unpkg.com/element-ui/lib/theme-chalk/index.css'
        ],
        js: [
          // vue
          '/ / cdn.staticfile.org/vue/2.5.22/vue.min.js',
          // vue-router
          '/ / cdn.staticfile.org/vue-router/3.0.2/vue-router.min.js',
          // vuex
          '/ / cdn.staticfile.org/vuex/3.1.0/vuex.min.js',
          // axios
          '/ / cdn.staticfile.org/axios/0.19.0-beta.1/axios.min.js',
          // element-ui js
          '//unpkg.com/element-ui/lib/index.js'
        ]
      }
      config.plugin('html')
        .tap(args => {
          args[0].cdn = cdn
          return args
        })
      // #endregion}}}Copy the code
  • Modify theindex.html
<! --public/index.html-->

      
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <% if (process.env.NODE_ENV= = ='production') { %>

      <% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
        <link href="<%=css%>" rel="preload" as="style">
        <link rel="stylesheet" href="<%=css%>" as="style">
      <%} % >
      <% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
        <link href="<%=js%>" rel="preload" as="script">
        <script src="<%=js%>"></script>
      <%} % >
        
    <%} % >
    <title>vue-cli3-project</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but vue-cli3-project doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <! -- built files will be auto injected -->
  </body>
</html>
Copy the code

7.3 total CDN

We have replaced the third-party library with CDN, so can we also use CDN for the JS and CSS files generated after our build?

Apply for your own CDN domain name

If you want to upload your own resources to CDN, you must have your own CDN domain name. If not, you can register and apply for one on qiniuyun official website

  1. Register a qiuniuyun account
  2. Create storage space in the qiuniuyun object storage module
  3. Enter storage space information
  4. Make sure to create
  5. After the storage space is created, the console page for the storage space is displayed
  6. One of these domains is your test domain
  7. We can upload ours to content Managementjs,cssAnd so on file, but our file so much, a upload is obviously unreasonable. Not if I ask you to.

At this point, these batch and repeat operations should be handled by our Node, let’s use Node to batch upload our resource files

Upload the generated JS and CSS resources to qiniu CDN

There is an introduction on how to upload files through Node in the documentation center of qiuniuyun official website. Those who are interested can go to study it themselves.

  1. To viewAccessKeyandSecretKeyIn your personal panel -> Key Management, these two keys will be used later

  1. Install the required plug-ins
npm install qiniu glob mime --save-dev
Copy the code
  1. inscriptsCreate one in the directoryupcdn.jsfile
// /scripts/upcdn.js
const qiniu = require('qiniu')
const glob = require('glob')
const mime = require('mime')
const path = require('path')

const isWindow = /^win/.test(process.platform)

let pre = path.resolve(__dirname, '.. /dist/') + (isWindow ? '\ \' : ' ')

const files = glob.sync(
  `${path.join(
    __dirname,
    '.. /dist/**/*.? (js|css|map|png|jpg|svg|woff|woff2|ttf|eot)'
  )}`
)
pre = pre.replace(/\\/g.'/')

const options = {
  scope: 'source' // Space object name
}
var config = {
  qiniu: {
    accessKey: ' '.// AccessKey in personal key management
    secretKey: ' '.// SecretKey in personal central key management
    bucket: options.scope,
    domain: 'http://ply4cszel.bkt.clouddn.com'}}var accessKey = config.qiniu.accessKey
var secretKey = config.qiniu.secretKey

var mac = new qiniu.auth.digest.Mac(accessKey, secretKey)
var putPolicy = new qiniu.rs.PutPolicy(options)
var uploadToken = putPolicy.uploadToken(mac)
var cf = new qiniu.conf.Config({
  zone: qiniu.zone.Zone_z2
})
var formUploader = new qiniu.form_up.FormUploader(cf)
async function uploadFileCDN (files) {
  files.map(async file => {
    const key = getFileKey(pre, file)
    try {
      await uploadFIle(key, file)
      console.log('Upload successful key:${key}`)}catch (err) {
      console.log('error', err)
    }
  })
}
async function uploadFIle (key, localFile) {
  const extname = path.extname(localFile)
  const mimeName = mime.getType(extname)
  const putExtra = new qiniu.form_up.PutExtra({ mimeType: mimeName })
  return new Promise((resolve, reject) = > {
    formUploader.putFile(uploadToken, key, localFile, putExtra, function (respErr, respBody, respInfo) {
      if (respErr) {
        reject(respErr)
      }
      resolve({ respBody, respInfo })
    })
  })
}
function getFileKey (pre, file) {
  if (file.indexOf(pre) > - 1) {
    const key = file.split(pre)[1]
    return key.startsWith('/')? key.substring(1) : key
  }
  return file
}

(async() = > {console.time('Upload file to CDN')
  await uploadFileCDN(files)
  console.timeEnd('Upload file to CDN')
})()
Copy the code

Modify publicPath

Modify the configuration information of vue.config.js to make its publicPath point to the domain name of our CDN

const IS_PROD = process.env.NODE_ENV === 'production'
const cdnDomian = 'http://ply4cszel.bkt.clouddn.com'
module.exports = {
  publicPath: IS_PROD ? cdnDomian : '/', // omit other code...Copy the code

Modify package.json configuration

Modify package.json configuration to automatically upload resource files to CDN server after we finish build

"build": "vue-cli-service build --mode prod && node ./scripts/upcdn.js".Copy the code

Run to view the effect

npm run build

cdn

8. Docker deployment

This is a centOS7 environment, but using a different system, you can refer to the installation method of other systems

8.1 installation docker

  • Update software library
yum update -y
Copy the code
  • Install the docker
yum install docker
Copy the code
  • Start the Docker service
service docker start
Copy the code
  • Install the docker – compose
Yum install docker-compose yum install docker-composeCopy the code

8.2 write a docker – compose. Yaml

version: '2.1'
services:
  nginx:
    restart: always
    image: nginx
    volumes:
      # ~ / var/local/nginx/nginx. Conf for native directory, / etc/nginx directory for container
      - /var/local/nginx/nginx.conf:/etc/nginx/nginx.conf
      Dist = /usr/ SRC /app = /usr/ SRC /app
      - /var/local/app/dist:/usr/src/app
    ports:
      - 80:80
    privileged: true
Copy the code

8.3 Writing the nginx.conf configuration

#user nobody;

worker_processes  2;

# Working mode and connection number online
events {
    worker_connections  1024;   # Maximum number of concurrent processes processed by a single worker process
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    # sendFile specifies whether nginx calls sendfile (zero copy) to output files. For common applications,
    sendfile        on;
    #tcp_nopush on;

    #keepalive_timeout 0;
    keepalive_timeout  65;

    # open GZIP
    gzip  on;

    Listen on port 80 and forward the request to port 3000
    server {
        # monitor port
        listen      80;
        # Encoding format
        charset utf-8;

        Front-end static file resources
        location / {
	    root  /usr/src/app;
            index index.html index.htm;
            try_files $uri $uri/ @rewrites;
        }
        If the resource is not matched, point the URL to index. HTML and use it in vue-router history modelocation @rewrites { rewrite ^(.*)$ /index.html last; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; }}}Copy the code

8.4 perform docker – compose

docker-compose -d up
Copy the code

8.5 Docker + Jenkins automated deployment

Docker + Jenkins can be used to implement the code submitted to Github after automatic deployment environment, this to talk about too much content, interested can see my article

Build docker+ Jenkins + Node.js automatic deployment environment from zero

6. Extension

  • Deploy node projects automatically using PM2
  • Build an SSR application with VUE-CLI3

If you have any better way to practice, welcome to comment section!!

Project address vuE-CLI3-project welcome star

The original address www.ccode.live/lentoo/list…

Welcome to attention

Welcome to pay attention to the public account “code development”, share the latest technical information every day