2
0
mirror of https://github.com/tenrok/vue-meta.git synced 2026-06-18 02:20:34 +03:00

feat: make ssr work

feat: update build script

chore: use jiti instead of babel-node for examples
This commit is contained in:
pimlie
2021-01-25 00:50:46 +01:00
parent 2e2c08e1f8
commit 9cfde5b550
37 changed files with 825 additions and 1606 deletions
-42
View File
@@ -1,42 +0,0 @@
# Vue Meta Examples
## Prepare examples
To prepare the examples to run locally, please follow these steps:
```bash
git clone https://github.com/nuxt/vue-meta
cd examples
yarn install
```
## Run the examples
When the examples are installed locally, start the example server as follows
```js
yarn start
// or
HOST=0.0.0.0 PORT=8080 yarn start
```
and browse to `http://localhost:3000` or whatever you changed the host and port to
### SSR Example
The server side rendering example is available on the cli only, to run the SSR example just run
```bash
yarn ssr
```
## Developing
If you would like to use the examples while developing or debugging `vue-meta` features or issues, please do as follows
```js
git clone https://github.com/nuxt/vue-meta
yarn install
cd examples
yarn install
yarn dev
```
+5
View File
@@ -1,3 +1,8 @@
if (!window.users) {
window.users = []
console.warn('window.users was not set')
}
window.users.push({
id: 1,
name: 'Leanne Graham',
+5
View File
@@ -1,3 +1,8 @@
if (!window.users) {
window.users = []
console.warn('window.users was not set')
}
window.users.push({
id: 2,
name: 'Ervin Howell',
+5
View File
@@ -1,3 +1,8 @@
if (!window.users) {
window.users = []
console.warn('window.users was not set')
}
window.users.push({
id: 3,
name: 'Clementine Bauch',
+5
View File
@@ -1,3 +1,8 @@
if (!window.users) {
window.users = []
console.warn('window.users was not set')
}
window.users.push({
id: 4,
name: 'Patricia Lebsack',
+45
View File
@@ -0,0 +1,45 @@
const path = require('path')
const { transformSync } = require('@babel/core')
module.exports = require('jiti')(__filename, {
cache: false,
debug: false,
transform (opts) {
const _opts = {
babelrc: false,
configFile: false,
compact: false,
retainLines: typeof opts.retainLines === 'boolean' ? opts.retainLines : true,
filename: '',
cwd: '/',
plugins: [
[require('@babel/plugin-transform-modules-commonjs'), { allowTopLevelThis: true }],
[require('@babel/plugin-transform-typescript')],
[require('babel-plugin-dynamic-import-node'), { noInterop: true }],
[require('babel-plugin-global-define'), {
__DEV__: true,
__BROWSER__: false
}],
[require('babel-plugin-module-resolver'), {
root: '.',
extensions: ['.ts'],
alias: {
'vue-meta': path.resolve(__dirname, '../src/')
}
}]
]
}
try {
return transformSync(opts.source, _opts).code || ''
} catch (err) {
return 'exports.__JITI_ERROR__ = ' + JSON.stringify({
filename: opts.filename,
line: (err.loc && err.loc.line) || 0,
column: (err.loc && err.loc.column) || 0,
code: err.code && err.code.replace('BABEL_', '').replace('PARSE_ERROR', 'ParseError'),
message: err.message.replace('/: ', '').replace(/\(.+\)\s*$/, '')
})
}
}
})
-76
View File
@@ -1,76 +0,0 @@
const {
baseParse,
transform,
generate,
processIf,
getBaseTransformPreset,
createObjectExpression,
createObjectProperty
} = require('@vue/compiler-core')
const { parse } = require('@vue/compiler-dom')
function headTransform (node, context) {
console.log('NODE', node)
if (node.type === 1 /* NodeTypes.ELEMENT */) {
return () => {
if (!context.parent.codegenNode) {
context.parent.codegenNode = createObjectExpression([])
}
const options = context.parent.codegenNode
const option = createObjectProperty(
node.tag,
node.children.length === 1 ? node.children[0] : 'null'
)
// options.properties.push(option)
}
}
}
module.exports = function (source, map) {
// TODO: add options
const ast = parse(source)
// console.log('AST', ast)
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset({
prefixIdentifiers: true
})
transform(ast, {
prefixIdentifiers: true,
nodeTransforms: [...nodeTransforms, headTransform],
directiveTransforms
})
const result = generate(ast, { mode: 'module' })
console.log(result.code)
this.callback(
null,
`
import { computed } from 'vue'
${result.code}
export default function (component) {
const setup = component.setup
component.setup = function (...args) {
console.log(component)
const __htmlMetaData = computed(() => {
})
return {
...setup.apply(this, args),
__htmlMetaData
}
}
}`,
map
)
/**/
}
+13 -10
View File
@@ -1,17 +1,20 @@
import fs from 'fs'
import path from 'path'
import consola from 'consola'
import express from 'express'
import rewrite from 'express-urlrewrite'
import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import WebpackConfig from './webpack.config'
import { renderPage } from './ssr/server'
const fs = require('fs')
const path = require('path')
const consola = require('consola')
const express = require('express')
const rewrite = require('express-urlrewrite')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackConfig = require('./webpack.config')
const jiti = require('./jiti')
const { renderPage } = jiti('./ssr/server.js')
// const { renderPage } = require('./ssr/server')
const app = express()
app.use(
webpackDevMiddleware(webpack(WebpackConfig), {
webpackDevMiddleware(webpack(webpackConfig(true)), {
publicPath: '/__build__/',
writeToDisk: true,
stats: {
+6 -6
View File
@@ -1,16 +1,16 @@
<!doctype html>
<html {{ htmlAttrs.text(true) }}>
<head {{ headAttrs.text() }}>
{{ head(true) }}
<html {{ htmlAttrs }}>
<head {{ headAttrs }}>
{{ head }}
<link rel="stylesheet" href="/global.css">
</head>
<body {{ bodyAttrs.text() }}>
{{ bodyPrepend(true) }}
<body {{ bodyAttrs }}>
<body-prepend id="body-prepend">{{ bodyPrepend }}</body-prepend>
<a href="/">&larr; Examples index</a>
{{ app }}
<script src="/__build__/ssr.js"></script>
{{ bodyAppend(true) }}
{{ bodyAppend }}
</body>
</html>
+15 -24
View File
@@ -1,8 +1,9 @@
import path from 'path'
import fs from 'fs-extra'
import { createSSRApp } from 'vue'
import { renderToStringWithMeta } from 'vue-meta'
import template from 'lodash/template'
import { renderToString } from '@vue/server-renderer'
import { App, createRouter, metaManager } from '../vue-router/main'
const templateFile = path.resolve(__dirname, 'app.template.html')
@@ -15,41 +16,31 @@ process.server = true
export async function renderPage ({ url }) {
console.log('renderPage', url)
const app = createSSRApp(App)
const router = createRouter('/ssr', true)
app.use(router)
// app.use(metaManager)
app.use(metaManager)
console.log('renderPage', 'push')
await router.push(url.substr(4))
await router.isReady()
console.log('renderPage', 'eady')
/* console.log(router)
const matchedComponents = router.getMatchedComponents()
// no matched routes, reject with 404
if (!matchedComponents.length) {
return reject({ code: 404 })
} */
const appHtml = await renderToString(app)
const [appHtml, ctx] = await renderToStringWithMeta(app)
if (!ctx.teleports) {
ctx.teleports = {}
}
const pageHtml = compiled({
app: appHtml,
htmlAttrs: {
text: () => {}
},
headAttrs: {
text: () => {}
},
bodyAttrs: {
text: () => {}
},
head: () => {},
bodyPrepend: () => {},
bodyAppend: () => {}
// ...app.$meta().inject()
htmlAttrs: ctx.teleports.htmlAttrs || '',
headAttrs: ctx.teleports.headAttrs || '',
bodyAttrs: ctx.teleports.bodyAttrs || '',
head: ctx.teleports.head || '',
bodyPrepend: ctx.teleports['body-prepend'] || '',
bodyAppend: ctx.teleports.body || ''
})
return pageHtml
+14 -11
View File
@@ -29,7 +29,7 @@ export default {
{ tag: 'link', rel: 'stylesheet', href: 'style2.css' }
]
},
body: 'body-script1.js',
body: 'body-script1.js', // TODO: fix
htmlAttrs: {
amp: true,
lang: ['en', 'nl']
@@ -44,7 +44,7 @@ export default {
// TODO { content: 'window.a = "<br/>"; </script><script>alert(\'asdasd\');' },
// TODO { rawContent: 'window.b = "<br/>"; </script><script> alert(\'123321\');' },
{ src: 'body-script2.js', to: 'body' },
{ src: 'body-script3.js', to: '#put-it-here' }
{ src: 'body-script3.js', to: 'body-prepend' }
]
/* esi: {
children: [
@@ -115,20 +115,15 @@ export default {
}
}
setTimeout(() => walk(metadata), 1000) */
return {
metadata
}
},
template: `
<metainfo>
<template v-slot:base="{ content, metainfo }">http://nuxt.dev:3000{{ content }}</template>
/*
<template v-slot:base="{ content, metainfo }">http://nuxt.dev:3000{{ content }}</template>
<template v-slot:title="{ content, metainfo }">{{ content }} - {{ metainfo.description }} - Hello</template>
<template v-slot:og(title)="{ content, metainfo, og }">
{{ content }} - {{ og.description }} - {{ metainfo.description }} - Hello Again
</template>
<!-- // TODO: Using script triggers [Vue warn]: Template compilation error: Tags with side effect (<script> and <style>) are ignored in client component templates. -->
<!-- // TODO: Using script triggers [Vue warn]: Template compilation error: Tags with side effect (<script> and <style>) are i
gnored in client component templates. -->
<component is="script">window.users = []</component>
<component is="script" src="user-1.js"></component>
<component is="script" src="user-2.js"></component>
@@ -147,6 +142,14 @@ export default {
<template v-slot:body>
<component is="script" src="user-4.js"></component>
</template>
*/
return {
metadata
}
},
template: `
<metainfo>
<template v-slot:body><br/></template>
</metainfo>
<div id="app">
+1 -1
View File
@@ -12,9 +12,9 @@
</style>
</head>
<body>
<body-prepend id="body-prepend"></body-prepend>
<a href="/">&larr; Examples index</a>
<div id="app"></div>
<div id="put-it-here"></div>
<script src="/__build__/vue-router.js"></script>
</body>
</html>
+2 -2
View File
@@ -1,6 +1,6 @@
import { h } from 'vue'
import { createRouter as createVueRouter, createMemoryHistory, createWebHistory } from 'vue-router'
import { createManager, defaultConfig, resolveOption, useMeta } from 'vue-meta'
import { createMetaManager, defaultConfig, resolveOption, useMeta } from 'vue-meta'
import App from './App'
import ChildComponent from './Child'
@@ -20,7 +20,7 @@ const decisionMaker5000000 = resolveOption((prevValue, context) => {
}
})
const metaManager = createManager({
const metaManager = createMetaManager({
...defaultConfig,
esi: {
group: true,
+81 -77
View File
@@ -1,89 +1,93 @@
import fs from 'fs'
import path from 'path'
import webpack from 'webpack'
import WebpackBar from 'webpackbar'
import { VueLoaderPlugin } from 'vue-loader'
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const WebpackBar = require('webpackbar')
const { VueLoaderPlugin } = require('vue-loader')
// const srcDir = path.join(__dirname, '..', 'src')
export default {
devtool: 'inline-source-map',
mode: 'development',
entry: fs.readdirSync(__dirname)
.reduce((entries, dir) => {
const fullDir = path.join(__dirname, dir)
module.exports = (isBrowser) => {
const extraAliases = {}
if (isBrowser) {
extraAliases['./ssr$'] = path.resolve(__dirname, '../build/stub.js')
}
if (dir === 'ssr') {
entries[dir] = path.join(fullDir, 'browser.js')
} else if (dir === 'vue-router') {
const possibleEntries = ['browser', 'app']
for (const entryName of possibleEntries) {
const entry = path.join(fullDir, entryName + '.js')
return {
devtool: 'inline-source-map',
mode: 'development',
entry: fs.readdirSync(__dirname)
.reduce((entries, dir) => {
const fullDir = path.join(__dirname, dir)
if (fs.statSync(fullDir).isDirectory() && fs.existsSync(entry)) {
entries[dir] = entry
break
if (dir === 'ssr') {
entries[dir] = path.join(fullDir, 'browser.js')
} else if (dir === 'vue-router') {
const possibleEntries = ['browser', 'app']
for (const entryName of possibleEntries) {
const entry = path.join(fullDir, entryName + '.js')
if (fs.statSync(fullDir).isDirectory() && fs.existsSync(entry)) {
entries[dir] = entry
break
}
}
}
}
return entries
}, {}),
output: {
path: path.join(__dirname, '__build__'),
filename: '[name].js',
chunkFilename: '[id].chunk.js',
publicPath: '/__build__/'
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.vue$/,
use: 'vue-loader'
return entries
}, {}),
output: {
path: path.join(__dirname, '__build__'),
filename: '[name].js',
chunkFilename: '[id].chunk.js',
publicPath: '/__build__/'
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.vue$/,
use: 'vue-loader'
}
]
},
resolve: {
extensions: ['.tsx', 'd.ts', '.ts', '.js', '.vue'],
alias: {
// this isn't technically needed, since the default `vue` entry for bundlers
// is a simple `export * = require(''@vue/runtime-dom`. However having this
// extra re-export somehow causes webpack to always invalidate the module
// on the first HMR update and causes the page to reload.
vue: 'vue/dist/vue.esm-bundler.js',
'vue-meta': path.resolve(__dirname, '../src/'),
...extraAliases
}
]
},
resolve: {
extensions: ['.tsx', 'd.ts', '.ts', '.js', '.vue'],
alias: {
// this isn't technically needed, since the default `vue` entry for bundlers
// is a simple `export * from '@vue/runtime-dom`. However having this
// extra re-export somehow causes webpack to always invalidate the module
// on the first HMR update and causes the page to reload.
vue: 'vue/dist/vue.esm-bundler.js',
'vue-meta': path.resolve(__dirname, '../src/')
},
// Expose __dirname to allow automatically setting basename.
context: __dirname,
node: {
__dirname: true
},
plugins: [
new WebpackBar(),
new VueLoaderPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
__DEV__: JSON.stringify(process.env.NODE_ENV !== 'production'),
__BROWSER__: JSON.stringify(true),
'process.client': JSON.stringify(true),
'process.server': JSON.stringify(false)
})
],
devServer: {
inline: true,
hot: true,
stats: 'minimal',
contentBase: __dirname,
overlay: true
}
},
// Expose __dirname to allow automatically setting basename.
context: __dirname,
node: {
__dirname: true
},
plugins: [
new WebpackBar(),
new VueLoaderPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
__DEV__: JSON.stringify(process.env.NODE_ENV !== 'production'),
__VUE_OPTIONS_API__: JSON.stringify(true),
__VUE_PROD_DEVTOOLS__: JSON.stringify(true)
})
],
devServer: {
inline: true,
hot: true,
stats: 'minimal',
contentBase: __dirname,
overlay: true
}
}