品种架构设计与工程化施行

Vue 项目架构划设想计与工程化实施

2018/07/25 · JavaScript
· Vue

初稿出处: Berwin   

文中会讲述自身从0~壹搭建一个前后端分离的vue项目详细进程

Feature:

  • 壹套很实用的架构划设想计
  • 因此 cli 工具生成新品类
  • 透过 cli 工具开端化配置文件
  • 编写翻译源码与机关上传CDN
  • Mock 数据
  • 反向检查评定server api接口是或不是符合预期

前些日子大家导航在支付1款新的出品,名为
快言,是1个宗旨词社区,具体那几个产品是干吗的就不开始展览讲了,有意思味的伴儿能够点进入玩壹玩~

本条类型的一.0叫化子版上线后,要求三个管理体系来保管这些产品,那个时候小编手里快言项目标功效已经上线,目前并未有别的急需付出的功效,所以自身跑去找笔者相当把后台这一个类型给拿下了。

.

|–
build                            //
项目营造(webpack)相关代码

|   |– build.js                     //
生产条件创设代码

|   |– check-version.js             // 检查node、npm等版本

|   |– dev-client.js                //
热重载相关

|   |– dev-server.js                //
创设地面服务器

|   |– utils.js                     //
创设筑工程具相关

|   |– webpack.base.conf.js         // webpack基础配置

|   |– webpack.dev.conf.js          // webpack开荒条件陈设

|   |– webpack.prod.conf.js         // webpack生产条件布署

|–
config                           //
项目支出条件安排

|   |– dev.env.js                   //
开垦情形变量

|   |– index.js                     //
项目部分配备变量

|   |– prod.env.js                  //
生产蒙受变量

|   |– test.env.js                  //
测试情况变量

|–
src                              //
源码目录

|   |– components                    
//
vue公共组件

|   |– store                          // vuex的动静管理

|   |– App.vue                        //
页面入口文件

|   |– main.js                        //
程序入口文件,加载种种公共组件

|–
static                           //
静态文件,比方一些图片,json数据等

|   |– data                          
//
群聊分析获得的多寡用于数据可视化

|–
.babelrc                         // ES陆语法编写翻译配置

|–
.editorconfig                    //
定义代码格式

|–
.gitignore                       // git上传须求忽略的文件格式

|–
README.md                        //
项目说明

|–
favicon.ico

|–
index.html                       //
入口页面

|–
package.json                     //
项目基本新闻

 

 

  一、   下载包:

  一、   下载包:

才具选型

收受那几个职责后,笔者首先牵记这么些种类然后会变得十分复杂,作用会非凡多。所以供给精心设计项目框架结构和支付流程,保证项目中期复杂度更高的时候,代码可维护性依然保持最初的景观

后台项目须求反复的出殡和埋葬请求,操作dom,以及保证各个场地,所以笔者急需先为项目选取1款适合的mvvm框架,综合思索最终项目框架选用采取Vue,原因是:

  • 左侧轻巧,团队新人能够很轻便就参与到这些体系中开始展览付出,对开垦者水平供给异常的低(毕竟是团体项目,门槛低自个儿感觉十分首要)
  • 自己个人笔者对Vue还算相比较纯熟,一年前二.0还没发表的时候阅读过vue
    1.x的源码,对vue的法则有询问,项目支付中碰着的富不不奇怪小编都有信念能一举成功掉
  • 调查研商了我们团队的分子,超越二分一都施用过vue,对vue多少都有过支付经历,并且在此以前组织内也用vue开采过部分项目

故而最后摘取了Vue

主要文件package.json

ackage.json文件是项目根目录下的1个文件,定义该项目开拓所必要的种种模块以及一些档期的顺序布署音讯(如项目名称、版本、描述、小编等)。

package.json
里的scripts字段,那一个字段定义了你能够用npm运营的一声令下。在付出条件下,在命令行工具中运作npm
run dev 就也就是施行 node build/dev-server.js
 .也等于展开了叁个node写的开垦行提议服务器。由此能够看到script字段是用来内定npm相关命令的缩写。

  “scripts”: {

    “dev”: “node
build/dev-server.js”,

    “build”: “node
build/build.js”

  },

 

dependencies字段和devDependencies字段

  • dependencies字段指项目周转时所依靠的模块;
  • devDependencies字段钦赐了等级次序支出时所依附的模块;

在指令行中运转npm
install命令,会自动安装dependencies和dev德姆pendencies字段中的模块。package.json还有繁多有关计划

    从Ueditor的官方网站下载1.4.三.三jsp版本的Ueditor编辑器,官方网站地址为:

    从Ueditor的官方网站下载一.四.3.3jsp版本的Ueditor编辑器,官方网址地址为:

选择vue相近正视(全家桶)

框架定了Vue 后,接下去自身急需采取部分vue套餐来援助开采,小编选取的套餐有:

  • vuex – 项目复杂后,使用vuex来保管情状不能缺少
  • element-ui – 基于vue二.0
    的机件库,饿了么的那套组件库还挺好用的,成效也全
  • vue-router –
    单页应用不可或缺须要利用前端路由(这种管理种类万分适合单页应用,系统不时索要反复的切换页面,使用单页应用可以异常高效的切换页面而且数量也是按需加载,不会再次加载正视)
  • axios – vue 官方推荐的http客户端
  • vue-cli 的 webpack 模板,那套模板是意义最全的,有hot
    reload,linting,testing,css extraction 等成效

