Для рендеринга сырого html используйте v-html
<template>
<div v-html="legacySystemHTML">
</div>
</template>
<script>
export default {
data() {
return {
// Just like JSX! Oh wait...
legacySystemHTML: `
<FONT color="#faddad" size="-2">
<MARQUEE>Please enter your name to continue.</MARQUEE>
...
</FONT>
`
}
}
}
</script>
Обязательно проверяйте приходящий код, что бы не было CSRF
https://vuejsexamples.com/tag/editor/
Далее на странице обязательно заполняйте теги meta title meta description и микроразметку для соцсетей.
Все это нужно делать на основе текста статьи.
Для "тупых" поисковиков желательно сделать пререндер страниц, хотя бы самых новых.
вот один из моих проектов
package.json
{
"name": "eggclodapp",
"version": "2.0.1",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --verbosity silent",
"dev": "yarn serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"postversion": "node scripts/postversion.js",
"start": "yarn dev"
},
"dependencies": {
"@dreysolano/prerender-spa-plugin": "^1.0.3",
"axios": "^0.27.2",
"moment": "^2.29.3",
"uuid": "^8.3.2",
"vee-validate": "3.4.14",
"vue": "^2.6.14",
"vue-meta": "^2.4.0",
"vue-router": "^3.5.2",
"vue-top-progress": "^0.7.0",
"vuetify": "^2.5.8",
"vuex": "3"
},
"devDependencies": {
"@babel/core": "^7.15.4",
"@fortawesome/fontawesome-free": "^6.1.1",
"@vue/cli-plugin-babel": "^4.5.13",
"@vue/cli-plugin-router": "~4.5.13",
"@vue/cli-service": "^4.5.13",
"@vue/eslint-config-standard": "^6.1.0",
"@vuetify/vue-cli-plugin-preset-base": "~0.3.2",
"archiver": "^5.3.0",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "^10.1.0",
"dotenv": "^8.2.0",
"eslint": "^6.8.0",
"eslint-config-standard": "^16.0.2",
"eslint-config-vuetify": "^0.6.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.3.1",
"eslint-plugin-standard": "^5.0.0",
"eslint-plugin-vue": "^7.9.0",
"eslint-plugin-vuetify": "^1.0.0-beta.7",
"lodash": "^4.17.21",
"open": "^7.0.3",
"sass": "~1.32.0",
"sass-loader": "^10.0.0",
"shelljs": "^0.8.4",
"vue-cli-plugin-vuetify": "~2.4.2",
"vue-template-compiler": "^2.6.14",
"vuetify-loader": "^1.7.3",
"webfontloader": "^1.6.28",
"webpack": "^5.52.0"
}
}
vue.config.js
const path = require('path')
const PrerenderSPAPlugin = require('@dreysolano/prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
const isDev = process.env.NODE_ENV !== 'production'
const plugins = isDev
? []
: [
new PrerenderSPAPlugin({
// Required - The path to the webpack-outputted app to prerender.
staticDir: path.join(__dirname, 'dist'),
// Optional - The path your rendered app should be output to.
// (Defaults to staticDir.)
// outputDir: path.join(__dirname, 'prerendered'),
// Optional - The location of index.html
indexPath: path.join(__dirname, 'dist', 'index.html'),
// Required - Routes to render.
routes: ['/', '/about', '/description', '/price', '/about'],
// Optional - Allows you to customize the HTML and output path before
// writing the rendered contents to a file.
// renderedRoute can be modified and it or an equivelant should be returned.
// renderedRoute format:
// {
// route: String, // Where the output file will end up (relative to outputDir)
// originalRoute: String, // The route that was passed into the renderer, before redirects.
// html: String, // The rendered HTML for this route.
// outputPath: String // The path the rendered HTML will be written to.
// }
postProcess (renderedRoute) {
// Ignore any redirects.
renderedRoute.route = renderedRoute.originalRoute
// Basic whitespace removal. (Don't use this in production.)
// renderedRoute.html = renderedRoute.html.split(/>[\s]+</gim).join('><');
// Remove /index.html from the output path if the dir name ends with a .html file extension.
// For example: /dist/dir/special.html/index.html -> /dist/dir/special.html
if (renderedRoute.route.endsWith('.html')) {
renderedRoute.outputPath = path.join(
__dirname,
'dist',
renderedRoute.route,
)
}
return renderedRoute
},
// Optional - Uses html-minifier (https://github.com/kangax/html-minifier)
// To minify the resulting HTML.
// Option reference: https://github.com/kangax/html-minifier#options-quick-reference
minify: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
decodeEntities: true,
keepClosingSlash: true,
sortAttributes: true,
},
// Server configuration options.
server: {
// Normally a free port is autodetected, but feel free to set this if needed.
port: 8001,
},
// The actual renderer to use. (Feel free to write your own)
// Available renderers: https://github.com/Tribex/prerenderer/tree/master/renderers
renderer: new Renderer({
// Optional - The name of the property to add to the window object with the contents of `inject`.
injectProperty: '__PRERENDER_INJECTED',
// Optional - Any values you'd like your app to have access to via `window.injectProperty`.
inject: {
foo: 'bar',
prerender: false,
},
// Optional - defaults to 0, no limit.
// Routes are rendered asynchronously.
// Use this to limit the number of routes rendered in parallel.
maxConcurrentRoutes: 4,
// Optional - Wait to render until the specified event is dispatched on the document.
// eg, with `document.dispatchEvent(new Event('custom-render-trigger'))`
// renderAfterDocumentEvent: 'custom-render-trigger',
// Optional - Wait to render until the specified element is detected using `document.querySelector`
renderAfterElementExists: '#app',
// Optional - Wait to render until a certain amount of time has passed.
// NOT RECOMMENDED
renderAfterTime: 5000, // Wait 5 seconds.
// Other puppeteer options.
// (See here: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions)
headless: true, // Display the browser window when rendering. Useful for debugging.
}),
}),
]
module.exports = {
devServer: {
disableHostCheck: true,
progress: false,
before () { // Output the same message as the react dev server to get the Spa middleware working with vue.
console.info('Starting the development server...')
},
},
transpileDependencies: ['vuetify'],
configureWebpack: {
plugins: [...plugins],
},
}