欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Vue SSR( Vue2 + Koa2 + Webpack4)配置指南

 更新時(shí)間:2018年11月13日 09:10:05   作者:軼哥  
這篇文章主要介紹了詳解Vue SSR( Vue2 + Koa2 + Webpack4)配置指南,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

正如Vue官方所說,SSR配置適合已經(jīng)熟悉 Vue, webpack 和 Node.js 開發(fā)的開發(fā)者閱讀。請先移步ssr.vuejs.org 了解手工進(jìn)行SSR配置的基本內(nèi)容。

從頭搭建一個(gè)服務(wù)端渲染的應(yīng)用是相當(dāng)復(fù)雜的。如果您有SSR需求,對Webpack及Koa不是很熟悉,請直接使用NUXT.js

本文所述內(nèi)容示例在 Vue SSR Koa2 腳手架 : https://github.com/yi-ge/Vue-SSR-Koa2-Scaffold

我們以撰寫本文時(shí)的最新版:Vue 2,Webpack 4,Koa 2為例。

特別說明

此文描述的是API與WEB同在一個(gè)項(xiàng)目的情況下進(jìn)行的配置,且API、SSR Server、Static均使用了同一個(gè)Koa示例,目的是闡述配置方法,所有的報(bào)錯(cuò)顯示在一個(gè)終端,方便調(diào)試。

初始化項(xiàng)目

git init
yarn init
touch .gitignore

在 .gitignore 文件,將常見的目錄放于其中。

.DS_Store
node_modules

# 編譯后的文件以下兩個(gè)目錄
/dist/web
/dist/api

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

根據(jù)經(jīng)驗(yàn)來預(yù)先添加肯定會用到的依賴項(xiàng):

echo "yarn add cross-env # 跨平臺的環(huán)境變量設(shè)置工具
 koa
 koa-body # 可選,推薦
 koa-compress # 壓縮數(shù)據(jù)
 compressible # https://github.com/jshttp/compressible
 axios # 此項(xiàng)目作為API請求工具
 es6-promise 
 vue
 vue-router # vue 路由 注意,SSR必選
 vuex # 可選,但推薦使用,本文基于此做Vuex在SSR的優(yōu)化
 vue-template-compiler
 vue-server-renderer # 關(guān)鍵
 lru-cache # 配合上面一個(gè)插件緩存數(shù)據(jù)
 vuex-router-sync" | sed 's/#[[:space:]].*//g' | tr '\n' ' ' | sed 's/[ ][ ]*/ /g' | bash

echo "yarn add -D webpack
 webpack-cli
 webpack-dev-middleware # 關(guān)鍵
 webpack-hot-middleware # 關(guān)鍵
 webpack-merge # 合并多個(gè)Webpack配置文件的配置
 webpack-node-externals # 不打包node_modules里面的模塊
 friendly-errors-webpack-plugin # 顯示友好的錯(cuò)誤提示插件
 case-sensitive-paths-webpack-plugin # 無視路徑大小寫插件
 copy-webpack-plugin # 用于拷貝文件的Webpack插件
 mini-css-extract-plugin # CSS壓縮插件
 chalk # console著色
 @babel/core # 不解釋
 babel-loader
 @babel/plugin-syntax-dynamic-import # 支持動態(tài)import
 @babel/plugin-syntax-jsx # 兼容JSX寫法
 babel-plugin-syntax-jsx # 不重復(fù),必須的
 babel-plugin-transform-vue-jsx
 babel-helper-vue-jsx-merge-props
 @babel/polyfill
 @babel/preset-env
 file-loader
 json-loader
 url-loader
 css-loader
 vue-loader
 vue-style-loader
 vue-html-loader" | sed 's/#[[:space:]].*//g' | tr '\n' ' ' | sed 's/[ ][ ]*/ /g' | bash

現(xiàn)在的npm模塊命名越來越語義化,基本上都是見名知意。關(guān)于Eslint以及Stylus、Less等CSS預(yù)處理模塊我沒有添加,其不是本文研究的重點(diǎn),況且既然您在閱讀本文,這些配置相信早已不在話下了。