webpack配置相关

我们在上头说了运行npm run dev 就一定于实践了node
build/dev-server.js,表达这些文件十三分紧要,先来谙习一下它。 

      http://ueditor.baidu.com/website/

      http://ueditor.baidu.com/website/

架构划设想计

在开辟这几个项目前,笔者去参预了首都的第陆届 vueconf
大会,个中有四个主题是阴明讲的《丹佛掘金队(Denver Nuggets) Vue.js 2.0
后端渲染及重构推行》,讲了掘金队(Denver Nuggets)重构后的框架结构划设想计,小编认为她们的架构划设想计的挺不错,所以参考掘金队的架构,设计了二个更合乎大家温馨事情场景的架构

dev-server.js

     下载解压后会获得即使下文件目录:

     下载解压后会获得如若下文件目录:

壹体化框架结构图

亚洲必赢官网 1

// 检查 Node 和 npm 版本

require(‘./check-versions’)()

 

// 获取 config/index.js 的默许配置

var config = require(‘../config’)

 

// 如若 Node 的意况一点都不大概判断当前是 dev / product
意况

// 使用 config.dev.env.NODE_ENV
作为当下的条件

 

if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)

 

// 使用 NodeJS 自带的公文路线工具

var path = require(‘path’)

 

// 使用 express

var express = require(‘express’)

 

// 使用 webpack

var webpack = require(‘webpack’)

 

// 八个得以强制展开浏览器并跳转到钦赐 url
的插件

品种架构设计与工程化施行。var opn = require(‘opn’)

 

// 使用 proxyTable

var proxyMiddleware = require(‘http-proxy-middleware’)

 

// 使用 dev 环境的 webpack 配置

var webpackConfig = require(‘./webpack.dev.conf’)

 

// default port where dev server listens for
incoming traffic

 

// 假设没有点名运营端口,使用 config.dev.port
作为运转端口

var port = process.env.PORT || config.dev.port

 

// Define HTTP proxies to your custom API
backend

//

 

// 使用 config.dev.proxyTable 的安排作为
proxyTable 的代办配置

var proxyTable = config.dev.proxyTable

 

// 使用 express 运行一个服务

var app = express()

 

// 运行 webpack 进行编写翻译

var compiler = webpack(webpackConfig)

 

// 运行 webpack-dev-middleware,将
编写翻译后的公文暂存到内部存款和储蓄器中

var devMiddleware = require(‘webpack-dev-middleware’)(compiler, {

  publicPath: webpackConfig.output.publicPath,

  stats: {

    colors: true,

    chunks: false

  }

})

 

// 运营 webpack-hot-middleware,也等于我们常说的
Hot-reload

var hotMiddleware = require(‘webpack-hot-middleware’)(compiler)

// force page reload when html-webpack-plugin
template changes

compiler.plugin(‘compilation’, function
(compilation) {

  compilation.plugin(‘html-webpack-plugin-after-emit’, function (data, cb)
{

    hotMiddleware.publish({
action: ‘reload’
})

    cb()

  })

})

 

// proxy api requests

// 将 proxyTable 中的请求配置挂在到运转的 express
服务上

Object.keys(proxyTable).forEach(function (context)
{

  var options
= proxyTable[context]

  if (typeof options === ‘string’) {

    options = { target:
options }

  }

  app.use(proxyMiddleware(context, options))

})

 

// handle fallback for HTML5 history API

// 使用 connect-history-api-fallback
相配财富,借使不相配就足以重定向到钦定地址

app.use(require(‘connect-history-api-fallback’)())

 

// serve webpack bundle output

// 将暂存到内部存款和储蓄器中的 webpack 编写翻译后的文书挂在到
express 服务上

app.use(devMiddleware)

 

// enable hot-reload and state-preserving

// compilation error display

// 将 Hot-reload 挂在到 express 服务上

app.use(hotMiddleware)

 

// serve pure static assets

// 拼接 static 文件夹的静态财富路线

var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)

// 为静态能源提供响应服务

app.use(staticPath, express.static(‘./static’))

 

// 让我们以此 express 服务监听 port
的央浼,并且将此服务作为 dev-server.js 的接口暴光

module.exports = app.listen(port,
function (err) {

  if (err)
{

    console.log(err)

    return

  }

  var uri
= ‘:’ + port

  console.log(‘Listening at ‘ + uri + ‘\n’)

 

  // when env is testing,
don’t need open it

  //
倘使不是测试意况,自动张开浏览器并跳到大家的支付地址

  if (process.env.NODE_ENV !== ‘testing’) {

    opn(uri)

  }

})

 

 

 

       亚洲必赢官网 2

       亚洲必赢官网 3

目录结构

. ├── README.md ├── build # build 脚本 ├── config # prod/dev build
config 文件 ├── hera # 代码发布上线 ├── index.html # 最基础的网页 ├──
package.json ├── src # Vue.js 大旨业务 │ ├── App.vue # App Root
Component │ ├── api # 接入后端服务的根基 API │ ├── assets # 静态文件 │
├── components # 组件 │ ├── event-bus # 伊芙nt Bus 事件总线,类似
伊芙ntEmitter │ ├── main.js # Vue 入口文件 │ ├── router # 路由 │ ├──
service # 服务 │ ├── store # Vuex 状态管理 │ ├── util # 通用
utility,directive, mixin 还有绑定到 Vue.prototype 的函数 │ └── view #
种种页面 ├── static # DevServer 静态文件 └── test # 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.
├── README.md
├── build                   # build 脚本
├── config                  # prod/dev build config 文件
├── hera                    # 代码发布上线
├── index.html              # 最基础的网页
├── package.json
├── src                     # Vue.js 核心业务
│   ├── App.vue             # App Root Component
│   ├── api                 # 接入后端服务的基础 API
│   ├── assets              # 静态文件
│   ├── components          # 组件
│   ├── event-bus           # Event Bus 事件总线,类似 EventEmitter
│   ├── main.js             # Vue 入口文件
│   ├── router              # 路由
│   ├── service             # 服务
│   ├── store               # Vuex 状态管理
│   ├── util                # 通用 utility,directive, mixin 还有绑定到 Vue.prototype 的函数
│   └── view                # 各个页面
├── static                  # DevServer 静态文件
└── test                    # 测试
 

从目录结构上,能够开掘大家的门类中绝非后端代码,因为咱俩是纯前端工程,整个git货仓皆从前者代码,包含中期发布上线都在此以前者项目独立上线,不借助于后端~

代码宣布上线的时候会先实行编写翻译,编写翻译的结果是1个无别的借助的html文件
index.html,然后把这一个 index.html
发表到服务器上,在编写翻译阶段拥有的依赖性,包罗css,js,图片,字体等都会活动上传到cdn上,最生平成二个无任何借助的纯html,差不多是上边包车型客车样子:

<!DOCTYPE html><html><head><meta
charset=utf-8><title>快言处理后台</title><link
rel=icon href=
href=
rel=stylesheet></head><body><div
id=app></div><script type=text/javascript
src=
type=text/javascript
src=
type=text/javascript
src=;

1
<!DOCTYPE html><html><head><meta charset=utf-8><title>快言管理后台</title><link rel=icon href=https://www.360.cn/favicon.ico><link href=http://s3.qhres.com/static/***.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=http://s2.qhres.com/static/***.js></script><script type=text/javascript src=http://s8.qhres.com/static/***.js></script><script type=text/javascript src=http://s2.qhres.com/static/***.js></script></body></html>

webpack.base.confg.js   webpack的基础配置文件

module.export
= {

    //
编写翻译入口文件

    entry: {},

    //
编写翻译输出路线

    output: {},

    //
一些缓慢解决方案安顿

    resolve: {},

    resolveLoader: {},

    module: {

        //
各个差异品类文件加载器配置

        loaders: {

        …

        …

        //
js文件用babel转码

        {

            test: /\.js$/,

            loader: ‘babel’,

            include: projectRoot,

            //
哪些文件不须求转码

            exclude: /node_modules/

        },

        …

        …

        }

    },

    //
vue文件一些相关陈设

    vue: {}

}

 

 

 

表现层

  • store/ – Vuex 状态管理
  • router/ – 前端路由
  • view/ – 种种业务页面
  • component/ – 通用组件

npm run build      安排   是将Vue网页放到服务器上

咱俩在命令行中输入npm run
build命令后,vue-cli会自动进行项目揭穿打包。你在package.json文件的scripts字段中得以看看,你执行的npm
run build命令就相对推行的 node build/build.js     开采应用           npm
run dev       项目根目录生成了dist文件夹,这几个文件夹里边正是大家要传播服务器上的文本。

dist文件夹下目录包罗:

  • index.html
    主页文件:因为我们开拓的是单页web应用,所以说一般只有一个html文件。
  • static 静态能源文件夹:里边js、CSS和局地图形。

    将上述Ueditor文件夹拷贝到vue项指标static文件夹中,此文件夹为项目标静态服务文件夹;

    将上述Ueditor文件夹拷贝到vue项目标static文件夹中,此文件夹为项目标静态服务文件夹;

业务层

  • service/ – 管理服务端再次来到的数量(类似data format),比方 service
    同时调用了分化的api,把分歧的回来数据整合在联合签字在联合发送到 store 中

 

 

API 层

  • api/ – 请求数据,Mock数据,反向校验后端api

  二、   修改配置

亚洲必赢官网,  二、   修改配置

util 层

  • util/ – 存放项目全局的工具函数

  • 若是早先时期项目必要,比如须求写一些vue自定义的指令,能够在这些依据须求活动创设目录,也属于util层

    在ueditor.config.js中期维修改如下代码:

    在ueditor.config.js中期维修改如下代码:

基本功设备层

  • init – 自动化伊始化配置文件
  • dev – 运行dev-server,hot-reload,http-proxy 等扶助开拓
  • deploy – 编写翻译源码,静态文件上传cdn,生成html,公布上线

 

 

全局事件机制

  • event-bus/ – 重要用来管理相当须求

关于那一层我想详细说一下,那一层最初始作者感到没什么用,并且那一个事物很惊险,新手操作不当很轻巧出bug,所以就没加,后来有3个必要正好用到了本人才精晓event-bus是用来干什么的

event-bus
小编不引入在事情中选择,在事情中运用那种全局的风云机制万分轻巧出bug,而且大好多要求通过vuex维护状态就能解决,那event-bus 是用来干什么的啊?

用来拍卖相当须要的,,,,那什么是分外要求呢,作者说一下我们在如哪里方用到了event-bus

场景:

大家的品类是纯前端项目,又是个管理种类,所以登入功效就比较玄妙

亚洲必赢官网 4

