]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
wip
authorEduardo San Martin Morote <posva13@gmail.com>
Thu, 29 Aug 2019 06:58:59 +0000 (08:58 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Thu, 29 Aug 2019 06:58:59 +0000 (08:58 +0200)
.vscode/settings.json [new file with mode: 0644]
__tests__/ssr/basic.spec.js [new file with mode: 0644]
package.json
src/index.ts
src/router.ts
yarn.lock

diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644 (file)
index 0000000..3662b37
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  "typescript.tsdk": "node_modules/typescript/lib"
+}
\ No newline at end of file
diff --git a/__tests__/ssr/basic.spec.js b/__tests__/ssr/basic.spec.js
new file mode 100644 (file)
index 0000000..d768414
--- /dev/null
@@ -0,0 +1,139 @@
+/** @type {import('vue').VueConstructor} */
+// @ts-ignore
+const Vue = require('vue')
+const Router = require('../../src').default
+const { components, isMocha } = require('../utils')
+const { createRenderer } = require('vue-server-renderer')
+
+describe.skip('SSR: basicRenderer', () => {
+  Vue.use(Router)
+
+  function createRouter() {
+    // TODO: a more complex routing that can be used for most tests
+    return new Router({
+      mode: 'history',
+      routes: [
+        {
+          path: '/',
+          component: components.Home,
+        },
+        {
+          path: '/foo',
+          component: components.Foo,
+        },
+      ],
+    })
+  }
+
+  function createApp() {
+    // create router instance
+    const router = createRouter()
+
+    const app = new Vue({
+      // @ts-ignore
+      router,
+      render: h => h('div', {}, [h('RouterView')]),
+    })
+
+    // return both the app and the router
+    return { app, router }
+  }
+
+  function renderApp(context) {
+    return new Promise((resolve, reject) => {
+      const { app, router } = createApp()
+
+      // set server-side router's location
+      router.push(context.url)
+
+      // wait until router has resolved possible async components and hooks
+      // TODO: rename the promise one to isReady
+      router.onReady().then(() => {
+        // const matchedComponents = router.getMatchedComponents()
+        // no matched routes, reject with 404
+        if (!matchedComponents.length) {
+          return reject({ code: 404 })
+        }
+
+        // the Promise should resolve to the app instance so it can be rendered
+        resolve(app)
+      }, reject)
+    })
+  }
+
+  it('should work', done => {
+    renderToString(
+      new Vue({
+        template: `
+        <div>
+          <p class="hi">yoyo</p>
+          <div id="ho" :class="{ red: isRed }"></div>
+          <span>{{ test }}</span>
+          <input :value="test">
+          <img :src="imageUrl">
+          <test></test>
+          <test-async></test-async>
+        </div>
+      `,
+        data: {
+          test: 'hi',
+          isRed: true,
+          imageUrl: 'https://vuejs.org/images/logo.png',
+        },
+        components: {
+          test: {
+            render() {
+              return this.$createElement('div', { class: ['a'] }, 'test')
+            },
+          },
+          testAsync(resolve) {
+            resolve({
+              render() {
+                return this.$createElement(
+                  'span',
+                  { class: ['b'] },
+                  'testAsync'
+                )
+              },
+            })
+          },
+        },
+      }),
+      (err, result) => {
+        expect(err).toBeNull()
+        expect(result).toContain(
+          '<div data-server-rendered="true">' +
+            '<p class="hi">yoyo</p> ' +
+            '<div id="ho" class="red"></div> ' +
+            '<span>hi</span> ' +
+            '<input value="hi"> ' +
+            '<img src="https://vuejs.org/images/logo.png"> ' +
+            '<div class="a">test</div> ' +
+            '<span class="b">testAsync</span>' +
+            '</div>'
+        )
+        done()
+      }
+    )
+  })
+
+  // #5941
+  it('should work peoperly when accessing $ssrContext in root component', done => {
+    let ssrContext
+    renderToString(
+      new Vue({
+        template: `
+        <div></div>
+      `,
+        created() {
+          ssrContext = this.$ssrContext
+        },
+      }),
+      err => {
+        expect(err).toBeNull()
+        expect(ssrContext).toBeUndefined()
+        done()
+      }
+    )
+  })
+})
index a59380794d5ff5ecf4206284b93f7edc1ebcff8b..cfa1d1a99359e13c0407c03e6e5bc2ce99ef9eb6 100644 (file)
@@ -44,6 +44,7 @@
     "ts-node": "^8.3.0",
     "typescript": "^3.5.3",
     "vue": "^2.6.10",
