Commit d37ebb43 authored by zhangyanni's avatar zhangyanni

试一下静态化

parent 7770c90e
NODE_ENV="production" NODE_ENV="production"
VUE_APP_URL="prod" VUE_APP_URL="production"
API_ROOT="/" API_ROOT="/"
VUE_APP_UPDATED="12.0.01" VUE_APP_UPDATED="12.0.01"
VUE_APP_UPLOAD_IMG="/base/upload/uploadPicture" VUE_APP_UPLOAD_IMG="/base/upload/uploadPicture"
......
NODE_ENV="development"
VUE_APP_URL="development"
API_ROOT="/"
VUE_APP_UPDATED="12.0.01"
VUE_APP_UPLOAD_IMG="/base/upload/uploadPicture"
VUE_APP_UPLOAD_FILE="/base/upload/uploadFile"
VUE_APP_UPLOAD_LOGO="/base/upload/uploadLogo"
VUE_APP_UPLOAD_FILEIMG="/base/upload/uploadImageOrFile"
NODE_ENV="production" NODE_ENV="production"
VUE_APP_URL="dev" VUE_APP_URL="production"
API_ROOT="/" API_ROOT="/"
VUE_APP_UPDATED="12.0.01" VUE_APP_UPDATED="12.0.01"
VUE_APP_UPLOAD_IMG="/base/upload/uploadPicture" VUE_APP_UPLOAD_IMG="/base/upload/uploadPicture"
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.idea .idea
.idea/* .idea/*
.env*
node_modules node_modules
/node_modules/* /node_modules/*
node_modules/* node_modules/*
......
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "npm run build:server && npm run build:client && npm run service",
"build:client": "cross-env RUN_ENV=client vue-cli-service build",
"build:server": "cross-env RUN_ENV=server vue-cli-service build --mode server",
"service": "node server/index.js",
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build", "build": "vue-cli-service build"
"devbuild": "vue-cli-service build --mode dev",
"lint": "vue-cli-service lint",
"test:unit": "vue-cli-service test:unit"
}, },
"dependencies": { "dependencies": {
"animate.css": "^4.1.0", "animate.css": "^4.1.0",
...@@ -28,17 +29,21 @@ ...@@ -28,17 +29,21 @@
"jquery": "^3.4.1", "jquery": "^3.4.1",
"js-base64": "^2.5.1", "js-base64": "^2.5.1",
"js-md5": "^0.7.3", "js-md5": "^0.7.3",
"koa": "^2.13.1",
"koa-static": "^5.0.0",
"less-loader": "^5.0.0", "less-loader": "^5.0.0",
"lrz": "^4.9.40", "lrz": "^4.9.40",
"mint-ui": "^2.2.13", "mint-ui": "^2.2.13",
"nativeshare": "^2.1.3", "nativeshare": "^2.1.3",
"pdfjs-dist": "^2.4.456", "pdfjs-dist": "^2.4.456",
"portfinder": "^1.0.21", "portfinder": "^1.0.21",
"prerender-spa-plugin": "^3.4.0",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-awesome-swiper": "^3.1.3", "vue-awesome-swiper": "^3.1.3",
"vue-count-to": "^1.0.13", "vue-count-to": "^1.0.13",
"vue-cropper": "^0.5.6", "vue-cropper": "^0.5.6",
"vue-i18n": "^8.14.0", "vue-i18n": "^8.14.0",
"vue-meta-info": "^0.1.7",
"vue-native-share": "^1.0.2", "vue-native-share": "^1.0.2",
"vue-pdf": "^4.0.8", "vue-pdf": "^4.0.8",
"vue-preview": "^1.1.3", "vue-preview": "^1.1.3",
...@@ -49,6 +54,7 @@ ...@@ -49,6 +54,7 @@
"vue-select": "^3.1.0", "vue-select": "^3.1.0",
"vue-video-player": "^5.0.2", "vue-video-player": "^5.0.2",
"vuex": "^3.0.1", "vuex": "^3.0.1",
"vuex-router-sync": "^5.0.0",
"wangeditor": "^3.1.1", "wangeditor": "^3.1.1",
"weixin-js-sdk": "^1.4.0-test" "weixin-js-sdk": "^1.4.0-test"
}, },
...@@ -64,6 +70,7 @@ ...@@ -64,6 +70,7 @@
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.1",
"babel-jest": "^23.6.0", "babel-jest": "^23.6.0",
"babel-plugin-transform-remove-strict-mode": "0.0.2", "babel-plugin-transform-remove-strict-mode": "0.0.2",
"cross-env": "^7.0.3",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0", "eslint-plugin-vue": "^5.0.0",
"html-webpack-plugin": "^4.3.0", "html-webpack-plugin": "^4.3.0",
...@@ -72,7 +79,9 @@ ...@@ -72,7 +79,9 @@
"node-sass": "^4.9.0", "node-sass": "^4.9.0",
"pdfh5": "^1.3.9", "pdfh5": "^1.3.9",
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"vue-server-renderer": "^2.6.12",
"vue-template-compiler": "^2.6.10", "vue-template-compiler": "^2.6.10",
"webpack-node-externals": "^2.5.2",
"weixin-jsapi": "^1.1.0", "weixin-jsapi": "^1.1.0",
"worker-loader": "^2.0.0" "worker-loader": "^2.0.0"
} }
......
const express = require('express');
const fs = require('fs');
const path = require('path');
const { createBundleRenderer } = require('vue-server-renderer');
const app = express();
const serverBundle = require('./dist/vue-ssr-server-bundle.json');
const clientManifest = require('./dist/vue-ssr-client-manifest.json');
const template = fs.readFileSync(path.resolve('./src/index.template.html'), 'utf-8');
const render = createBundleRenderer(serverBundle, {
runInNewContext: false, // 推荐
template, // (可选)页面模板
clientManifest
});
app.use(express.static('./dist',{index:false}))
app.get('*', (req, res) => {
const context = { url: req.url }
// 这里无需传入一个应用程序,因为在执行 bundle 时已经自动创建过。
// 现在我们的服务器与应用程序已经解耦!
render.renderToString(context, (err, html) => {
console.log(html)
// 处理异常……
res.end(html)
})
})
const port = 3003;
app.listen(port, function() {
console.log(`server started at localhost:${port}`);
});
import {createApp} from './main'
const {app, router, store} = createApp()
// 因为可能存在异步组件,所以等待router将所有异步组件加载完毕,服务器端配置也需要此操作
if (window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__);
}
router.onReady(() => {
// 添加路由钩子函数,用于处理 asyncData.
// 在初始路由 resolve 后执行,
// 以便我们不会二次预取(double-fetch)已有的数据。
// 使用 `router.beforeResolve()`,以便确保所有异步组件都 resolve。
router.beforeResolve((to, from, next) => {
const matched = router.getMatchedComponents(to);
const prevMatched = router.getMatchedComponents(from);
// 我们只关心非预渲染的组件
// 所以我们对比它们,找出两个匹配列表的差异组件
let diffed = false;
const activated = matched.filter((c, i) => {
return diffed || (diffed = prevMatched[i] !== c);
});
if (!activated.length) {
return next();
}
// 这里如果有加载指示器 (loading indicator),就触发
Promise.all(
activated.map((c) => {
if (c.asyncData) {
return c.asyncData({store, route: to});
}
})
)
.then(() => {
// 停止加载指示器(loading indicator)
next();
})
.catch(next);
});
app.$mount('#app')
})
\ No newline at end of file
// entry-server.js
import { createApp } from './main'
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
router.push(context.url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
// 对所有匹配的路由组件调用 `asyncData()`
Promise.all(matchedComponents.map(Component => {
if (Component.asyncData) {
return Component.asyncData({
store,
route: router.currentRoute
})
}
})).then(() => {
// 在所有预取钩子(preFetch hook) resolve 后,
// 我们的 store 现在已经填充入渲染应用程序所需的状态。
// 当我们将状态附加到上下文,
// 并且 `template` 选项用于 renderer 时,
// 状态将自动序列化为 `window.__INITIAL_STATE__`,并注入 HTML。
context.state = store.state
resolve(app)
}).catch(reject)
}, reject)
})
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>hshs</title>
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
This diff is collapsed.
...@@ -151,6 +151,11 @@ const router = new Router({ ...@@ -151,6 +151,11 @@ const router = new Router({
mode: 'history', mode: 'history',
routes: [ routes: [
{path: '*', component: notFind}, {path: '*', component: notFind},
{
path: '/test',
name: 'Test',
component: () => import('views/test') // 异步组件
},
{ {
path: '/', path: '/',
name: 'index', name: 'index',
...@@ -2199,4 +2204,7 @@ router.onError((err) => { ...@@ -2199,4 +2204,7 @@ router.onError((err) => {
} }
}) })
// export function createRouter () {
// return router;
// }
export default router; export default router;
\ No newline at end of file
...@@ -227,3 +227,230 @@ export default new Vuex.Store({ ...@@ -227,3 +227,230 @@ export default new Vuex.Store({
} }
} }
}) })
// export default function createStore(){
// return new Vuex.Store({
// state: {
// bigBusinessSearch:new Map(),//大B列表搜索
// bigBusinessPage:new Map(),//大B分页页码
// projectPage:new Map(),//小B分页页码
// searchResultBigBusiness:new Map(),//搜索结果大B分页
// searchResultSmallBusiness:new Map(),//搜索结果小B分页
// searchResult:new Map(),//搜索结果
// projectSearch:new Map(),
// saveSearchResultKeyword:new Map(),//搜索key
// saleManageRequireListSearch:new Map(),//销售维护的需求搜索+分页
// saleManageProjectListSearch:new Map(),//销售对接的项目搜索
// hotCitySelected:new Map(),//热门城市选中字段
// sortCitySelected:new Map(),//排序城市选中字段
// applyListPage:new Map(),//报名列表页码
// applySearchListPage:new Map(),//报名搜索列表页码
// myJoinListPage:new Map(),//我参与的活动页码
// selectSubjectProjectList:new Map(),//项目评审列表页码
// subjectProjectDetailCommentList:new Map(),//项目评审详情评论页码
// currentDetailId:new Map(),//发布需求成功之后获取需求id
// routerToPath:"",
// myPartnerManageListSearch:new Map(),//销售我维护的合作伙伴筛选+分页
// myAuditPartnerManageListSearch:new Map(),//运营验收的合作伙伴筛选+分页
// myBusGoverManageListSearch:new Map(),//销售我维护的大企业机构政府筛选+分页
// myAuditBusGoverManageListSearch:new Map(),//运营验收的大企业机构政府筛选+分页
// },
// mutations: {
// SAVE_LIST_PAGE_PARS:(state,{path,pars})=>{
// state.bigBusinessSearch.set(path,pars);
// },
//
// SAVE_LIST_PAGE_NUM:(state,{path,pars})=>{ //大B记住分页
// state.bigBusinessPage.set(path,pars)
// },
//
// project_PAGE_NUM:(state,{path,pars})=>{ //大B记住分页
// state.projectPage.set(path,pars)
// },
//
// SEARCH_RESULT_BB_PAGE_NUM:(state,{path,pars})=>{ //搜索结果大B分页
// state.searchResultBigBusiness.set(path,pars)
// },
//
// SEARCH_RESULT_SB_PAGE_NUM:(state,{path,pars})=>{ //搜索结果小B分页
// state.searchResultSmallBusiness.set(path,pars)
// },
//
// SEARCH_RESULT:(state,{path,pars})=>{//搜索结果
// state.searchResult.set(path,pars)
// },
//
// SEARCH_RESULT_KEYWORD:(state,{path,pars})=>{//搜索key
// state.saveSearchResultKeyword.set(path,pars)
// },
//
// pro_PARS:(state,{path,pars})=>{
// state.projectSearch.set(path,pars);
// },
//
// //销售维护的需求分页
// saleManageRequireListSearch_Func:(state,{path,pars})=>{
// state.saleManageRequireListSearch.set(path,pars);
// },
//
// //销售对接的项目分页
// saleManageProjectListSearch_Func:(state,{path,pars})=>{
// state.saleManageProjectListSearch.set(path,pars);
// },
// hotCitySelected_Func:(state,{path,pars})=>{
// state.hotCitySelected.set(path,pars);
// },
// sortCitySelected_Func:(state,{path,pars})=>{
// state.sortCitySelected.set(path,pars);
// },
// applyListPage_Func:(state,{path,pars})=>{
// state.applyListPage.set(path,pars);
// },
// applySearchListPage_Func:(state,{path,pars})=>{
// state.applySearchListPage.set(path,pars);
// },
// myJoinListPage_Func:(state,{path,pars})=>{
// state.myJoinListPage.set(path,pars);
// },
//
// selectSubjectProjectList_Func:(state,{path,pars})=>{
// state.selectSubjectProjectList.set(path,pars);
// },
//
// subjectProjectDetailCommentList_Func:(state,{path,pars})=>{
// state.subjectProjectDetailCommentList.set(path,pars);
// },
// currentDetailId_Func:(state,{path,pars})=>{
// state.currentDetailId.set(path,pars);
// },
//
// // 记录要跳转过去的路径
// routerToPathMutation(state, value){
// state.routerToPath = value;
// },
//
// //销售维护的合作伙伴分页
// myPartnerManageListSearch_Func:(state,{path,pars})=>{
// state.myPartnerManageListSearch.set(path,pars);
// },
//
// //运营验收的的合作伙伴分页
// myAuditPartnerManageListSearch_Func:(state,{path,pars})=>{
// state.myAuditPartnerManageListSearch.set(path,pars);
// },
//
// //销售维护的大企业机构政府分页
// myBusGoverManageListSearch_Func:(state,{path,pars})=>{
// state.myBusGoverManageListSearch.set(path,pars);
// },
//
// //运营验收的的大企业机构政府分页
// myAuditBusGoverManageListSearch_Func:(state,{path,pars})=>{
// state.myAuditBusGoverManageListSearch.set(path,pars);
// },
// },
// actions: {
// saveListPagePars: ({ commit },{path,pars}) => {
// commit('SAVE_LIST_PAGE_PARS',{ path,pars });
// },
//
// saveListPageNum: ({ commit },{path,pars}) => {
// commit('SAVE_LIST_PAGE_NUM',{ path,pars });
// },
//
// projectPageNum: ({ commit },{path,pars}) => {
// commit('project_PAGE_NUM',{ path,pars });
// },
// saveSearchResultBBPageNum: ({ commit },{path,pars}) => {
// commit('SEARCH_RESULT_BB_PAGE_NUM',{ path,pars });
// },
//
// saveSearchResultSBPageNum: ({ commit },{path,pars}) => {
// commit('SEARCH_RESULT_SB_PAGE_NUM',{ path,pars });
// },
//
// saveSearchResult: ({ commit },{path,pars}) => {
// commit('SEARCH_RESULT',{ path,pars });
// },
//
// saveSearchResultKeyword: ({ commit },{path,pars}) => {
// commit('SEARCH_RESULT_KEYWORD',{ path,pars });
// },
//
// projectPagePars: ({ commit },{path,pars}) => {
// commit('pro_PARS',{ path,pars });
// },
//
// saleManageRequireListSearchAction: ({ commit },{path,pars}) => {
// commit('saleManageRequireListSearch_Func',{ path,pars });
// },
//
// saleManageProjectListSearchAction: ({ commit },{path,pars}) => {
// commit('saleManageProjectListSearch_Func',{ path,pars });
// },
//
// hotCitySelectedAction:({ commit },{path,pars})=>{
// commit('hotCitySelected_Func',{ path,pars });
//
// },
//
// sortCitySelectedAction:({ commit },{path,pars})=>{
// commit('sortCitySelected_Func',{ path,pars });
//
// },
//
// applyListPageAction:({ commit },{path,pars})=>{
// commit('applyListPage_Func',{ path,pars });
//
// },
// applySearchListPageAction:({ commit },{path,pars})=>{
// commit('applySearchListPage_Func',{ path,pars });
//
// },
// myJoinListPageAction:({ commit },{path,pars})=>{
// commit('myJoinListPage_Func',{ path,pars });
//
// },
//
// selectSubjectProjectListAction:({ commit },{path,pars})=>{
// commit('selectSubjectProjectList_Func',{ path,pars });
// },
//
// subjectProjectDetailCommentListAction:({ commit },{path,pars})=>{
// commit('subjectProjectDetailCommentList_Func',{ path,pars });
// },
//
// currentDetailIdAction:({ commit },{path,pars})=>{
// commit('currentDetailId_Func',{ path,pars });
// },
//
// // 记录要跳转过去的路径
// routerToPathAction(context, value){
// context.commit("routerToPathMutation", value);
// },
//
// myPartnerManageListSearchAction: ({ commit },{path,pars}) => {
// commit('myPartnerManageListSearch_Func',{ path,pars });
// },
//
// myAuditPartnerManageListSearchAction: ({ commit },{path,pars}) => {
// commit('myAuditPartnerManageListSearch_Func',{ path,pars });
// },
//
// myBusGoverManageListSearchAction: ({ commit },{path,pars}) => {
// commit('myBusGoverManageListSearch_Func',{ path,pars });
// },
//
// myAuditBusGoverManageListSearchAction: ({ commit },{path,pars}) => {
// commit('myAuditBusGoverManageListSearch_Func',{ path,pars });
// },
//
//
// },
// getters:{
// routerToPath(state) {
// return state.routerToPath;
// }
// }
// })
// }
...@@ -169,6 +169,16 @@ ...@@ -169,6 +169,16 @@
components:{ components:{
hotArticlepage,VueQRCodeComponent,expertVisible,reporbar,dialogintegralbar hotArticlepage,VueQRCodeComponent,expertVisible,reporbar,dialogintegralbar
}, },
metaInfo() {
return {
title: this.contentData ? this.contentData.contentTitle + "_TechBook" : "",
meta: [
{name: 'description', content: this.contentData ? this.contentData.contentValidity : ""},
{name: 'keywords', content: this.contentData ? this.contentData.contentLabel : ""}
],
}
},
data() { data() {
return { return {
contentData:{ contentData:{
......
<template>
<div>
Just a test page.
<div>
<router-link to="/">Home</router-link>
</div>
<div><h2>{{mode}}</h2></div>
<div><span>{{count}}</span></div>
<div><button @click="count++">+1</button></div>
</div>
</template>
<script>
export default {
data () {
return {
mode: process.env.VUE_ENV === 'server' ? 'server' : 'client',
count: 2
}
}
}
</script>
...@@ -8,9 +8,14 @@ const productionGzipExtensions = ['js', 'css']; ...@@ -8,9 +8,14 @@ const productionGzipExtensions = ['js', 'css'];
const path = require("path"); const path = require("path");
const express = require('express') const express = require('express')
const app = express() const app = express()
const PrerenderSpaPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSpaPlugin.PuppeteerRenderer
var version = require('./public/version') //本地json文件数据 var version = require('./public/version') //本地json文件数据
const VueSSRServerPlugin = require("vue-server-renderer/server-plugin");
const VueSSRClientPlugin = require("vue-server-renderer/client-plugin");
const nodeExternals = require("webpack-node-externals");
const env = process.env;
const isServer = env.RUN_ENV === "server";
var apiRoutes = express.Router(); var apiRoutes = express.Router();
app.use('/api', apiRoutes) app.use('/api', apiRoutes)
function resolve(dir) { function resolve(dir) {
...@@ -28,6 +33,7 @@ module.exports = { ...@@ -28,6 +33,7 @@ module.exports = {
// 例如,如果您的应用程序部署在https://www.foobar.com/my-app/,集baseUrl到'/my-app/'. // 例如,如果您的应用程序部署在https://www.foobar.com/my-app/,集baseUrl到'/my-app/'.
// publicPath : process.env.NODE_ENV === 'production' ? '/' : '/', // publicPath : process.env.NODE_ENV === 'production' ? '/' : '/',
publicPath :'/', publicPath :'/',
// outputDir: `dist/${env.RUN_ENV}`,
// outputDir: 在npm run build时 生成文件的目录 type:string, default:'dist' // outputDir: 在npm run build时 生成文件的目录 type:string, default:'dist'
// outputDir : 'dist', // outputDir : 'dist',
// pages:{ type:Object,Default:undfind } // pages:{ type:Object,Default:undfind }
...@@ -75,7 +81,9 @@ module.exports = { ...@@ -75,7 +81,9 @@ module.exports = {
}, },
configureWebpack: config => { configureWebpack: config => {
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
// config.entry = `./src/entry-${env.RUN_ENV}.js`;
// config.target = isServer ? "node" : "web";
// config.output.libraryTarget = isServer ? "commonjs2" : undefined;
new CompressionWebpackPlugin({ new CompressionWebpackPlugin({
filename: '[path].gz[query]', filename: '[path].gz[query]',
algorithm: 'gzip', algorithm: 'gzip',
...@@ -86,7 +94,6 @@ module.exports = { ...@@ -86,7 +94,6 @@ module.exports = {
}); });
config.output.filename = `js/[name].[chunkhash:8].${process.env.VUE_APP_UPDATED}.js`; config.output.filename = `js/[name].[chunkhash:8].${process.env.VUE_APP_UPDATED}.js`;
config.output.chunkFilename = `js/[name].[chunkhash:8].${process.env.VUE_APP_UPDATED}.js`; config.output.chunkFilename = `js/[name].[chunkhash:8].${process.env.VUE_APP_UPDATED}.js`;
// 为生产环境修改配置... // 为生产环境修改配置...
config.plugins.push( config.plugins.push(
// new CleanWebpackPlugin(['dist']), // new CleanWebpackPlugin(['dist']),
...@@ -94,6 +101,33 @@ module.exports = { ...@@ -94,6 +101,33 @@ module.exports = {
// filename : `css/[name].${process.env.VUE_APP_UPDATED}.css`, // filename : `css/[name].${process.env.VUE_APP_UPDATED}.css`,
// chunkFilename: `css/[name].${process.env.VUE_APP_UPDATED}.css` // chunkFilename: `css/[name].${process.env.VUE_APP_UPDATED}.css`
// } ), // } ),
// new PrerenderSpaPlugin({ //预渲染 处理页面SEO
// staticDir: path.join(__dirname, 'dist'),
// // 需要进行预渲染的路由路径 我这里做的是首页
// routes: ['/articleDetail'], //需要预渲染的路由页面 我这只用了首页
// // html文件压缩
// minify: {
// minifyCSS: true, // css压缩
// removeComments: true // 移除注释
// },
// renderer: new Renderer({
// inject: {},
// // 在 main.js 中 new Vue({ mounted () {document.dispatchEvent(new Event('render-event'))}}),两者的事件名称要对应上。
// renderAfterDocumentEvent: 'render-event',
// // args: ['--no-sandbox', '--disable-setuid-sandbox'],
// })
// // renderer: new PrerenderSpaPlugin.PuppeteerRenderer({//这样写renderAfterTime生效了
// // renderAfterTime: 5000
// // })
// }),
new PrerenderSpaPlugin(
// 生成文件的路径,此处与webpack打包地址一致
path.join(__dirname, 'dist'), //config.build.assetsRoot为vue cli生成的配置,打包后的文件地址
// 配置要做预渲染的路由,只支持h5 history方式
[ '/','/articleDetail']
),
// isServer ? new VueSSRServerPlugin() : new VueSSRClientPlugin(),
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
$:"jquery", $:"jquery",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment