【澳门葡京】品种架构划设想计与工程化实践

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

2018/07/25 · JavaScript
· Vue

初稿出处: Berwin   

文中会讲述自个儿从0~1搭建二个上下端分离的vue项目详细经过

Feature:

  • 一套很实用的架构设计
  • 因此 cli 工具生成新品类
  • 经过 cli 工具开首化配置文件
  • 编写翻译源码与机动上传CDN
  • Mock 数据
  • 反向检查和测试server api接口是或不是符合预期

前段时间我们导航在支付一款新的成品,名叫
快言,是1个大旨词社区,具体这么些产品是干吗的就不实行讲了,有趣味的小伙伴能够点进去玩一玩~

以此类其他1.0乞讨的人版上线后,必要1个管制类别来治本这一个产品,这一个时候笔者手里快言项指标功用已经上线,暂前卫未任何急需成本的效应,所以自身跑去找小编相当把后台这一个类型给拿下了。

.

|–
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                         // ES6语法编写翻译配置

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

|–
.gitignore                       // git上传必要忽略的文件格式

|–
README.md                        //
项目表明

|–
favicon.ico

|–
index.html                       //
入口页面

|–
package.json                     //
项目基本消息

 

 

  一、   下载包:

 

  一、   下载包:

    从Ueditor的官网下载1.4.3.3jsp本子的Ueditor编辑器,官网地址为:

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

     下载解压后会得到假诺下文件目录:

       澳门葡京 1

 

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

 

  二、   修改配置

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

 

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

        window.UEDITOR_HOME_URL = “/static/Ueditor/”

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

 

 

  三、   文件的引入

    在vue项目标入口文件main.js中校Ueditor全数的基本功文件引入如下:(路径自行配制)

 

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

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

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

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

 

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

 

    <template>

    <div>

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

    <divid=”editor”></div>

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

    </div>

    </template>

    <script>

    exportdefault {

            data() {

        return {

                    editor: null,

               }

          },

          mounted() {

      // 实例化editor编辑器

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

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

          },

          methods: {

              gettext() {

      // 获取editor中的文本

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

              }

          },

        destroyed() {

  // 将editor实行销毁

  this.editor.destroy();

          }

      }

 </script>

  五、   推行上述代码大概会冒出的题材

  1. 1.   出现如下报错

   澳门葡京 2

 

  现身此种现象的原由是配置ueditor的图纸以及文件的后台上传递口不得法;

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

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

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

  现在将不会再出现上述报错,但是也将不也许进展图纸的上传:如下图:

 澳门葡京 3

   

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

  // 服务器统一请求接口路径,配置的服务端接口

          serverUrl: “”,

  //可能假若应用了代办,则能够如下进行配置

          serverUrl: “/api/ue”,

 

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

    首先下载编辑器包

    npm install –save-dev ueditor

 

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

     澳门葡京 4

 

 

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

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

  开发接口

  //加载ueditor 模块

  var ueditor = require(“ueditor”);

  //使用模块

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

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

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

  var foo = req.ueditor;

 

  var imgname = req.ueditor.filename;

 

  var img_url = ‘/ueditor’;

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

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

    }

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

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

  var dir_url = ‘/ueditor’;

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

      }

  // 客户端发起其余请求

  else {

          console.log(‘config.json’)

 

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

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

    }

}));

 

 

  注:

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

  上述接口中img_url的’/ueditor’和res.redirect的’/ueditor/nodejs/config.js’配置都以使用的express静态文件服务对图片存款和储蓄路径和图纸默许配置文件的囤积和呼吁;

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

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

  ’/ueditor’: {

    //后台接口地址

                target: ”,

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

                changeOrigin: true,

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

                pathRewrite: {

      ’^/ueditor’: ‘/ueditor’

                }

            }

技术选型

收到那一个职责后,作者第贰考虑那几个项目然后会变得分外复杂,功效会杰出多。所以须求精心设计项目架构和开发流程,保障项目中期复杂度越来越高的时候,代码可维护性依旧维持最初的气象

后台项目须要反复的出殡和埋葬请求,操作dom,以及维护各样景况,所以作者要求先为项目选取一款适合的mvvm框架,综合考虑最终项目框架选用使用
Vue,原因是:

  • 左边简单,团队新人能够很不难就到场到那么些类型中开始展览付出,对开发者水平须要较低(毕竟是团队项目,门槛低自身认为十一分重要)
  • 自个儿个人我对Vue还算相比较纯熟,一年前2.0还没宣布的时候阅读过vue
    1.x的源码,对vue的规律有打探,项目支出中相遇的保有标题笔者都有信心能消除掉
  • 调查研讨了我们团队的分子,超越三分一都利用过vue,对vue多少都有过支付经历,并且此前协会内也用vue开发过局地档次

之所以最终摘取了Vue

主要文件package.json

ackage.json文件是项目根目录下的2个文本,定义该品种支付所急需的种种模块以及部分品类配置音讯(如项目名称、版本、描述、小编等)。