效仿 electorn 分離main及renderer,在 src 中創(chuàng)建 api 及 web 目錄。效仿 vue-cli ,在根目錄下創(chuàng)建 public 目錄用于存放根目錄下的靜態(tài)資源文件。

|-- public # 靜態(tài)資源
|-- src
 |-- api # 后端代碼
 |-- web # 前端代碼

譬如 NUXT.js ,前端服務(wù)器代理API進(jìn)行后端渲染,我們的配置可以選擇進(jìn)行一層代理,也可以配置減少這層代理,直接返回渲染結(jié)果。通常來說,SSR的服務(wù)器端渲染只渲染首屏,因此API服務(wù)器最好和前端服務(wù)器在同一個(gè)內(nèi)網(wǎng)。

配置 package.json 的 scripts :

"scripts": {
 "serve": "cross-env NODE_ENV=development node config/server.js",
 "start": "cross-env NODE_ENV=production node config/server.js"
}

  • yarn serve : 啟動開發(fā)調(diào)試
  • yarn start : 運(yùn)行編譯后的程序
  • config/app.js 導(dǎo)出一些常見配置:
module.exports = {
 app: {
 port: 3000, // 監(jiān)聽的端口
 devHost: 'localhost', // 開發(fā)環(huán)境下打開的地址,監(jiān)聽了0.0.0.0,但是不是所有設(shè)備都支持訪問這個(gè)地址,用127.0.0.1或localhost代替
 open: true // 是否打開瀏覽器
 }
}

配置SSR

我們以Koa作為調(diào)試和實(shí)際運(yùn)行的服務(wù)器框架, config/server.js :

const path = require('path')
const Koa = req uire('koa')
const koaCompress = require('koa-compress')
const compressible = require('compressible')
const koaStatic = require('./koa/static')
const SSR = require('./ssr')
const conf = require('./app')

const isProd = process.env.NODE_ENV === 'production'

const app = new Koa()

app.use(koaCompress({ // 壓縮數(shù)據(jù)
 filter: type => !(/event\-stream/i.test(type)) && compressible(type) // eslint-disable-line
}))

app.use(koaStatic(isProd ? path.resolve(__dirname, '../dist/web') : path.resolve(__dirname, '../public'), {
 maxAge: 30 * 24 * 60 * 60 * 1000
})) // 配置靜態(tài)資源目錄及過期時(shí)間

// vue ssr處理,在SSR中處理API
SSR(app).then(server => {
 server.listen(conf.app.port, '0.0.0.0', () => {
 console.log(`> server is staring...`)
 })
})

上述文件我們根據(jù)是否是開發(fā)環(huán)境,配置了對應(yīng)的靜態(tài)資源目錄。需要說明的是,我們約定編譯后的API文件位于 dist/api ,前端文件位于 dist/web 。

參考 koa-static 實(shí)現(xiàn)靜態(tài)資源的處理, config/koa/static.js :

'use strict'

/**
 * From koa-static
 */

const { resolve } = require('path')
const assert = require('assert')
const send = require('koa-send')

/**
 * Expose `serve()`.
 */

module.exports = serve

/**
 * Serve static files from `root`.
 *
 * @param {String} root
 * @param {Object} [opts]
 * @return {Function}
 * @api public
 */

function serve (root, opts) {
 opts = Object.assign({}, opts)

 assert(root, 'root directory is required to serve files')

 // options
 opts.root = resolve(root)
 if (opts.index !== false) opts.index = opts.index || 'index.html'

 if (!opts.defer) {
 return async function serve (ctx, next) {
  let done = false

  if (ctx.method === 'HEAD' || ctx.method === 'GET') {
  if (ctx.path === '/' || ctx.path === '/index.html') { // exclude index.html file
   await next()
   return
  }
  try {
   done = await send(ctx, ctx.path, opts)
  } catch (err) {
   if (err.status !== 404) {
   throw err
   }
  }
  }

  if (!done) {
  await next()
  }
 }
 }

 return async function serve (ctx, next) {
 await next()

 if (ctx.method !== 'HEAD' && ctx.method !== 'GET') return
 // response is already handled
 if (ctx.body != null || ctx.status !== 404) return // eslint-disable-line

 try {
  await send(ctx, ctx.path, opts)
 } catch (err) {
  if (err.status !== 404) {
  throw err
  }
 }
 }
}

