Coder Social home page Coder Social logo

solarliner / vue-cli-plugin-prerender-spa Goto Github PK

View Code? Open in Web Editor NEW
173.0 8.0 26.0 281 KB

Boost SEO by prerendering your Vue application. Powered by prerender-spa-plugin.

Home Page: https://www.npmjs.com/package/vue-cli-plugin-prerender-spa

License: MIT License

JavaScript 100.00%
vuejs cli plugin pre-rendering

vue-cli-plugin-prerender-spa's Introduction

vue-cli-plugin-prerender-spa

Add prerender-spa-plugin into your Vue application with zero configuration.

Looking for a co-maintainer: I'm continuing to maintain this project, hoever I still would like help on some of the issues, and generally to help me keep this plugin going as it's getting more and more popular. If you think you can help, file and issue for maintainship!

Support requests: Vue has a Discord server and I often lurk in there. And while there is a support label in the Issues, GitHub isn't the place for support requests and should be directed to me in the Vue Land Discord server.

Install

Add prerendering to your Vue application with:

vue add prerender-spa

or by searching for prerender-spa in the Vue UI plugins.

You'll be asked a few questions, detailed below, to which the default answers are the most common options.

The main option to fit to your needs is the list of routes to pre-render. Specify them as a comma-separated list:

? Which routes to pre-render? (list them separated by a comma) /,/about,/contact

Options list

Pre-rendered routes

? Which routes to pre-render? (list them separated by a comma) /

Specify a list of routes to pre-render. By default only the index page is pre- rendered, which should cover most SPAs. If your project uses vue-router, you can specify a list of routes that do not depend on dynamic content (like user uploaded data, public profiles, etc.). For example you can add your about page as well as a contact page - those will load faster, and will be indexed by bots who do not execute JavaScript, improving Search Engines rankings.

Note that if you want to also pre-render user generated content, you will have to switch to Server-Side Rendering, there are no other options.

What it does to your project

The list of routes is split into an array and passed into the Webpack plugin. The routes aren't checked for existence or even duplicates, just split into an array and sent to the PrerenderSPAPlugin instance.

Event-triggered snapshot

? Use a render event to trigger the snapshot? Yes

Use a document event to signal prerender-spa-plugin to trigger a snapshot of the DOM and save it. By default the renderer waits until DOMContentLoaded to take a snapshot of the DOM. But it is still recommended that you control the snapshot trigger - no surprise waiting for hours for your build before realizing what's happening.

What it does to your project

When enabling the event-based snapshot trigger, it will tell PrerenderSPAPlugin to listen for an x-app-rendered event. Your main file is then modified to add a mounted() hook where the event will fire. Note that it doesn't check if the hook is already present, nor does it parses the file; it just looks for the line starting with render: (minus whitespaces) and inserts the mounted() hook below. If you already have the hook set up, or if your render() function on the main file is longer than one line, it will break your Vue entrypoint. A better injection routine is planned, but for now, it covers a vast majority of projects where the main file isn't touched.

Use a headless browser for rendering

? Use a headless browser to render the application? (recommended) Yes

This option is there for debugging purposes, but should be left enabled otherwise. Not using a headless browser will open a Chrome window when building with your app running inside, then close once the snapshot has been taken. Since the plugin configuration object isn't available, it is available here.

What it does to your project

The headless value of the configuration object is set to the answer to the question.

Only pre-render for production builds

? Only use prerendering for production builds? (recommended) Yes

Only load the pre-rendering plugin when building for production. This is strongly recommended as the plugin, spawning an instance of the Chrome browser, adds significant time to the build process. Development builds should be snappy and not memory-intensive; which is exactly what this plugin does to your build.

However, there may be cases where you want to test the pre-rendering itself, and switching to a production build isn't the solution - you may then turn off that option.

Indirect options

Parallel / Mutli-threaded

This option is configured from within the Vue CLI itself, but serves to a whole host of plugins to determine whether to turn on parallel jobs / multi-threading.

This plugin uses it to tell prerender-spa-plugin to render pages concurrently (meaning in parallel) or not by setting the maxConcurrentRoutes parameter to either 1 or 4, if the build is respectively single-threaded or multi-threaded.

Custom configuration

After being invoked, the plugin saves a file named .prerender-spa.json in the root directory of the project; where you can specify custom options for the Puppeteer renderer. It will be merged, and its options will overwrite those set by the plugin itself.

Other way to set custom configuration for the Puppeteer renderer is to use customRendererConfig dictionary of possible Puppeteer launch options.

Example configuration of debugging your site with Chrome DevTools opened automatically:

// vue.config.js

module.exports = {
  pluginOptions: {
    prerenderSpa: {
      registry: undefined,
      renderRoutes: [
        '/',
        '/about'
      ],
      useRenderEvent: true,
      onlyProduction: true,
      
      headless: false, // <- this could also be inside the customRendererConfig
      customRendererConfig: 
      {
        args: ["--auto-open-devtools-for-tabs"]
      }
    }
  }
}