package.json
里的scripts字段,那一个字段定义了你能够用npm运维的吩咐。在支付环境下,在命令行工具中运作npm
run dev 就相当于履行 node build/dev-server.js
 .也正是开启了3个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.3.3jsp版本的Ueditor编辑器,官网地址为:

分选vue周边正视(全家桶)

框架定了Vue 后,接下去本身索要选择部分vue套餐来支援开发,笔者选拔的套餐有:

  • vuex – 项目复杂后,使用vuex来管理境况必不可少
  • element-ui – 基于vue2.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/

架构划设想计

在付出这几个类型前,作者去参预了京城的首届 vueconf
大会,个中有一个宗旨是阴明讲的《丹佛掘金队 Vue.js 2.0
后端渲染及重构实践》,讲了掘金队(Denver Nuggets)重构后的架构划设想计,作者以为她们的架构划设想计的挺不错,所以参考丹佛掘金(Denver Nuggets)的架构,设计了2个更切合大家本身事情场景的架构

dev-server.js

     下载解压后会得到假使下文件目录:

完整架构图

澳门葡京 5

// 检查 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’)

 

// 2个能够强制打开浏览器并跳转到钦点 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 运转1个劳动

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)

  }

})

 

 

 

       澳门葡京 6

目录结构

. ├── 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文件夹中,此文件夹为项指标静态服务文件夹;

业务层

  • service/ – 处理服务端重返的数码(类似data format),例如 service
    同时调用了分化的api,把不相同的回到数据整合在联合署名在统一发送到 store 中

 

API 层

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

  二、   修改配置

util 层

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

  • 借使前期项目必要,例如须要写一些vue自定义的吩咐,能够在这一个依据要求活动成立目录,也属于util层

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

基本功设备层

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

 

大局事件机制

  • event-bus/ – 主要用来处理12分要求

关于这一层作者想详细说一下,这一层最初阶作者以为没什么用,并且那几个事物很凶险,新手操作不当很不难出bug,所以就没加,后来有贰个要求正好用到了自身才精晓event-bus是用来干什么的

event-bus
我不推荐在事情中选取,在事情中运用那种全局的轩然大波机制格外不难出bug,而且多数必要通过vuex维护状态就能消除,那event-bus 是用来干什么的啊?

用来处理十分须要的,,,,那怎么是分歧平常供给呢,小编说一下大家在什么地点用到了event-bus

场景:

我们的类别是纯前端项目,又是个管理种类,所以登陆功效就比较神奇

澳门葡京 7

上边是登陆的欧洲经济共同体流程图,关于登陆前端须求做几个业务:

  1. 监听全体api的响应,借使未登录后端会再次来到贰个错误码
  2. 只要后端再次回到3个未登录的错误码,前端需求跳转到公司统一的登陆宗旨去登陆,登陆成功后会跳转回当前地点并在url上带走sid
  3. 监听全数路由,即使发现路由上带有sid,表明是从登陆中央跳过来的,用这些sid去央浼一下用户消息
  4. 登陆成功并获得用户消息

透过地点一多级的登陆流程,最后的结果是登陆之后会得到三个用户音讯,这一个获得用户音讯的操作是在router里发起的推行,那么难点就来了,router中获得了用户音信笔者希望把这一个用户消息放到store里,因为在router中拿不到vue实例,不能够直接操作vuex的办法,这几个时候假诺没有
event-bus 就很难操作。

为此普通 event-bus
大家都会用在表现层下边包车型大巴任何层级(没有vue实例)之间通讯,而且需求求很明白本身在做哪些

缘何 event-bus
很简单出题目?好像它正是二个常见的风浪机制而已,为啥那么危险?

那是个好难点,笔者说一下小编早已蒙受的二个题材。先描述八个很简短的业务场景:“进入三个页面然后加载列表,然后点击了翻页,重新拉取一下列表”

用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
里这样多重复的伸手?点了2遍翻页怎么发了这么八个 fetchList
的乞求???什么处境????

那边有3个新手很简单忽视的题材,即就是经历非凡丰盛的人也会在不留心的事态犯错,那就是生命周期区别台的难题,event-bus
的扬言周期是全局的,唯有在页面刷新的时候 event-bus
才会重置内部境况,而组件的宣示周期相对来说就短了累累
,所以地方的代码当自身进入这么些组件然后又销毁了这么些组件然后又进入这一个组件反复五遍之后就会在
event-bus 中监听了好多个 word:refreshList
事件,每趟触发事件实际上都会有不可胜举个函数在实施,所以才会在 network
中窥见N八个一律的伸手。

为此发现那么些bug之后赶紧加了几行代码把这些标题修复了:

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

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

自从出了那一个题材今后,小编就像与自个儿联合开发后台的同伙说了这么些事,提议全数工作须要无限不要在行使event-bus了,除非很领悟的领悟本人正值干什么。

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

布告上线