我們可以看到, koa-static 僅僅是對 koa-send 進(jìn)行了簡單封裝( yarn add koa-send )。接下來就是重頭戲SSR相關(guān)的配置了, config/ssr.js :

const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const LRU = require('lru-cache')
const {
 createBundleRenderer
} = require('vue-server-renderer')
const isProd = process.env.NODE_ENV === 'production'
const setUpDevServer = require('./setup-dev-server')
const HtmlMinifier = require('html-minifier').minify

const pathResolve = file => path.resolve(__dirname, file)

module.exports = app => {
 return new Promise((resolve, reject) => {
 const createRenderer = (bundle, options) => {
  return createBundleRenderer(bundle, Object.assign(options, {
  cache: LRU({
   max: 1000,
   maxAge: 1000 * 60 * 15
  }),
  basedir: pathResolve('../dist/web'),
  runInNewContext: false
  }))
 }

 let renderer = null
 if (isProd) {
  // prod mode
  const template = HtmlMinifier(fs.readFileSync(pathResolve('../public/index.html'), 'utf-8'), {
  collapseWhitespace: true,
  removeAttributeQuotes: true,
  removeComments: false
  })
  const bundle = require(pathResolve('../dist/web/vue-ssr-server-bundle.json'))
  const clientManifest = require(pathResolve('../dist/web/vue-ssr-client-manifest.json'))
  renderer = createRenderer(bundle, {
  template,
  clientManifest
  })
 } else {
  // dev mode
  setUpDevServer(app, (bundle, options, apiMain, apiOutDir) => {
  try {
   const API = eval(apiMain).default // eslint-disable-line
   const server = API(app)
   renderer = createRenderer(bundle, options)
   resolve(server)
  } catch (e) {
   console.log(chalk.red('\nServer error'), e)
  }
  })
 }

 app.use(async (ctx, next) => {
  if (!renderer) {
  ctx.type = 'html'
  ctx.body = 'waiting for compilation... refresh in a moment.'
  next()
  return
  }

  let status = 200
  let html = null
  const context = {
  url: ctx.url,
  title: 'OK'
  }

  if (/^\/api/.test(ctx.url)) { // 如果請求以/api開頭,則進(jìn)入api部分進(jìn)行處理。
  next()
  return
  }

  try {
  status = 200
  html = await renderer.renderToString(context)
  } catch (e) {
  if (e.message === '404') {
   status = 404
   html = '404 | Not Found'
  } else {
   status = 500
   console.log(chalk.red('\nError: '), e.message)
   html = '500 | Internal Server Error'
  }
  }
  ctx.type = 'html'
  ctx.status = status || ctx.status
  ctx.body = html
  next()
 })

 if (isProd) {
  const API = require('../dist/api/api').default
  const server = API(app)
  resolve(server)
 }
 })
}

這里新加入了 html-minifier 模塊來壓縮生產(chǎn)環(huán)境的 index.html 文件( yarn add html-minifier )。其余配置和官方給出的差不多,不再贅述。只不過Promise返回的是 require('http').createServer(app.callback()) (詳見源碼)。這樣做的目的是為了共用一個(gè)koa2實(shí)例。此外,這里攔截了 /api 開頭的請求,將請求交由API Server進(jìn)行處理(因在同一個(gè)Koa2實(shí)例,這里直接next()了)。在 public 目錄下必須存在 index.html 文件:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
 <title>{{ title }}</title>
 ...
</head>
<body>
 <!--vue-ssr-outlet-->
</body>
</html>

開發(fā)環(huán)境中,處理數(shù)據(jù)的核心在 config/setup-dev-server.js 文件:

const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const MFS = require('memory-fs')
const webpack = require('webpack')
const chokidar = require('chokidar')
const apiConfig = require('./webpack.api.config')
const serverConfig = require('./webpack.server.config')
const webConfig = require('./webpack.web.config')
const webpackDevMiddleware = require('./koa/dev')
const webpackHotMiddleware = require('./koa/hot')
const readline = require('readline')
const conf = require('./app')
const {
 hasProjectYarn,
 openBrowser
} = require('./lib')

const readFile = (fs, file) => {
 try {
 return fs.readFileSync(path.join(webConfig.output.path, file), 'utf-8')
 } catch (e) {}
}

module.exports = (app, cb) => {
 let apiMain, bundle, template, clientManifest, serverTime, webTime, apiTime
 const apiOutDir = apiConfig.output.path
 let isFrist = true

 const clearConsole = () => {
 if (process.stdout.isTTY) {
  // Fill screen with blank lines. Then move to 0 (beginning of visible part) and clear it
  const blank = '\n'.repeat(process.stdout.rows)
  console.log(blank)
  readline.cursorTo(process.stdout, 0, 0)
  readline.clearScreenDown(process.stdout)
 }
 }

 const update = () => {
 if (apiMain && bundle && template && clientManifest) {
  if (isFrist) {
  const url = 'http://' + conf.app.devHost + ':' + conf.app.port
  console.log(chalk.bgGreen.black(' DONE ') + ' ' + chalk.green(`Compiled successfully in ${serverTime + webTime + apiTime}ms`))
  console.log()
  console.log(` App running at: ${chalk.cyan(url)}`)
  console.log()
  const buildCommand = hasProjectYarn(process.cwd()) ? `yarn build` : `npm run build`
  console.log(` Note that the development build is not optimized.`)
  console.log(` To create a production build, run ${chalk.cyan(buildCommand)}.`)
  console.log()
  if (conf.app.open) openBrowser(url)
  isFrist = false
  }
  cb(bundle, {
  template,
  clientManifest
  }, apiMain, apiOutDir)
 }
 }

 // server for api
 apiConfig.entry.app = ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true', apiConfig.entry.app]
 apiConfig.plugins.push(
 new webpack.HotModuleReplacementPlugin(),
 new webpack.NoEmitOnErrorsPlugin()
 )
 const apiCompiler = webpack(apiConfig)
 const apiMfs = new MFS()
 apiCompiler.outputFileSystem = apiMfs
 apiCompiler.watch({}, (err, stats) => {
 if (err) throw err
 stats = stats.toJson()
 if (stats.errors.length) return
 console.log('api-dev...')
 apiMfs.readdir(path.join(__dirname, '../dist/api'), function (err, files) {
  if (err) {
  return console.error(err)
  }
  files.forEach(function (file) {
  console.info(file)
  })
 })
 apiMain = apiMfs.readFileSync(path.join(apiConfig.output.path, 'api.js'), 'utf-8')
 update()
 })
 apiCompiler.plugin('done', stats => {
 stats = stats.toJson()
 stats.errors.forEach(err => console.error(err))
 stats.warnings.forEach(err => console.warn(err))
 if (stats.errors.length) return

 apiTime = stats.time
 // console.log('web-dev')
 // update()
 })

 // web server for ssr
 const serverCompiler = webpack(serverConfig)
 const mfs = new MFS()
 serverCompiler.outputFileSystem = mfs
 serverCompiler.watch({}, (err, stats) => {
 if (err) throw err
 stats = stats.toJson()
 if (stats.errors.length) return
 // console.log('server-dev...')
 bundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json'))
 update()
 })
 serverCompiler.plugin('done', stats => {
 stats = stats.toJson()
 stats.errors.forEach(err => console.error(err))
 stats.warnings.forEach(err => console.warn(err))
 if (stats.errors.length) return

 serverTime = stats.time
 })

 // web
 webConfig.entry.app = ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true', webConfig.entry.app]
 webConfig.output.filename = '[name].js'
 webConfig.plugins.push(
 new webpack.HotModuleReplacementPlugin(),
 new webpack.NoEmitOnErrorsPlugin()
 )
 const clientCompiler = webpack(webConfig)
 const devMiddleware = webpackDevMiddleware(clientCompiler, {
 // publicPath: webConfig.output.publicPath,
 stats: { // or 'errors-only'
  colors: true
 },
 reporter: (middlewareOptions, options) => {
  const { log, state, stats } = options

  if (state) {
  const displayStats = (middlewareOptions.stats !== false)

  if (displayStats) {
   if (stats.hasErrors()) {
   log.error(stats.toString(middlewareOptions.stats))
   } else if (stats.hasWarnings()) {
   log.warn(stats.toString(middlewareOptions.stats))
   } else {
   log.info(stats.toString(middlewareOptions.stats))
   }
  }

  let message = 'Compiled successfully.'

  if (stats.hasErrors()) {
   message = 'Failed to compile.'
  } else if (stats.hasWarnings()) {
   message = 'Compiled with warnings.'
  }
  log.info(message)

  clearConsole()

  update()
  } else {
  log.info('Compiling...')
  }
 },
 noInfo: true,
 serverSideRender: false
 })
 app.use(devMiddleware)

 const templatePath = path.resolve(__dirname, '../public/index.html')

 // read template from disk and watch
 template = fs.readFileSync(templatePath, 'utf-8')
 chokidar.watch(templatePath).on('change', () => {
 template = fs.readFileSync(templatePath, 'utf-8')
 console.log('index.html template updated.')
 update()
 })

 clientCompiler.plugin('done', stats => {
 stats = stats.toJson()
 stats.errors.forEach(err => console.error(err))
 stats.warnings.forEach(err => console.warn(err))
 if (stats.errors.length) return

 clientManifest = JSON.parse(readFile(
  devMiddleware.fileSystem,
  'vue-ssr-client-manifest.json'
 ))

 webTime = stats.time
 })
 app.use(webpackHotMiddleware(clientCompiler))
}