地点是登录的完整流程图,关于登入前端供给做多少个事情:

  1. 监听全部api的响应,要是未登6后端会回来3个错误码
  2. 假若后端重返几个未登入的错误码,前端供给跳转到公司集结的登录主题去登入,登录成功后会跳转回当前地点并在url上指引sid
  3. 监听全部路由,假设发现路由上带有sid,表达是从登入中央跳过来的,用那些sid去哀告一下用户音信
  4. 登入成功并得到用户消息

经过地点一三种的登入流程,最后的结果是登录之后会拿到3个用户音信,这些获得用户新闻的操作是在router里发起的进行,那么难题就来了,router中得到了用户信息我希望把这么些用户新闻放到store里,因为在router中拿不到vue实例,不能间接操作vuex的法子,那个时候借使没有event-bus 就很难操作。

于是平日 event-bus
咱们都会用在突显层上面包车型客车别样层级(未有vue实例)之间通讯,而且必要求很清楚自个儿在做什么

为啥 event-bus
很轻巧出题目?好像它便是三个平淡无奇的事件机制而已,为何那么危急?

那是个好主题素材,笔者说一下自个儿早就碰到的二个主题材料。先描述1个很简短的业务场景:“进入二个页面然后加载列表,然后点击了翻页,重新拉取一下列表”

用event-bus来写的话是这么的:

watch: { ‘$route’ () { EventHub.$emit(‘word:refreshList’) } }, mounted
() { EventBus.$on(‘word:refreshList’, _ => {
this.changeLoadingState(true) .then(this.fetchList)
.then(this.changeLoadingState.bind(this, false))
.catch(this.changeLoadingState.bind(this, false)) })
EventBus.$emit(‘word:refreshList’) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
watch: {
  ‘$route’ () {
    EventHub.$emit(‘word:refreshList’)
  }
},
mounted () {
  EventBus.$on(‘word:refreshList’, _ => {
    this.changeLoadingState(true)
      .then(this.fetchList)
      .then(this.changeLoadingState.bind(this, false))
      .catch(this.changeLoadingState.bind(this, false))
  })
  EventBus.$emit(‘word:refreshList’)
}

watch 路由,点击翻页后触发事件再度拉取一下列表,

功效写完后测试了意识成效都好使,没什么难点就上线了

接下来过了几天偶然二回开掘怎么 network
里如此多重复的央求?点了1次翻页怎么发了如此几个 fetchList
的呼吁???什么状态????

此间有1个新手很轻松忽视的难题,即正是涉世分外丰盛的人也会在不注意的景况犯错,那就是生命周期差别台的标题,event-bus
的评释周期是大局的,唯有在页面刷新的时候 event-bus
才会重新恢复设置内部情况,而组件的扬言周期相对来说就短了过多
,所以地点的代码当本身进入那几个组件然后又销毁了这几个组件然后又进入那个组件反复三回之后就会在
event-bus 中监听了众多个 word:refreshList
事件,每一遍触发事件实际上都会有过三个函数在实行,所以才会在 network
中发觉N五个同样的央浼。

据此开采那一个bug之后不久加了几行代码把这几个主题素材修复了:

destroyed () { EventHub.$off(‘word:refreshList’) }

1
2
3
destroyed () {
  EventHub.$off(‘word:refreshList’)
}

自打出了这一个标题以往,作者就如与自己一块儿开荒后台的伴儿说了这些事,建议具备专业要求Infiniti不用在应用event-bus了,除非很明亮的精晓自身正在干什么。

    // 那里是配置Ueditor内部进行理文件件请求时的静态文件服务地方

    // 那里是配置Ueditor内部开始展览文件请求时的静态文件服务地点

公布上线

种类架构搭建好了现在1度得以起来写作业了,所以本身每日的白昼是在支付业务职能,早上和周3的时间用来支付编写翻译上线的功能

        window.UEDITOR_HOME_URL = “/static/Ueditor/”

        window.UEDITOR_HOME_URL = “/static/Ueditor/”

编写翻译源码

眼下说了我们的品种是纯前端工程,所以希望是编写翻译出1个无其它借助的纯html文件

亚洲必赢官网 5

在动用 vue-cli 发轫化项目的时候,官方的 webpack
模板会把webpack的布署都安装好,项不熟悉成好了随后直接运转 npm run build
就足以编写翻译源码,不过编写翻译出来的html中依赖的js、css是地方的,所以作者今日要做的政工正是想办法把这个编写翻译后的静态文件上传cdn,然后把html中的本地地址替换到上传cdn之后的地方

体系是经过webpack插件 HtmlWebpackPlugin
来生成html的,所以自个儿想以此插件应该会有接口来帮衬本身达成职责,所以本身查看了那一个插件的文档,开掘那么些插件会接触一些风浪,作者感到这个事件应该能够帮忙自身完毕职责,所以自个儿写了demo来尝试一下逐项事件都感到何用的以及有哪些界别,经过尝试开掘了一个轩然大波称为
html-webpack-plugin-alter-asset-tags的轩然大波能够扶持笔者成功职分,所以小编写了下边那样的代码:

var qcdn = require(‘@q/qcdn’) function CdnPlugin (options) {}
CdnPlugin.prototype.apply = function (compiler) {
compiler.plugin(‘compilation’, function(compilation) {
compilation.plugin(‘html-webpack-plugin-alter-asset-tags’,
function(htmlPluginData, callback) { console.log(‘> Static file
uploading cdn…’) var bodys =
htmlPluginData.body.map(upload(compilation, htmlPluginData, ‘body’)) var
heads = htmlPluginData.head.map(upload(compilation, htmlPluginData,
‘head’)) Promise.all(heads.concat(bodys)) .then(function (result) {
console.log(‘> Static file upload cdn done!’) callback(null,
htmlPluginData) }) .catch(callback) }) }) } var extMap = { script: {
ext: ‘js’, src: ‘src’ }, link: { ext: ‘css’, src: ‘href’ }, } function
upload (compilation, htmlPluginData, type) { return function (item, i) {
if (!extMap[item.tagName]) return Promise.resolve() var source =
compilation.assets[item.attributes[extMap[item.tagName].src].replace(/^(/)*/g,
”)].source() return qcdn.content(source, extMap[item.tagName].ext)
.then(function qcdnDone(url) {
htmlPluginData[type][i].attributes[extMap[item.tagName].src] =
url return url }) } } module.exports = CdnPlugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
var qcdn = require(‘@q/qcdn’)
 
function CdnPlugin (options) {}
 
CdnPlugin.prototype.apply = function (compiler) {
  compiler.plugin(‘compilation’, function(compilation) {
    compilation.plugin(‘html-webpack-plugin-alter-asset-tags’, function(htmlPluginData, callback) {
      console.log(‘> Static file uploading cdn…’)
 
      var bodys = htmlPluginData.body.map(upload(compilation, htmlPluginData, ‘body’))
      var heads = htmlPluginData.head.map(upload(compilation, htmlPluginData, ‘head’))
 
      Promise.all(heads.concat(bodys))
        .then(function (result) {
          console.log(‘> Static file upload cdn done!’)
          callback(null, htmlPluginData)
        })
        .catch(callback)
    })
  })
}
 
var extMap = {
  script: {
    ext: ‘js’,
    src: ‘src’
  },
  link: {
    ext: ‘css’,
    src: ‘href’
  },
}
 
function upload (compilation, htmlPluginData, type) {
  return function (item, i) {
    if (!extMap[item.tagName]) return Promise.resolve()
    var source = compilation.assets[item.attributes[extMap[item.tagName].src].replace(/^(/)*/g, ”)].source()
    return qcdn.content(source, extMap[item.tagName].ext)
      .then(function qcdnDone(url) {
        htmlPluginData[type][i].attributes[extMap[item.tagName].src] = url
        return url
      })
  }
}
 
module.exports = CdnPlugin

实际上原理并不复杂,compilation.assets
里保存了文本内容,htmlPluginData 里保存了哪些输出html, 所以从
compilation.assets
中读取到文件内容然后上传CDN,然后用上传后的CDN地址把htmlPluginData
中的本地地址替换掉就行了。

下一场将以此插件加多到build/webpack.prod.conf.js布署文件中。

此地有个关键点是,html中的信赖和静态文件中的信赖是见仁见智的管理方式

如何意思吧,举个例证:

源码编写翻译后生成了多少个静态文件,把这一个静态文件上传到cdn,然后用cdn地址替换掉html里的本地地址(正是地点CdnPlugin刚巧做的政工)

你感到马到成功了? No!No!No!

CdnPlugin
只是把在html中引进的编写翻译后的js,css上传了cdn,可是js,css中引进的图样只怕字体等公事并没上传cdn

假如代码中引进了地面包车型大巴有个别图片或字体,编写翻译后这个地点依然地方的,此时的html是有依据的,是不纯的,要是只把html上线了,代码中依赖的那么些图片和字体在服务器上找不到文件就会有失水准

由此须求先把源码中依据的静态文件(图片,字体等)上传到cdn,然后在把编写翻译后的静态文件(js,css)上传cdn。

代码中依赖的静态文件比如图片,怎么上传cdn呢?

答案是用 loader 来实现,webpack 中的 loader
以自己的敞亮它是3个filter,或者是中间件,总来讲之正是 import
三个文书的时候,那些文件先通过loader
过滤3次,把过滤后的结果回到,过滤的进程能够是 babel
那种编写翻译代码,当然也能够是上传cdn,所以笔者写了上边那样的代码:

var loaderUtils = require(‘loader-utils’) var qcdn = require(‘@q/qcdn’)
module.exports = function(content) { this.cacheable && this.cacheable()
var query = loaderUtils.getOptions(this) || {} if (query.disable) { var
urlLoader = require(‘url-loader’) return urlLoader.call(this, content) }
var callback = this.async() var ext = loaderUtils.interpolateName(this,
‘[ext]’, {content: content}) qcdn.content(content, ext) .then(function
upload(url) { callback(null, ‘module.exports = ‘ + JSON.stringify(url))
}) .catch(callback) } module.exports.raw = true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var loaderUtils = require(‘loader-utils’)
var qcdn = require(‘@q/qcdn’)
 
module.exports = function(content) {
  this.cacheable && this.cacheable()
  var query = loaderUtils.getOptions(this) || {}
 
  if (query.disable) {
    var urlLoader = require(‘url-loader’)
    return urlLoader.call(this, content)
  }
 
  var callback = this.async()
  var ext = loaderUtils.interpolateName(this, ‘[ext]’, {content: content})
 
  qcdn.content(content, ext)
    .then(function upload(url) {
      callback(null, ‘module.exports = ‘ + JSON.stringify(url))
    })
    .catch(callback)
}
 
module.exports.raw = true

其实正是把 content 上传CDN,然后把CDN地址抛出去

有了那些loader 之后,在 import 图片的时候,拿到的正是多个cdn的地址~

不过自个儿不想在开拓条件也上传cdn,小编愿意唯有在变化情形才用这几个loader,所以本人设置了二个
disable 的选项,如果 disabletrue,我使用 url-loader
来管理这几个文件内容。

终极把loader也助长到陈设文件中:

rules: [ …, { test: /.(png|jpe?g|gif|svg)(?.*)?$/, loader:
path.join(__dirname, ‘cdn-loader’), options: { disable: !isProduction,
limit: 10000, name: utils.assetsPath(‘img/[name].[hash:7].[ext]’)
} } ]

1
2
3
4
5
6
7
8
9
10
11
12
rules: [
  …,
  {
    test: /.(png|jpe?g|gif|svg)(?.*)?$/,
    loader: path.join(__dirname, ‘cdn-loader’),
    options: {
      disable: !isProduction,
      limit: 10000,
      name: utils.assetsPath(‘img/[name].[hash:7].[ext]’)
    }
  }
]

写好了 cdn-loadercdn-plugin
之后,已经得以编写翻译出三个无任何借助的纯html,下一步便是把那几个html文件揭橥上线

    var URL = window.UEDITOR_HOME_URL || getUEBasePath();

    var URL = window.UEDITOR_HOME_URL || getUEBasePath();

宣布上线

大家部门有友好的发布上线的工具叫 hera
能够把代码宣布到docker机上举办编写翻译,然后把编写翻译后的纯html文件揭橥到先行布置好的服务器的钦定目录中

编写翻译的流水生产线是先把代码公布到编写翻译机上 -> 编写翻译机运营 docker
(docker可以保证编写翻译意况1致) -> 在 docker 中执行 npm install
安装正视 -> 实行 npm run build 编写翻译 -> 把编写翻译后的 html
发送到服务器

因为老是编写翻译都供给安装依赖,速度相当的慢,所以我们有3个 diffinstall
的逻辑,每一遍安装重视都会议及展览开一遍diff,把有缓存的直接用缓存copy到node_modules,没缓存的运用qnpm安装,之后会把本次新安装的注重缓存1份。正视缓存领悟后每一回安装信赖速度明显快了成都百货上千。

当今项目已经能够不奇怪耗费和上线啦~

 

 

api-proxy

即便品类得以健康耗费了,但本身感到还不够,作者希望项目能够有 mock
数据的功效并且能够检查服务端重临的多寡是不是精确,能够制止因为接口重回数据不准确的主题素材debug好久。

从而作者付出了三个粗略的模块 api-proxy ,便是包装了叁个http
client,能够配备请求音信和Mock
规则,开启Mock的时候利用Mock规则改动Mock数据重返,不开启Mock的时候使用Mock规则来校验接口重临是还是不是合乎预期。

那么 api-proxy 如何使用呢?

比方:

. └── api └── log ├── index.js └── fetchLogs.js

1
2
3
4
5
6
.
└── api
    └── log
        ├── index.js
        └── fetchLogs.js
 

/* * /api/log/fetchLogs.js */ export default { options: { url:
‘/api/operatelog/list’, method: ‘GET’ }, rule: { ‘data’: { ‘list|0-20’:
[{ ‘id|3-7’: ‘1’, ‘path’: ‘/log/opreate’, ‘url’: ‘/operate/log?id=3’,
‘user’: ‘berwin’ }], ‘pageData|7-8’: { ‘cur’: 1, ‘first’: 1, ‘last’: 1,
‘total_pages|0-999999’: 1, ‘total_rows|0-99999玖’: 一, ‘size|0-99999玖’:
壹 } }, ‘errno’: 0, ‘msg’: ‘操作日志列表’ } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
* /api/log/fetchLogs.js
*/
export default {
  options: {
    url: ‘/api/operatelog/list’,
    method: ‘GET’
  },
  rule: {
    ‘data’: {
      ‘list|0-20’: [{
        ‘id|3-7’: ‘1’,
        ‘path’: ‘/log/opreate’,
        ‘url’: ‘/operate/log?id=3’,
        ‘user’: ‘berwin’
      }],
      ‘pageData|7-8’: {
        ‘cur’: 1,
        ‘first’: 1,
        ‘last’: 1,
        ‘total_pages|0-999999’: 1,
        ‘total_rows|0-999999’: 1,
        ‘size|0-999999’: 1
      }
    },
    ‘errno’: 0,
    ‘msg’: ‘操作日志列表’
  }
}

/* * /api/log/index.js */ import proxy from ‘../base.js’ import
fetchLogs from ‘./fetchLogs.js’ export default proxy.api({ fetchLogs })

1
2
3
4
5
6
7
8
9
/*
* /api/log/index.js
*/
import proxy from ‘../base.js’
import fetchLogs from ‘./fetchLogs.js’
 
export default proxy.api({
  fetchLogs
})

使用:

import log from ‘@/api/log’ log.fetchLogs(query) .then(…)

1
2
3
import log from ‘@/api/log’
log.fetchLogs(query)
  .then(…)

设想到新鲜意况,也并不是威胁必须这么使用,小编只怕抛出了一个api方法来供开采者符合规律使用,比如:

// 不使用api-proxy的api import {api} from ‘./base’ export default {
getUserInfo (sid) { return api.get(‘/api/user/getUserInfo’, { params: {
sid } }) } }

1
2
3
4
5
6
7
8
9
10
11
12
// 不使用api-proxy的api
import {api} from ‘./base’
 
export default {
  getUserInfo (sid) {
    return api.get(‘/api/user/getUserInfo’, {
      params: {
        sid
      }
    })
  }
}

这个 api 就是 axios ,并没做怎么着特别管理。

 

 

起初化配置文件

项目支出中会用到有的配备文件,比方开荒情况急需布署一个server地址用来设置api请求的server。开垦遭遇的陈设文件每种人都分裂等,所以作者在
.gitignore 中把那么些dev.conf
屏蔽掉,并不曾入到版本库中,所以就推动了3个难点,每一回有新妇进入到那么些连串,在首先次搭建项目标时候,总是要手动成立贰个dev.conf 文件,小编愿意能自行成立布局文件

刚巧此前小编写了一个好像于 vue-cli 的工具
speike-cli,也是由此沙盘生成项目标一个工具,所以那一次正好派上用场,笔者把布署文件定义了三个模板,然后利用
speike 来生成了二个配备文件

// package.json { “scripts”: { “init”: “speike init ./config/init-tpl
./config/dev.conf” } }