User post processing function

Pupeteer allows to postprocess the HTML after it's been snapshot, and the plugin allows you to provide your own function if you need to.

Add a postProcess option into your vue.config.js file to provide a custom post-processing function to run on every build.

Example configuration:

// vue.config.js

module.exports = {
  pluginOptions: {
    prerenderSpa: {
      registry: undefined,
      renderRoutes: [
        '/',
        '/about'
      ],
      useRenderEvent: true,
      headless: true,
      onlyProduction: true,
      postProcess: route => {
        // Defer scripts and tell Vue it's been server rendered to trigger hydration
        route.html = route.html
          .replace(/<script (.*?)>/g, '<script $1 defer>')
          .replace('id="app"', 'id="app" data-server-rendered="true"');
        return route;
      }
    }
  }
}

Contributing

You are very welcome to contribute. To ask for a feature, or submit a bug, use the Issues list. If you want to contribute a feature yourself, first submit an Issue, work on your code, and add a Pull Request, referencing your issue in the PR message. This way the isse can serve as a mean to discuss the feature, and the Pull Request is where we can review the code and talk specificities.

In all cases, follow the templates carefully, in order to maximize information throughput.

Notices

Backend routing configuration for deployments

Since the index.html is now (most likely, depending on your list of routes) pre-rendered, pointing to it from another path will lead to whiteflashing as the pre-rendered content (of the index page) will not match the expected content of the route (say from an about page). For this reason, the plugin outputs another file called app.html that doesn't get pre-rendered. For better user experience, it is recommended to route non-prerendered routes to this file instead of the default index.html.

Here's an example nginx configuration snippet:

location / {
try_files $uri $uri/index.html $uri.html /app.html;
}

And an example Firebase configuration (taken from https://stackoverflow.com/a/51218261):

"rewrites": [
  {
    "source": "**",
    "destination": "/app.html"
  },
  {
    "source": "/",
    "destination": "/index.html"
  }
]

CI/CD workflows

Because the prerender-spa-plugin uses a headless Chrome instance, your regular node:latest Docker image will not chug your build correctly; you need system dependencies and configuration that might not be efficient to add to the job itself - rather, it is recommended to switch to a Node.js + Puppeteer image where you can just use your install && build workflow without any additional configuration. I personally use the alekzonder/puppeteer image.

If you do decide on using alekzonder/puppeteer and you want to install global npm packages. The following commands can be used prior to the installation of your required global package to ensure that you do not receive an EACCES: permission denied, access '/usr/local/lib/node_modules' error. I have tested this using Gitlab CI.

- mkdir ~/.npm-global
- npm config set prefix '~/.npm-global'
- npm install -g @vue/cli-service-global

Compatibility with other Vue CLI plugins

This plugin should be compatible with any plugin that doesn't add a mounted() hook into the Vue entrypoint in your main.{js,ts} file, as this is the only file it updates, and only if you choose an event-based snapshot trigger.

vue-cli-plugin-prerender-spa's People

Contributors

chrillefkr avatar dependabot-preview[bot] avatar dependabot[bot] avatar far3 avatar jamiecarter7 avatar jrutila avatar karticus avatar lmvdz avatar nahanil avatar snadn avatar solarliner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-cli-plugin-prerender-spa's Issues

IE10/IE11: Object doesn't support this action

I'm getting a

Object doesn't support this action

on

mounted: () => document.dispatchEvent(new Event("x-app-rendered")),

To Reproduce
Steps to reproduce the behavior:

Use defaults; add to project; run in IE10/IE11

Expected behavior
A clear and concise description of what you expected to happen.

No error on console / bugsnag

Additional context
Package version: 1.1.6
Vue version: X.X.X
Vue CLI version: X.X.X

Html files get built but contain index.html content once deployed

  • Using Vue Router with history mode and the first route that is loaded is /welcome.
  • Dist (build) folder contains - as expected - an index.html and a welcome.html file.
  • Once deployed, the welcome file gets loaded BUT has not the content of the welcome.html as in the dist folder but actually just the same content as the index.html.

The page now obviously stays white as even though we're looking at /welcome what actually is loaded is a welcome-file with the index.html content.

Any idea what I may do wrong?

TypeError: Cannot set property of 'template' of undefined

I get this Error:

-  Building for production... **ERROR  TypeError: Cannot set property 'template' of undefined
TypeError: Cannot set property 'template' of undefined**
    at config.plugin.tap.args (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\vue-cli-plugin-prerender-spa\index.js:55:26)
    at Object.tap (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\webpack-chain\src\Plugin.js:24:24)
    at config (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\vue-cli-plugin-prerender-spa\index.js:54:29)
    at webpackChainFns.forEach.fn (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\@vue\cli-service\lib\Service.js:227:40)
    at Array.forEach (<anonymous>)
    at Service.resolveChainableWebpackConfig (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\@vue\cli-service\lib\Service.js:227:26)
    at PluginAPI.resolveChainableWebpackConfig (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\@vue\cli-service\lib\PluginAPI.js:128:25)
    at module.exports (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\@vue\cli-service\lib\commands\build\resolveAppConfig.js:2:22)
    at build (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\@vue\cli-service\lib\commands\build\index.js:138:50)
    at api.registerCommand (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\@vue\cli-service\lib\commands\build\index.js:85:13)
    at Service.run (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\@vue\cli-service\lib\Service.js:221:12)
    at Object.<anonymous> (C:\Users\erikr\source\repos\ToDoStudio\To-Do.Studio Info\TDS.Web\node_modules\@vue\cli-service\bin\vue-cli-service.js:36:9)
    at Module._compile (internal/modules/cjs/loader.js:722:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:733:10)
    at Module.load (internal/modules/cjs/loader.js:620:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:560:12)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] build: `vue-cli-service build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:

I am using a normal vue-cli based project using multiple pages (and no main.js)

pages: {
    "index": {
      entry: "src/home.js",
      template: "public/home.html",
      filename: "index.html",
    },
    "home-french": {
      entry: "src/homeFrench.js",
      template: "public/home-french.html",
      filename: "home-french.html",
    },
    "privacy-policy": {
      entry: "src/privacyPolicy.js",
      template: "public/privacy-policy.html",
      filename: "privacy-policy.html",
    },
    "terms-of-use": {
      entry: "src/termsOfUse.js",
      template: "public/terms-of-use.html",
      filename: "terms-of-use.html",
    },
  },

  pluginOptions: {
    prerenderSpa: {
      registry: undefined,
      renderRoutes: [
        '/',
        '/home-french',
        '/terms-of-use',
        '/privacy-policy'
      ],
      useRenderEvent: true,
      headless: true,
      onlyProduction: true
    }

failed to launch chrome in heroku

When I include "vue-cli-plugin-prerender-spa" into my dependencies and I deploy my app to heroku I get a puppeteer error. But I only get it with your vue plugin. My project already uses puppeteer and I already included the buildpack. I have no idea why it only happens to "vue-cli-plugin-prerender-spa".
This is the full error I get in the heroku console:

-  Building for production...
Browserslist: caniuse-lite is outdated. Please run next command `npm update`
Error: Failed to launch chrome!
/tmp/build_a7b338b0_/node_modules/puppeteer/.local-chromium/linux-650583/chrome-linux/chrome: error while loading shared libraries: libX11-xcb.so.1: cannot open shared object file: No such file or directory
TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md
    at onClose (/tmp/build_a7b338b0_/node_modules/puppeteer/lib/Launcher.js:342:14)
    at Interface.helper.addEventListener (/tmp/build_a7b338b0_/node_modules/puppeteer/lib/Launcher.js:331:50)
    at Interface.emit (events.js:203:15)
    at Interface.close (readline.js:397:8)
    at Socket.onend (readline.js:173:10)
    at Socket.emit (events.js:203:15)
    at endReadableNT (_stream_readable.js:1145:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)
[Prerenderer - PuppeteerRenderer] Unable to start Puppeteer
(node:1285) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'close' of null
    at PuppeteerRenderer.destroy (/tmp/build_a7b338b0_/node_modules/@prerenderer/renderer-puppeteer/es6/renderer.js:140:21)
    at Prerenderer.destroy (/tmp/build_a7b338b0_/node_modules/@prerenderer/prerenderer/es6/index.js:87:20)
    at PrerendererInstance.initialize.then.then.then.then.then.then.then.then.catch.err (/tmp/build_a7b338b0_/node_modules/prerender-spa-plugin/es6/index.js:144:29)
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:1285) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:1285) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
-----> Timed out running buildpack Node.js
Terminated
 !     Push failed

Versions
node version in heroku: v10.22.1
"vue-cli-plugin-prerender-spa": "^1.1.6"
"vue": "^2.6.10"
vue CLI: 3.5.1

Support pass all prerender-spa-plugin options

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

We can define more options which are feed to prerender-spa-plugin not only the renderer options in .prerender-spa.json.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Some async scripts write script tags into html and be rendered in pre-rendering. While user visit website these async scripts write twice thtese script tags. prerender-spa-plugin provides us postProcess option to cleanup the prerendered html. Need a way to configure that option.

Add server configuration options

Is your feature request related to a problem? Please describe.

I need to add server configuration options to prerender-spa-plugin. I specifically want to configure a proxy.

module.exports = {
  plugins: [
    ...
    new PrerenderSPAPlugin({
      ...
      // Server configuration options.
      server: {
        /* I need to add stuff here! */
      },

Describe the solution you'd like

Patch index.js:

diff --git a/old b/new
index e4e155a..1515509 100644
--- a/old
+++ b/new
@@ -26,6 +26,7 @@ function chain(api, projectOptions) {
     const prerenderOptions = {
       ...paths,
       routes: options.renderRoutes,
+      server: options.server,
       renderer,
       postProcess: renderedRoute => {
         const route = renderedRoute.route;

Describe alternatives you've considered

I could not find an alternative, other than dropping this plugin and using https://github.com/chrisvfritz/prerender-spa-plugin directly.

Missing the index.html and built dir is not correct too

Describe the bug
after i add this plugin to my pervious pro by useing 'vue add prerender-spa-plugin'.
i followed the prompts ervery step. i think the generated configuration is also correct as bellow.
//...vue.config.js
image
// main.js
image

But something different from custom pro is that mine is not right in the root dir at my backend pro.
I have to set my publicPath to '/v5/',maybe thi caused the issue. this is my publicPath configuration bellow

publicPath: process.env.NODE_ENV === 'development' ? '/' : '/v5/',

then i got my dist Dir like this:
image

My login.html is under in the v5 Dir. And I missed my index.html,too.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Package version: X.X.X
Vue version: 2.6.X
Vue CLI version: 4.2.3

Meta information

Describe the bug
Every route has the meta information from the homepage. Even in history mode. Is there any way to solve this ?

queries and x-app-rendered

  mounted: () => {
    this.$nextTick( function () {
      // Code that will run only after the
      // entire view has been rendered
      document.dispatchEvent(new Event("x-app-rendered"))
    })
  },

see also #39
I wonder if there is a way to fire the event programmatically after all request of a route are resolved. The idea above does not work. Doing it manually with each query is uncomfortable.

@click events not firing when built for production

Describe the bug
I am using vue-owl-carousel and vue-scrollto. Both plugins work fine in dev, but break in production. I thought the issue was tree shaking (or something else related to the plugins not being included in the final build), however inspecting the source reveals they are both included.

I tried something else - attaching @click event with window.scrollTo and I got the same effect - works in dev, not in production. I believe the two issues are related and fixing one would fix the other (or at least I hope so).
Additional context

"vue": "^2.6.10",
    "vue-owl-carousel": "^2.0.3",
    "vue-router": "^3.0.3",
    "vue-scrollto": "^2.17.1"

main.js

import Vue from "vue";
import App from "./App.vue";
import router from './router';
import VueScrollTo from 'vue-scrollto';


Vue.config.productionTip = false;

Vue.use(VueScrollTo, {
  container: "body",
  duration: 500,
  easing: "ease",
  offset: 0,
  force: true,
  cancelable: true,
  onStart: false,
  onDone: false,
  onCancel: false,
  x: false,
  y: true
})

new Vue({
  el: '#app',
  router,
  VueScrollTo,
  render: h => h(App),
  mounted: () => document.dispatchEvent(new Event("x-app-rendered")),
})

vue.config.js

module.exports = {
  pluginOptions: {
    prerenderSpa: {
      registry: undefined,
      renderRoutes: [
        '/civil-engineering',
        '/',
      ],
      useRenderEvent: true,
      headless: true,
      onlyProduction: true
    }
  }
}

Not working with vue cli 4.4

Describe the bug
npm run build keeps "building for production..." forever when vue cli plugin prerender spa is use
Additional context
Package version: 1.1.6
Vue version: 2.6.11
Vue CLI version: 4.4

Meta Information

Is your feature request related to a problem? Please describe.
No way to add more SEO friendly meta tags and information to the page? Currently using: https://www.npmjs.com/package/@bachdgvn/vue-router-meta-tags

Describe the solution you'd like
I am not sure if this is a feature specifically or support for something, but since Vue CLI now does not use webpack (or at least allows us to edit the webpack config), I was wondering is there any plugins that would allow me to define meta information within the routes and then this would then amend and edit the meta tags before the snapshot is taken?

Describe alternatives you've considered
I have found things like this: https://www.npmjs.com/package/@bachdgvn/vue-router-meta-tags but they do not work with this plugin.

Additional context
Any other plugins that do exist and work please let me know!

Thanks,

Getting ERROR TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string

Describe the bug
Getting ERROR TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string

To Reproduce
Steps to reproduce the behavior:

  1. Followed installation instructions.
  2. Ran command npm run build.

Expected behavior
Successful build.

Output
But getting error..

npm run build

> vue-cli-service build

⠋  Building for production... ERROR  TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string
    at assertPath (path.js:28:11)
    at Object.join (path.js:1244:7)
    at api.chainWebpack.config (~/node_modules/vue-cli-plugin-prerender-spa/index.js:34:16)

Contents of my .prerender-spa.json

{
"renderRoutes":["/","/about"],
"useRenderEvent":true,
"headless":true,
"onlyProduction":true
}

Additional context
Vue version: 2.5.16
Vue CLI version: 3.0.0-beta.15

Build fails if there's no pluginOptions.prerenderSpa in vue.config.js

Describe the bug
Build fails when removing pluginOptions.prerenderSpa from vue.config.js

TypeError: Cannot convert undefined or null to object
    at Function.assign (<anonymous>)
    at createPluginOptions (/node_modules/vue-cli-plugin-prerender-spa/index.js:136:17)

To Reproduce
Steps to reproduce the behavior:

  1. Install plugin
  2. Comment out the plugin options in vue.config.js
pluginOptions: {
  /*prerenderSpa: { ... }*/
}

or

/*pluginOptions: {
  prerenderSpa: { ... }
}*/
  1. Build npm run build (aka vue-cli-service build)
  2. See error

Expected behavior
I was looking for a way to disable the plugin temporarily, and tried by removing any options, and then stumbled upon this.

Additional context
vue-cli-plugin-prerender-spa: 1.1.5
@vue/cli-service: 3.5.0

Advert processing

** NOT A FEATURE / BUG **

Has anyone got any experience with how to pre-render an SPA with adverts that appear on said pages?

When building on my local google sees that I am on localhost so an advert is not delivered, but I am worried that rendering the 300 or so pages on my spa might trigger large amounts of ad impressions.

How have other people tackled this issue?

Thanks!

Now (Zeit.co) config

I am using vue-cli and deploy my app on Now and experiencing the known problem when all regular SPA routes stop working as index.html is changed. But I don't know how to configure routing all regular routes to app.html on Now.

To see what I am talking about go to https://clubedmarketru-sfilimonov.netology-group.now.sh and click "Войти" at the top right corner.

My vue.config.js file

module.exports = {
  pluginOptions: {
    prerenderSpa: {
      registry: undefined,
      renderRoutes: [
        '/'
      ],
      useRenderEvent: true,
      headless: true,
      onlyProduction: true
    }
  }
}

now.json:

{
   "name": "project",
   "version": 2,
   "github": {
     "enabled": false
   },
   "builds": [
     {
       "src": "dist/**",
       "use": "@now/static"
     }
   ],
   "routes": [
     {
       "src": "/(js|css|img|fonts|images|docs)/(.*)",
       "dest": "/dist/$1/$2"
     },
     {
       "src": "/favicon.ico",
       "dest": "/dist/favicon.ico"
     },
     {
       "src": "/robots.txt",
       "dest": "/dist/robots.txt"
     },
     {
       "src": "/(.*)",
       "dest": "/dist"
     }
   ]
 }

Can anybody help me with this? Thanks!

serve error after installed this plugin

Describe the bug
this is a blank project init by vue ui, include vue-router, after install this plugin, I got an error when serve it, I haven't change any code …

To Reproduce
Steps to reproduce the behavior:

  1. vue ui
  2. create project
  3. choose vue-router
  4. search plugin vue-cli-plugin-prerender-spa and install it
  5. task -> serve

Screenshots
image

Problems with publicPath instead of deprecated baseUrl

Describe the bug
in vue.config.js rendering doesn't happen in puppeteer if publicPath is used instead of deprecated baseUrl, this happens with projects in subfolders.

Additional context
Package version: 1.1.1
Vue version: 2.5.21
Vue CLI version: 3.3.0

index.html scripts get called twice

Some of my scripts in my index.html page like analytics scripts care causing 2x the number of calls then normal.

An example script in the tag of my page is something like :

When npm run build has finished, the generated index.html has two calls to the src app-worker-visitor... hence generating two times the number of calls.

This does not happen to chunk vendors, but only inline scripts in index.html file.

How can this be avoided?

Thanks.

Missing index.html when redirecting routes with vi18n

Describe the bug
Index.html in the dist folder. I have vue-i18n for localization and redirecting the / to /:lang/ as per the vi18n documentation

router/index.js

/* eslint-disable no-unused-vars */
import Vue from "vue";
import VueRouter from "vue-router";
const Home = () => import("../views/Home.vue");
const Services = () => import("../views/Services.vue");
const ComingSoon = () => import("../views/ComingSoon.vue");
const NotFound = () => import("../views/NotFound.vue");

import i18n from "@/i18n";
Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    redirect: `/${i18n.locale}/`,
  },

  // USE CODE BELOW FOR DYNAMIC ROUTES
  {
    path: "/:lang/",
    component: {
      render(c) {
        return c("router-view");
      },
    },
    children: [
      {
        path: "",
        name: "Home",
        component: {
          render(c) {
            return c(Home);
          },
        },
      },
      {
        path: "services",
        name: "Services",
        component: {
          render(c) {
            return c(Services);
          },
        },
      },
      {
        path: "404",
        name: "NotFound",
        component: NotFound,
      },
      {
        path: "*",
        redirect: {
          name: "NotFound",
        },
      },
    ],
  },

];

const router = new VueRouter({
  mode: "history",
  routes,
  scrollBehavior(to, from, savedPosition) {
    if (to.hash) {
      return {
        selector: to.hash,
        // , offset: { x: 0, y: 10 }
      };
    }
    
  },
});

export default router;

To Reproduce
Steps to reproduce the behavior:

  1. create vue app
  2. install vue-i18n for localization
  3. create routes for the localization
  4. add vue-cli-plugin-prerender-spa
  5. build the app
  6. check dist folder

Expected behavior
index.html should be in the dist folder after the app is built

Screenshots
/dist/
image

Additional context
Package version: 1.1.6
Vue version: 2.6.12
Vue CLI version: 4.5.4

e2e tests fail with latest vue-cli + vue-prerender-spa-plugin

Describe the bug

End to end tests with Cypress fail when installing this plugin to a fresh project created by vue-cli (using router in history mode and Cypress for tests).

To Reproduce
Steps to reproduce the behavior:

  1. Create new project, select router, (I also usex vuex) and e2e tests with Cypress. (Run yarn test:e2e -- it works)
  2. Add the plugin vue add prerender-spa
  3. Run yarn test:e2e -- tests fail to start (Error: ENOENT: no such file or directory, stat '/Users/uninen/LocalDocuments/Projects/TestProjects/vueclie2etest/dist/app.html')
  4. Run yarn build, then run tests again with yarn test:e2e. Now Cypress starts but the tests fail as the server only show s blank page.

I also recreated the issue with a new blank project, the issue was identical. If I disable the plugin, tests start to work again.

Expected behavior
Tests should work after installing the plugin.

Additional context
Package version: 3.2.1
Vue version: 2.6.11
Vue CLI version: 4.2.2
@vue/cli-plugin-e2e-cypress: 4.2.0

when using --modern on build prerenders all routes twice

Describe the bug
Using --modern on the build function means that vue cli runs the prerender method twice, once after legacy build and again after modern build, doubling build time.

Is it necessary to do this?

Are the rendered files different, either way I imagine they are overwritten by the second render.

To Reproduce
Steps to reproduce the behavior:
pacakge.json

"scripts": {
    "build": "vue-cli-service build --modern"
 }

npm run build

Expected behavior
Should run the prerender only once.

Additional context
vue-cli-plugin-prerender-spa: ^1.1.3
vue: ^2.5.22
vue-cli: ^3.3.1

FreeBSD Compatibility

Describe the bug
FreeBSD platform unsupported. I do most of my dev work on the BSD's (FreeBSD, OpenBSD, DragonflyBSD), and trying to install this plugin failed on my box. If I have some time in the near future, I wouldn't mind tackling the issue and offering a PR for it. If anyone else wants to join in, feel free.

To Reproduce
Steps to reproduce the behavior:

  1. run vue add prerender-spa on a FreeBSD system

Expected behavior
I expected it to install

Screenshots
N/A

Additional context
FreeBSD 12.1-RELEASE
Node version: 14.13.0
Yarn version: 1.22.4
Vue version: 2.6.12
Vue CLI version: 4.5.7

Node and Yarn installed via pkg, the FreeBSD package manager

Asynchronously loaded content not rendering

Route which loads content from some API on the mounted hook should be able to prerender that async content.
Right now not working.
Current confing in vue.config.js

pluginOptions: {
    prerenderSpa: {
      registry: undefined,
      renderRoutes: [
      	'/page-with-async-content-load-on-mounted-hook',
        '/'
      ],
      useRenderEvent: true,
      headless: true,
      onlyProduction: true,
	    renderAfterTime: 5000
    }
  },

Thanks in advance!

All pages are rendered identical

Describe the bug
I have 2 pages to render: /,/about. Both index.html and about/index.html render properly but they are identical (the content is the one of the homepage). I was expecting them to be different.

To Reproduce
Steps to reproduce the behavior:

  1. vue create prerender-spa-bug
  2. Select default
  3. cd prerender-spa-bug
  4. vue add prerender-spa
  5. /,/about to the first question, press enter for the following ones
  6. yarn build

Expected behavior
Find both dist/index.html and dist/about/index.html with the respective page content.

Additional context
Package version: 1.0.2
Vue version: 2.5.17
Vue CLI version: 3.0.1

No prerender when baseURL variable is set in vue.config.js

Describe the bug
No prerender are triggered when baseURL variable is set. Build is created as normal as when the plugin is not installed but the console keeps waiting on the sentence "Building for production"

To Reproduce
Steps to reproduce the behavior:

  1. vue create example
  2. cd example
  3. vue add prerender-spa
  4. Create a vue.config.js file in the root of the project
  5. Fill vue.config.js with this.
module.exports = {
  baseUrl: '/example/',
}; 
  1. npm run build

Expected behavior
Build the project and prerender the project with the correct url

Additional context
Package version: 1.0.2
Vue version: 2.5.17
Vue CLI version: 3.0.1

index.html precache-manifest version not changing (vue cli pwa)

I'm using the plugin with "/" as one of my pre rendered routes. This of course generates an app.html since index.html becomes the pre-rendered version.

I'm also using the Vue CLI 3 PWA plugin in InjectManifest mode. What happens, is that the build process creates the precache-manifest.xxxxx.js file, and has both the app.html and index.html file, but index.html revision never changes, so my service worker gets confused once deployed as the new index.html file isn't loaded on an update. App.html seems to get a new version which is good.

I wonder if it has to do with order of operations. I.e. when does vue-cli-plugin-prerender-spa create app.html, and then I guess overwrite the index.html file generated by webpack build? I'm guessing that the workbox plugin which hashes the files to create the revision strings in precache-manifest.xxxxx.js is doing it an an inopportune time.

Thoughts?

Thanks!

Help with CI/CD pipeline

Hi! You mention that you use alekzonder/puppeteer image to help you create your CI/CD. I was wondering if you could share a little more about your pipeline. I'm trying to create a Docker image that help my team build our app, and also use it to update the app from our Jenkins.

However, I'm having some issues trying to make my Dockerfile/docker-compose + node-sass + etc work together, so any help would be appreciated.

Thanks! 😄 and thanks for your plugin, works like a charm (outside of Docker for now hahah)

View page source for all the pages only shows home page content

Describe the bug
I am using https://github.com/troxler/vue-headful plugin to dynamically generate html meta tags. But when I click on view page source for a page, all the pages have show only the home page content. However when I inspect page html, it looks exactly like it should. I am primarily using prerender-spa plugin for SEO and google bot seem to be only fetching page source. So it reports indexing errors because of incorrect canonical url.

To Reproduce

  1. Prerender one of the page for e.g https://doculet.net/about
  2. Click on view page source.
  3. It shows content of home page https://doculet.net and not https://doculet.net/about
  4. Inpect the page, it will have correct content.

Expected behavior
View page source should have same content as when you inspect the page. It may not be a bug in plugin, would like get advice on how to resolve this problem so that I can make my website SEO ready.

Screenshots
See https://www.dropbox.com/s/130e57h0kterop3/prerender-issue.png?raw=1 for screen shot.

Additional context
Package version:1.0.2
Vue version: 2.5.16
Vue CLI version: 3.0.4

Programmatically list the pages to render

Is your feature request related to a problem? Please describe.
I'm trying to see if Vue is a good tool to generate static websites. I tried Nuxt but the i18n implementation with nuxt-i18n is broken so I dropped it. And the CLI 3 gives me the feeling Nuxt isn't needed as much anymore. That said, one thing I liked was their generate config:

{
generate: {
    routes: function () {
      return axios.get('https://jsonplaceholder.typicode.com/users')
      .then((res) => {
        return res.data.map((user) => {
            return {
              route: '/projects/' + user.id,
              payload: user
            }
        })
      })
    }
  }
}

Describe the solution you'd like
A function hook to configure the routes to prerender.

Describe alternatives you've considered
I would write a script that parses my folder or router.js and update the .prerender-spa.json automatically.

onlyProduction not work

I set onlyProduction to false, but it is true and i can't build well in development and test mode

baseUrl use a CDN path prerender-spa doesn't work

use vue-cli 3

Here's the vue.config.js I'm using:
   {
     ...
     baseUrl: process.env.NODE_ENV === 'production'
           ? 'https://js.mycdnhost.com/web/'
            : '/',
   }

When our Project release,our index.html file will in www.a.com, but out our js、css file we want use cdn server to improve experience, but when the baseUrl use a CDN path, vue-cli-plugin-prerender-spa d donesn't work, and it donesn't show any error.

And if the baseUrl: '/' , It works well, what should I do? I think is is a common case to do that, which js, css in a CDN server, index.html in another server. Someone encountered in this situation like me ?

Any help would be appreciated.

Can't Submit form alway reloading when button click

Pre render works but i when i submit/ click a button on form just reload the page but when no prerender everything works fine, also hosting in firebase

Screenshots
If applicable, add screenshots to help explain your problem.

Vue version: 2.6.11
Vue CLI version: 4.2.3

Generate separate `app.html` and `index.html`/etc for better hydration behavior

Is your feature request related to a problem? Please describe.
Better support for non-prerendered pages (avoids whiteflash; some server config gotchas, etc)

Describe the solution you'd like
Either by default (or with an option) to render a separate app.html and index.html.

For previous work on the problem, see:

Describe alternatives you've considered
Trying to get a vue-cli project to have 2 separate build scripts (one for pre-rendered and one for not)

Not triggered on different env?

Describe the bug
If I run the build with
npm run build -- --mode=prod (or any other env)

the prerender does not trigger.
How do I trigger it with different env settings?

Implement JsdomRenderer

Is your feature request related to a problem? Please describe.
Puppeteer sometimes take long time to process website, but with jsdomrenderer it is faster.

Unexpected token at config

Describe the bug
It simply doesn't work after answering the questions.

Error: Line 14: Unexpected token ...
    at ErrorHandler.constructError (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:5012:22)
    at ErrorHandler.createError (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:5028:27)
    at Parser.unexpectedTokenError (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:1985:39)
    at Parser.throwUnexpectedToken (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:1995:21)
    at Parser.parseObjectPropertyKey (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:2499:33)
    at Parser.parseObjectProperty (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:2534:25)
    at Parser.parseObjectInitializer (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:2602:35)
    at Parser.inheritCoverGrammar (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:2285:37)
    at Parser.parsePrimaryExpression (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:2354:38)
    at Parser.inheritCoverGrammar (/home/user/.config/yarn/global/node_modules/esprima/dist/esprima.js:2285:37)

To Reproduce
Steps to reproduce the behavior:

  1. vue add prerender-spa
  2. Answer questions
  3. See error

Additional context
Vue version: 2.6.10
Vue CLI version: 3.9.3
OS: Ubuntu 19.04
Using typescript.

Generate with error not found inside html file

I have installed this plugin on my laravel-vue app and setup the config inside laravel mix's webpack.mix.js file.

Now, when I run it via npm(I use watch, dev, and prod for this issue), It rendered without errors.
But the rendered html file contains error test inside title tag and not found inside pre tag: http://prntscr.com/owcj6e

here's my setup:

webpack.mix.js:

mix.webpackConfig({
    plugins: [
        new PrerenderSPAPlugin({
            staticDir: path.join(__dirname, "dist"),
            routes: ["/", "/bulletin-board","/top-requests","/about-us","/sign-in"],
            postProcess(renderedRoute) {
                renderedRoute.html = renderedRoute.html
                    .replace(/<script (.*?)>/g, `<script $1 defer>`)
                    .replace(`id="app"`, `id="app" data-server-rendered="true"`)

                return renderedRoute
            },
            renderer: new Renderer({
                renderAfterTime: 5000,
                headless: true
            })
        })
    ]
});

resources/js/routes.js


import Router from 'vue-router';

export const router = new Router({
    mode : "history",
    routes : [
        {
            path    :   "/",
            name    :   "index",
            component   :   require("./client/Home.vue").default,
            meta    :   { guest: true }
        },
        {
            path    :   "/home",
            name    :   "home",
            redirect    :   "/",
            meta    :   { guest: true }
        },
        {
            path    :   "/my-account",
            name    :   "my-account",
            component   :   require("./client/MyAccount.vue").default,
            meta    :   { auth: true }
        },
        {
            path    :   "/bulletin-board",
            name    :   "bulletin-board",
            component   :   require("./client/BulletinBoard.vue").default,
            meta    :   { guest: true }
        },
        {
            path    :   "/top-requests",
            name    :   "top-requests",
            component   :   require("./client/TopRequests.vue").default,
            meta    :   { guest: true }
        },
        {
            path    :   "/about-us",
            name    :   "about-us",
            component   :   require("./client/AboutUs.vue").default,
            meta    :   { guest: true }
        },
        {
            path    :   "/privacy-policy",
            name    :   "privacy-policy",
            meta    :   { guest: true },
            component   :   require("./client/PrivacyPolicy.vue").default
        },
        {
            path    :   "/sign-in",
            name    :   "sign-in",
            component   :   require("./client/Login.vue").default
        },
        {
            path    :   "*",
            name    :   "404",
            meta    :   { guest: true },
            component   :   require("./components/404.vue").default
        }
    ]

});

router.beforeEach((to, from, next) => {

    if(to.matched.some(record => record.meta.guest)) {
        next()
    }else if( to.matched.some(record => record.meta.auth )) {
        if( localStorage.getItem('soundlaunch.user') == null ) {
            next( { name : "sign-in" })
        }else{
            next()
        }
    }else{
        next()
    }
})

resources/js/app.js

require('./bootstrap');
import Vue from 'vue';
import VueRouter from 'vue-router';
import Vuex from 'vuex';
import {router} from './routes.js';
import {store} from './store.js';
import VueSweetalert2 from 'vue-sweetalert2';

import App from './App.vue';

import Client from './layouts/Client.vue';
import Admin from './layouts/Admin.vue';

Vue.component('default-layout', Client);
Vue.component('sidebar-layout', Admin);

Vue.use(VueRouter);
Vue.use(Vuex);
Vue.use(VueSweetalert2);

const app = new Vue({
    el: '#app',
    router,
    store,
    components : {
        App
    },
    refreshData : { enabled : false }
});

Any suggestions, advise and help is heavenly appreciated.

Thank you.

plugin installationg fails if no main.js found

Installation fails if no main.js (to inject the render done event).

The workaround is to have a dummy main.js present at install or to manually finish installation by adding the appropriate code in the different entry points.

Fix error handling

Describe the bug

Error message on run

node_modules/vue-cli-plugin-prerender-spa/index.js:101
  } catch {
          ^

SyntaxError: Unexpected token {

Can you add in Line index.js:101 a exception parameter? Informations

from

} catch { <-------
  if (existsSync(oldConfigPath)) {
    options = JSON.parse(readFileSync(oldConfigPath).toString("utf-8"));
  }
}

to

} catch(ex) { <-------
  if (existsSync(oldConfigPath)) {
    options = JSON.parse(readFileSync(oldConfigPath).toString("utf-8"));
  }
}

Additional context
Package version: 1.1.1
Vue version: 2.5.21
Vue CLI version: 3.3.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.