由于篇幅限制, koa 及 lib 目錄下的文件參考示例代碼。其中 lib 下的文件均來自 vue-cli ,主要用于判斷用戶是否使用 yarn 以及在瀏覽器中打開URL。 這時(shí),為了適應(yīng)上述功能的需要,需添加以下模塊(可選):

yarn add memory-fs chokidar readline

yarn add -D opn execa

通過閱讀 config/setup-dev-server.js 文件內(nèi)容,您將發(fā)現(xiàn)此處進(jìn)行了三個(gè)webpack配置的處理。

Server for API // 用于處理`/api`開頭下的API接口,提供非首屏API接入的能力

Web server for SSR // 用于服務(wù)器端對API的代理請求,實(shí)現(xiàn)SSR

WEB // 進(jìn)行常規(guī)靜態(tài)資源的處理

Webpack 配置

|-- config
 |-- webpack.api.config.js // Server for API
 |-- webpack.base.config.js // 基礎(chǔ)Webpack配置
 |-- webpack.server.config.js // Web server for SSR
 |-- webpack.web.config.js // 常規(guī)靜態(tài)資源

由于Webpack的配置較常規(guī)Vue項(xiàng)目以及Node.js項(xiàng)目并沒有太大區(qū)別,不再一一贅述,具體配置請翻閱源碼。

值得注意的是,我們?yōu)锳PI和WEB指定了別名:

alias: {
 '@': path.join(__dirname, '../src/web'),
 '~': path.join(__dirname, '../src/api'),
 'vue$': 'vue/dist/vue.esm.js'
},

此外, webpack.base.config.js 中設(shè)定編譯時(shí)拷貝 public 目錄下的文件到 dist/web 目錄時(shí)并不包含 index.html 文件。

編譯腳本:

"scripts": {
 ...
 "build": "rimraf dist && npm run build:web && npm run build:server && npm run build:api",
 "build:web": "cross-env NODE_ENV=production webpack --config config/webpack.web.config.js --progress --hide-modules",
 "build:server": "cross-env NODE_ENV=production webpack --config config/webpack.server.config.js --progress --hide-modules",
 "build:api": "cross-env NODE_ENV=production webpack --config config/webpack.api.config.js --progress --hide-modules"
},

執(zhí)行 yarn build 進(jìn)行編譯。編譯后的文件存于 /dist 目錄下。正式環(huán)境請盡量分離API及SSR Server。

測試

執(zhí)行 yarn serve (開發(fā))或 yarn start (編譯后)命令,訪問 http://localhost:3000 。

通過查看源文件可以看到,首屏渲染結(jié)果是這樣的:

 ~ curl -s http://localhost:3000/ | grep Hello
 <div id="app" data-server-rendered="true"><div>Hello World SSR</div></div>

至此,Vue SSR配置完成。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Element-plus使用中遇到的問題小結(jié)

    Element-plus使用中遇到的問題小結(jié)

    表格數(shù)據(jù)是websocket通信獲取的數(shù)據(jù),首次獲取20條數(shù)據(jù),以后新增訂閱獲取一條,新增一條則向上滑動顯示最新數(shù)據(jù),本文給大家介紹Element-plus使用中遇到的問題小結(jié),感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • 關(guān)于elementUi表格合并行數(shù)據(jù)并展示序號

    關(guān)于elementUi表格合并行數(shù)據(jù)并展示序號

    這篇文章主要介紹了關(guān)于elementUi表格合并行數(shù)據(jù)并展示序號,通過給table傳入span-method方法可以實(shí)現(xiàn)合并行或列,方法的參數(shù)是一個(gè)對象,感興趣的朋友可以學(xué)習(xí)一下
    2023-04-04
  • Vue如何使用ElementUI對表單元素進(jìn)行自定義校驗(yàn)及踩坑

    Vue如何使用ElementUI對表單元素進(jìn)行自定義校驗(yàn)及踩坑

    有一些驗(yàn)證不是通過input select這樣的受控組件來觸發(fā)驗(yàn)證條件的 ,可以通過自定義驗(yàn)證的方法來觸發(fā),下面這篇文章主要給大家介紹了關(guān)于Vue如何使用ElementUI對表單元素進(jìn)行自定義校驗(yàn)及踩坑的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • vue之elementUi的el-select同時(shí)獲取value和label的三種方式

    vue之elementUi的el-select同時(shí)獲取value和label的三種方式

    這篇文章主要介紹了vue之elementUi的el-select同時(shí)獲取value和label的三種方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • vue數(shù)據(jù)初始化initState的實(shí)例詳解

    vue數(shù)據(jù)初始化initState的實(shí)例詳解

    Vue 實(shí)例在建立的時(shí)候會運(yùn)行一系列的初始化操作,而在這些初始化操作里面,和數(shù)據(jù)綁定關(guān)聯(lián)最大的是 initState。這篇文章主要介紹了vue數(shù)據(jù)初始化--initState,需要的朋友可以參考下
    2019-04-04
  • Vue包大小優(yōu)化的實(shí)現(xiàn)(從1.72M到94K)

    Vue包大小優(yōu)化的實(shí)現(xiàn)(從1.72M到94K)

    這篇文章主要介紹了Vue包大小優(yōu)化的實(shí)現(xiàn)(從1.72M到94K),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • vue-router中的hash和history兩種模式的區(qū)別

    vue-router中的hash和history兩種模式的區(qū)別

    大家都知道vue-router有兩種模式,hash模式和history模式,這里來談?wù)剉ue-router中的hash和history兩種模式的區(qū)別。感興趣的朋友一起看看吧
    2018-07-07
  • vue中的局部過濾器和全局過濾器代碼實(shí)操

    vue中的局部過濾器和全局過濾器代碼實(shí)操

    這篇文章主要分享的是vue中的局部過濾器和全局過濾器代碼實(shí)操,下面文章主要以代碼展現(xiàn),具有一的的知識參考性,需要的小伙伴可以參考一下
    2022-02-02
  • vue-router傳參用法詳解

    vue-router傳參用法詳解

    今天小編就為大家分享一篇關(guān)于vue-router傳參用法詳解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • vscode中的vue項(xiàng)目報(bào)錯(cuò)Property ‘xxx‘ does not exist on type ‘CombinedVueInstance<{ readyOnly...Vetur(2339)

    vscode中的vue項(xiàng)目報(bào)錯(cuò)Property ‘xxx‘ does not exist on type ‘Combin

    這篇文章主要介紹了vscode中的vue項(xiàng)目報(bào)錯(cuò)Property ‘xxx‘ does not exist on type ‘CombinedVueInstance<{ readyOnly...Vetur(2339),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09

最新評論