+    "vue-server-renderer": "^2.6.10",
     "vue-template-compiler": "^2.6.10",
     "webpack": "^4.39.2",
     "webpack-cli": "^3.3.7",
index 11a399bb4e40a971e789f30f6fcb37990d27e5e8..7c596c08bcec6632c02db46e58a209984da0ec3e 100644 (file)
@@ -72,23 +72,37 @@ export {
   plugin,
 }
 
+// TODO: refactor somewhere else
+const inBrowser = typeof window !== 'undefined'
+
+const HistoryMode = {
+  history: HTML5History,
+  hash: HashHistory,
+  abstract: AbstractHistory,
+}
+
 export default class VueRouter extends Router {
   static install = plugin
   static version = '__VERSION__'
 
   // TODO: handle mode in a retro compatible way
-  constructor(options: RouterOptions & { mode: 'string' }) {
+  constructor(
+    options: Partial<RouterOptions & { mode: 'history' | 'abstract' | 'hash' }>
+  ) {
+    let { mode } = options
+    if (!inBrowser) mode = 'abstract'
     super({
-      history: new HTML5History(),
       ...options,
+      routes: options.routes || [],
+      history: new HistoryMode[mode || 'hash'](),
     })
   }
 }
 
 declare global {
   interface Window {
-    Vue?: VueConstructor
+    Vue: VueConstructor
   }
 }
 
-if (window.Vue) window.Vue.use(VueRouter)
+if (typeof window !== 'undefined' && window.Vue) window.Vue.use(VueRouter)
index 8480559d007c7e9c436e568ccb6e1ed753f63773..fb5310f9b99c51be4cd7209122b89a3126fd26f3 100644 (file)
@@ -135,12 +135,18 @@ export class Router {
     })
   }
 