1
2
3
4
5
6
// package.json
{
  "scripts": {
    "init": "speike init ./config/init-tpl ./config/dev.conf"
  }
}

亚洲必赢官网 6

  三、   文本的引进

  三、   文本的引进

起头化项目

此番该有的都有了,能够愉悦的写码了,为了现在有类似的管理连串创建项目便利,小编把这一次精心设计的框架结构,编写翻译逻辑等定制成了模版,日后得以直接使用speike
选拔这一个模板来扭转项目。

亚洲必赢官网 7

    在vue项目标输入文件main.js中将Ueditor全部的底子文件引进如下:(路线自行配制)

    在vue项目的入口文件main.js准将Ueditor全体的根底文件引进如下:(路径自行配制)

重新整建与计算

经过地点1连串做的事,最后整理一下品类工程化的生命周期

亚洲必赢官网 8

摸底愈多能够看自个儿写过的
PPT

1 赞 收藏
评论

亚洲必赢官网 9

 

 

    import’../static/Ueditor/ueditor.config.js’

    import’../static/Ueditor/ueditor.config.js’

    import’../static/Ueditor/ueditor.all.min.js’

    import’../static/Ueditor/ueditor.all.min.js’

    import’../static/Ueditor/lang/zh-cn/zh-cn.js’

    import’../static/Ueditor/lang/zh-cn/zh-cn.js’

    import’../static/Ueditor/ueditor.parse.min.js’

    import’../static/Ueditor/ueditor.parse.min.js’

 

 

  四、   在对应vue的componnent文件中使用富文本编辑器

  四、   在相应vue的componnent文件中选取富文本编辑器

 

 

    <template>

    <template>

    <div>

    <div>

    <!–editor的div为富文本的承载容器–>

    <!–editor的div为富文本的承上启下容器–>

    <divid=”editor”></div>

    <divid=”editor”></div>

    <buttontype=”” @click=”gettext”>点击</button>

    <buttontype=”” @click=”gettext”>点击</button>

    </div>

    </div>

    </template>

    </template>

    <script>

    <script>

    exportdefault {

    exportdefault {

            data() {

            data() {

        return {

        return {

                    editor: null,

                    editor: null,

               }

               }

          },

          },

          mounted() {

          mounted() {

      // 实例化editor编辑器

      // 实例化editor编辑器

      this.editor = UE.getEditor(‘editor’);

      this.editor = UE.getEditor(‘editor’);

      // console.log(this.editor.setContent(“1223”))

      // console.log(this.editor.setContent(“1223”))

          },

          },

          methods: {

          methods: {

              gettext() {

              gettext() {

      // 获取editor中的文本

      // 获取editor中的文本

                  console.log(this.editor.getContent())

                  console.log(this.editor.getContent())

              }

              }

          },

          },

        destroyed() {

        destroyed() {

  // 将editor举办销毁

  // 将editor进行销毁

  this.editor.destroy();

  this.editor.destroy();

          }

          }

      }

      }

 </script>

 </script>

  五、   进行上述代码恐怕会出现的标题

  五、   实行上述代码恐怕会并发的题材

  1. 1.   出现如下报错
  1. 1.   出现如下报错

   亚洲必赢官网 10

   亚洲必赢官网 11

 

 

  出现此种现象的案由是配置ueditor的图纸以及文件的后台上传递口不科学;

  出现此种现象的原委是配置ueditor的图纸以及文件的后台上传递口不精确;

  倘使Ueditor不需求使用文件以及图片的上传则在ueditor.config.js中开始展览如下配置:(将serverUrl注释掉)

  假使Ueditor不需求利用文件以及图片的上传则在ueditor.config.js中展开如下配置:(将serverUrl注释掉)

  // 服务器统一请求接口路线

  // 服务器统一请求接口路线

  // serverUrl: URL + “jsp/controller.jsp”,

  // serverUrl: URL + “jsp/controller.jsp”,

  未来将不会再冒出上述报错,不过也将不能张开图片的上传:如下图:

  未来将不会再冒出上述报错,可是也将不可能进展图纸的上传:如下图:

 亚洲必赢官网 12

 亚洲必赢官网 13

   

   

  假如Ueditor必要运用文件以及图片的上传则在ueditor.config.js中开始展览如下配置:

  若是Ueditor须求利用文件以及图片的上传则在ueditor.config.js中张开如下配置:

  // 服务器统1请求接口路线,配置的服务端接口

  // 服务器统壹请求接口路线,配置的服务端接口

          serverUrl: “”,

          serverUrl: “”,

  //恐怕如果选用了代办,则可以如下实行配备

  //大概若是使用了代理,则足以如下进行布局

          serverUrl: “/api/ue”,

          serverUrl: “/api/ue”,

 

 

  六、   假若运用的是node的express做服务端,接口开垦如下

  六、   假设应用的是node的express做服务端,接口开辟如下

    首先下载编辑器包

    首先下载编辑器包

    npm install –save-dev ueditor

    npm install –save-dev ueditor

 

 

  服务端项目文件中在public中追加如下目录以及文件

  服务端项目文件中在public中加进如下目录以及文件

     亚洲必赢官网 14

     亚洲必赢官网 15

 

 

 

 

    注:ueditor中的images文件夹是上传图片后存款和储蓄的地点

    注:ueditor中的images文件夹是上传图片后存款和储蓄的地点

    nodejs中的config.js便是下载的ueditor包的jsp文件夹下config.json文件

    nodejs中的config.js正是下载的ueditor包的jsp文件夹下config.json文件

  开垦接口

  开拓接口

  //加载ueditor 模块

  //加载ueditor 模块

  var ueditor = require(“ueditor”);

  var ueditor = require(“ueditor”);

  //使用模块

  //使用模块

  app.use(“/api/ue”, ueditor(path.join(__dirname, ‘public’),
function(req, res, next) {

  app.use(“/api/ue”, ueditor(path.join(__dirname, ‘public’),
function(req, res, next) {

  // ueditor 客户发起上传图片请求

  // ueditor 客户发起上传图片请求

  if (req.query.action === ‘uploadimage’) {

  if (req.query.action === ‘uploadimage’) {

  var foo = req.ueditor;

  var foo = req.ueditor;

 

 

  var imgname = req.ueditor.filename;

  var imgname = req.ueditor.filename;

 

 

  var img_url = ‘/ueditor’;

  var img_url = ‘/ueditor’;

          res.ue_up(img_url);
//你假使输入要封存的地址。保存操作交给ueditor来做

          res.ue_up(img_url);
//你若是输入要保留的地方。保存操作交给ueditor来做

          res.setHeader(‘Content-Type’, ‘text/html’);
//IE8下载供给设置重回头尾text/html 不然json重返文件会被直接下载张开

          res.setHeader(‘Content-Type’, ‘text/html’);
//IE八下载供给安装重回头尾text/html 不然json重临文件会被一向下载张开

    }

    }

  //  客户端发起图片列表请求

  //  客户端发起图片列表请求

  elseif (req.query.action === ‘listimage’) {

  elseif (req.query.action === ‘listimage’) {

  var dir_url = ‘/ueditor’;

  var dir_url = ‘/ueditor’;

          res.ue_list(dir_url); // 客户端会列出 dir_url
目录下的保有图片

          res.ue_list(dir_url); // 客户端会列出 dir_url
目录下的具备图片

      }

      }

  // 客户端发起别的请求

  // 客户端发起其余请求

  else {

  else {

          console.log(‘config.json’)

          console.log(‘config.json’)

 

 

        res.setHeader(‘Content-Type’, ‘application/json’);

        res.setHeader(‘Content-Type’, ‘application/json’);

        res.redirect(‘/ueditor/nodejs/config.js’);

        res.redirect(‘/ueditor/nodejs/config.js’);

    }

    }

}));

}));

 

 

 

 

  注:

  注:

  上述接口中的”/api/ue”接口就是陈设在前台项目ueditor.config.js文件中的serverUrl地址;

  上述接口中的”/api/ue”接口正是布局在前台项目ueditor.config.js文件中的serverUrl地址;

  上述接口中img_url的’/ueditor’和res.redirect的’/ueditor/nodejs/config.js’配置都以应用的express静态文件服务对图纸存款和储蓄路线和图表暗中同意配置文件的囤积和伸手;

  上述接口中img_url的’/ueditor’和res.redirect的’/ueditor/nodejs/config.js’配置都以应用的express静态文件服务对图纸存款和储蓄路线和图纸暗许配置文件的囤积和乞求;

  举办上述配置后,一定要在webpack的代办中增多如下代理:

  进行上述配置后,一定要在webpack的代理中增添如下代理:

  // 配置ueditor的图样上传服务器预览路线

  // 配置ueditor的图片上传服务器预览路线

  ’/ueditor’: {

  ’/ueditor’: {

    //后台接口地址

    //后台接口地址

                target: ”,

                target: ”,

    //那里能够效仿服务器举行get和post参数的传递

    //这里能够如法炮征服务器实行get和post参数的传递

                changeOrigin: true,

                changeOrigin: true,

    //前端全部的/ueditor’请求都会呈请到后台的/ueditor’路线之下

    //前端全体的/ueditor’请求都会呈请到后台的/ueditor’路线之下

                pathRewrite: {

                pathRewrite: {

      ’^/ueditor’: ‘/ueditor’

      ’^/ueditor’: ‘/ueditor’

                }

                }

            }

            }

网站地图xml地图