类型框架结构搭建好了未来一度能够早先写作业了,所以本身天天的白昼是在开发业务职能,早上和星期天的光阴用来开发编写翻译上线的机能

        window.UEDITOR_HOME_URL = “/static/Ueditor/”

编写翻译源码

前面说了我们的种类是纯前端工程,所以希望是编写翻译出二个无任何借助的纯html文件

澳门葡京 8

在行使 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
以本人的明亮它是2个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 图片的时候,得到的正是2个cdn的地点~

可是作者不想在支付环境也上传cdn,笔者盼望唯有在转变环境才用那些loader,所以自个儿设置了2个
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();

颁发上线

我们部门有本身的公布上线的工具叫 hera
能够把代码公布到docker机上开始展览编写翻译,然后把编写翻译后的纯html文件表露到事先安插好的服务器的钦点目录中

编写翻译的流水生产线是先把代码发表到编写翻译机上 -> 编写翻译机运维 docker
(docker能够保证编译环境一致) -> 在 docker 中执行 npm install
安装重视 -> 执行 npm run build 编写翻译 -> 把编写翻译后的 html
发送到服务器

因为每趟编写翻译都急需设置依赖,速度特别慢,所以大家有三个 diffinstall
的逻辑,每一回安装重视都会实行三遍diff,把有缓存的平昔用缓存copy到node_modules,没缓存的运用qnpm安装,之后会把此次新装置的依靠缓存一份。依赖缓存了之后每一趟安装正视速度显然快了许多。

现行反革命项目曾经足以健康花费和上线啦~

 

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-999999’: 1, ‘size|0-999999’:
1 } }, ‘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(…)

设想到出色景况,也并不是挟持必须那样使用,我要么抛出了3个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
屏蔽掉,并从未入到版本库中,所以就推动了2个题材,每便有新人进入到这么些项目,在第②次搭建项目标时候,总是要手动成立三个dev.conf 文件,作者梦想能自动成立布局文件

正要以前作者写了三个好像于 vue-cli 的工具
speike-cli,也是透过沙盘生成项指标1个工具,所以那一回正好派上用场,笔者把陈设文件定义了多个模板,然后接纳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"
  }
}

澳门葡京 9

  三、   文本的引入

开始化项目

此次该有的都有了,能够愉悦的写码了,为了现在有像样的管制种类创立项目便利,作者把本次精心设计的架构,编译逻辑等定制成了模版,日后得以一直利用speike
接纳那个模板来扭转项目。

澳门葡京 10

    在vue项指标入口文件main.js准将Ueditor全部的底蕴文件引入如下:(路径自行配制)

重新整建与总计

经过地点一多种做的事,最终整理一下类型工程化的生命周期

澳门葡京 11

摸底越来越多能够看笔者写过的
PPT

1 赞 收藏
评论

澳门葡京 12

 

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

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

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

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

 

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

 

    <template>

    <div>

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

    <divid=”editor”></div>

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

    </div>

    </template>

    <script>

    exportdefault {

            data() {

        return {

                    editor: null,

               }

          },

          mounted() {

      // 实例化editor编辑器

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

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

          },

          methods: {

              gettext() {

      // 获取editor中的文本

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

              }

          },

        destroyed() {

  // 将editor进行销毁

  this.editor.destroy();

          }

      }

 </script>

  五、   履行上述代码只怕会并发的标题

  1. 1.   出现如下报错

   澳门葡京 13

 

  出现此种现象的因由是配置ueditor的图样以及文件的后台上传递口不得法;

  假设Ueditor不须要采取文件以及图片的上传则在ueditor.config.js中实行如下配置:(将serverUrl注释掉)

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

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

  现在将不会再冒出上述报错,然则也将不可能展开图片的上传:如下图:

 澳门葡京 14

   

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

  // 服务器统一请求接口路径,配置的服务端接口

          serverUrl: “”,

  //或然假使运用了代理,则足以如下举办安排

          serverUrl: “/api/ue”,

 

  六、   假如利用的是node的express做服务端,接口开发如下

    首先下载编辑器包

    npm install –save-dev ueditor

 

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

     澳门葡京 15

 

 

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

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

  开发接口

  //加载ueditor 模块

  var ueditor = require(“ueditor”);

  //使用模块

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

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

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

  var foo = req.ueditor;

 

  var imgname = req.ueditor.filename;

 

  var img_url = ‘/ueditor’;

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

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

    }

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

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

  var dir_url = ‘/ueditor’;

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

      }

  // 客户端发起别的请求

  else {

          console.log(‘config.json’)

 

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

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

    }

}));

 

 

  注:

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

  上述接口中img_url的’/ueditor’和res.redirect的’/ueditor/nodejs/config.js’配置都是行使的express静态文件服务对图纸存款和储蓄路径和图纸私下认可配置文件的储存和请求;

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

  // 配置ueditor的图形上传服务器预览路径

  ’/ueditor’: {

    //后台接口地址

                target: ”,

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

                changeOrigin: true,

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

                pathRewrite: {

      ’^/ueditor’: ‘/ueditor’

                }

            }

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website