+  resolve(to: RouteLocation, currentLocation?: RouteLocationNormalized/*, append?: boolean */) {
+    if (typeof to === 'string') return this.resolveLocation(this.history.utils.normalizeLocation(to), currentLocation)
+    return this.resolveLocation(to)
+  }
+
   resolveLocation(
     location: MatcherLocation & Required<RouteQueryAndHash>,
-    currentLocation: RouteLocationNormalized,
+    currentLocation?: RouteLocationNormalized,
     redirectedFrom?: RouteLocationNormalized
     // ensure when returning that the redirectedFrom is a normalized location
   ): RouteLocationNormalized {
+    currentLocation = currentLocation || this.currentRoute
     const matchedRoute = this.matcher.resolve(location, currentLocation)
 
     if ('redirect' in matchedRoute) {
@@ -216,6 +222,25 @@ export class Router {
     }
   }
 
+  /**
+   * Get an array of matched components for a location. TODO: check if the array should contain plain components
+   * instead of functions that return promises for lazy loaded components
+   * @param to location to geth matched components from. If not provided, uses current location instead
+   */
+  // getMatchedComponents(
+  //   to?: RouteLocation | RouteLocationNormalized
+  // ): RouteComponent[] {
+  //   const location = to
+  //     ? typeof to !== 'string' && 'matched' in to
+  //       ? to
+  //       : this.resolveLocation(typeof to === 'string' ? this.history.utils.normalizeLocation(to) : to)
+  //     : this.currentRoute
+  //   if (!location) return []
+  //   return location.matched.map(m =>
+  //     Object.keys(m.components).map(name => m.components[name])
+  //   )
+  // }
+
   /**
    * Trigger a navigation, adding an entry to the history stack. Also apply all navigation
    * guards first
index 9e85cce9d2cb840532ff188c8ca4e2b559173d9e..7f2c80df42bdd963d57f7383437966ccd77ac927 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
@@ -709,6 +709,11 @@ ansi-regex@^4.0.0, ansi-regex@^4.1.0:
   resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
   integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
 
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+  integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+
 ansi-styles@^3.2.0, ansi-styles@^3.2.1:
   version "3.2.1"
   resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@@ -1256,6 +1261,17 @@ chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.2:
     escape-string-regexp "^1.0.5"
     supports-color "^5.3.0"
 
+chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
 chokidar@^2.0.2, chokidar@^2.1.6:
   version "2.1.6"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5"
@@ -2020,7 +2036,7 @@ escape-html@~1.0.3:
   resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
   integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
 
-escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
+escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
   integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
@@ -2625,6 +2641,13 @@ har-validator@~5.1.0:
     ajv "^6.5.5"
     har-schema "^2.0.0"
 
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+  dependencies:
+    ansi-regex "^2.0.0"
+
 has-flag@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -2686,6 +2709,11 @@ hash-base@^3.0.0:
     inherits "^2.0.1"
     safe-buffer "^5.0.1"
 
+hash-sum@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04"
+  integrity sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=
+
 hash.js@^1.0.0, hash.js@^1.0.3:
   version "1.1.7"
   resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
@@ -3890,11 +3918,36 @@ locate-path@^3.0.0:
     p-locate "^3.0.0"
     path-exists "^3.0.0"
 
+lodash._reinterpolate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
+  integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
+
 lodash.sortby@^4.7.0:
   version "4.7.0"
   resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
   integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
 
+lodash.template@^4.4.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
+  integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==
+  dependencies:
+    lodash._reinterpolate "^3.0.0"
+    lodash.templatesettings "^4.0.0"
+
+lodash.templatesettings@^4.0.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33"
+  integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==
+  dependencies:
+    lodash._reinterpolate "^3.0.0"
+
+lodash.uniq@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+  integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
+
 lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.3, lodash@^4.17.4:
   version "4.17.15"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
@@ -5250,7 +5303,7 @@ resolve@1.11.1:
   dependencies:
     path-parse "^1.0.6"
 
-resolve@1.x, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.3.2:
+resolve@1.x, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.2.0, resolve@^1.3.2:
   version "1.12.0"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6"
   integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==
@@ -5467,6 +5520,11 @@ send@0.17.1:
     range-parser "~1.2.1"
     statuses "~1.5.0"
 
+serialize-javascript@^1.3.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.8.0.tgz#9515fc687232e2321aea1ca7a529476eb34bb480"
+  integrity sha512-3tHgtF4OzDmeKYj6V9nSyceRS0UJ3C7VqyD2Yj28vC/z2j6jG5FmFGahOKMD9CrglxTm3tETr87jEypaYV8DUg==
+
 serialize-javascript@^1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65"
@@ -5649,6 +5707,11 @@ source-map-url@^0.4.0:
   resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
   integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
 
+source-map@0.5.6:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+  integrity sha1-dc449SvwczxafwwRjYEzSiu19BI=
+
 source-map@^0.5.0, source-map@^0.5.6:
   version "0.5.7"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@@ -5900,6 +5963,11 @@ supports-color@6.1.0, supports-color@^6.1.0:
   dependencies:
     has-flag "^3.0.0"
 
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+  integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+
 supports-color@^5.3.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -6356,6 +6424,20 @@ vm-browserify@^1.0.1:
   resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
   integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==
 
+vue-server-renderer@^2.6.10:
+  version "2.6.10"
+  resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.6.10.tgz#cb2558842ead360ae2ec1f3719b75564a805b375"
+  integrity sha512-UYoCEutBpKzL2fKCwx8zlRtRtwxbPZXKTqbl2iIF4yRZUNO/ovrHyDAJDljft0kd+K0tZhN53XRHkgvCZoIhug==
+  dependencies:
+    chalk "^1.1.3"
+    hash-sum "^1.0.2"
+    he "^1.1.0"
+    lodash.template "^4.4.0"
+    lodash.uniq "^4.5.0"
+    resolve "^1.2.0"
+    serialize-javascript "^1.3.0"
+    source-map "0.5.6"
+
 vue-template-compiler@^2.6.10:
   version "2.6.10"
   resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz#323b4f3495f04faa3503337a82f5d6507799c9cc"