花色架构划设想计与工程化实行

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

2018/07/25 · JavaScript
· Vue

原来的书文出处: Berwin   

文中会讲述自个儿从0~1搭建多少个内外端分离的vue项目详细进度

Feature:

  • 1套很实用的架构划设想计
  • 由此 cli 工具生成新品类
  • 通过 cli 工具开首化配置文件
  • 编写翻译源码与活动上传CDN
  • Mock 数据
  • 反向检查评定server api接口是还是不是吻合预期

下月大家导航在开荒壹款新的成品,名为
快言,是八个宗旨词社区,具体那些产品是干什么的就不开始展览讲了,风乐趣的伙伴能够点进入玩一玩~

其一项目的壹.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                         // ES6语法编写翻译配置

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

|–
.gitignore                       // git上传供给忽略的文件格式

|–
README.md                        //
项目表达

|–
favicon.ico

|–
index.html                       //
入口页面

|–
package.json                     //
项目为主新闻

 

 

  一、   下载包:

 

  一、   下载包:

    从Ueditor的官方网站下载1.四.三.三jsp版本的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,以及体贴种种情况,所以作者索要先为项目选拔1款适合的mvvm框架,综合考虑最终项目框架采纳使用
Vue,原因是:

  • 左边轻易,团队新人能够很轻松就加入到这一个类型中开始展览付出,对开拓者水平需要非常的低(毕竟是团体项目,门槛低自身感到十分关键)
  • 小编个人自个儿对Vue还算相比较熟谙,一年前2.0还没宣布的时候阅读过vue
    一.x的源码,对vue的规律有打探,项目开销中境遇的享有标题本人都有信心能一举成功掉
  • 应用研讨了我们协会的成员,超过十分之五都应用过vue,对vue多少都有过支付经历,并且以前协会内也用vue开辟过部分等级次序

所以最终甄选了Vue

主要文件package.json

ackage.json文件是项目根目录下的三个文书,定义该项目支付所急需的种种模块以及一些连串布局音信(如项目名称、版本、描述、小编等)。

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和devDempendencies字段中的模块。package.json还有为数不少辅车相依安顿

    从Ueditor的官方网站下载1.四.三.叁jsp本子的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/

架构划设想计

在付出这几个类型前,小编去插足了香岛市的第壹届 vueconf
大会,个中有三个宗旨是阴明讲的《丹佛掘金 Vue.js 二.0
后端渲染及重构实施》,讲了丹佛掘金队(Denver Nuggets)重构后的架构划设想计,笔者感到他们的框架结构划设想计的挺不错,所以参考丹佛掘金的框架结构,设计了多个更合乎我们团结事情场景的架构

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’)

 

// 三个足以强制展开浏览器并跳转到钦命 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)

  }

})

 

 

 

       美高梅开户网址 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货仓皆在此以前者代码,包蕴前期公布上线皆在此以前者项目独立上线,不借助于后端~

代码公布上线的时候会先举办编译,编写翻译的结果是3个无别的借助的html文件
index.html,然后把这么些 index.html
宣布到服务器上,在编写翻译阶段具备的信赖,包涵css,js,图片,字体等都会自动上传到cdn上,最一生成叁个无别的借助的纯html,差不离是底下的标准:

<!DOCTYPE html><html><head><meta
charset=utf-捌><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/ – 紧要用于管理格外需求

有关那1层作者想详细说一下,这1层最起先本身以为无妨用,并且那一个事物很危急,菜鸟操作不当很轻便出bug,所以就没加,后来有3个必要正好用到了自家才精晓event-bus是用来干什么的

event-bus
笔者不引入在工作中运用,在事业中运用那种全局的事件机制相当轻松出bug,而且超越四分之二供给通过vuex维护状态就能缓和,那event-bus 是用来干什么的吗?

用来拍卖至极需要的,,,,那什么是例外部须要要吗,作者说一下我们在怎么地点用到了event-bus

场景:

我们的项目是纯前端项目,又是个处理类别,所以登录效率就相比较玄妙

美高梅开户网址 7

地点是登录的全部流程图,关于登入前端需求做几个事情:

  1. 监听全数api的响应,即便未登入后端会回来二个错误码
  2. 要是后端重回1个未登陆的错误码,前端须求跳转到公司会集的登入大旨去登入,登录成功后会跳转回当前地点并在url上引导sid
  3. 监听全体路由,假诺开掘路由上含蓄sid,表达是从登入中心跳过来的,用那么些sid去乞请一下用户消息
  4. 登录成功并得到用户音讯

由此地方一密密麻麻的登入流程,末了的结果是登入之后会得到三个用户音信,这几个得到用户音信的操作是在router里发起的施行,那么难点就来了,router中得到了用户新闻作者盼望把这么些用户消息放到store里,因为在router中拿不到vue实例,无法直接操作vuex的章程,那个时候假若未有event-bus 就很难操作。

由此一般 event-bus
我们都会用在表现层上面包车型大巴任何层级(未有vue实例)之间通讯,而且须要求很了然自个儿在做什么

缘何 event-bus
很轻巧出难题?好像它正是三个一般性的事件机制而已,为什么那么凶险?

那是个好主题材料,小编说一下自个儿早就碰着的1个标题。先描述三个异常粗略的事体场景:“进入3个页面然后加载列表,然后点击了翻页,重新拉取一下列表”

用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 路由,点击翻页后触发事件再一次拉取一下列表,

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

接下来过了几天偶然1遍开掘怎么 network
里那样多种复的伸手?点了三次翻页怎么发了如此三个 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内部进行理文件件请求时的静态文件服务地点

颁发上线

系列架构搭建好了随后已经得以起来写作业了,所以本身每一日的白昼是在付出工作功效,深夜和周天的时间用来支付编写翻译上线的功能

        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
以自己的驾驭它是二个filter,或然是中间件,同理可得就是 import
八个文书的时候,那几个文件先通过loader
过滤一次,把过滤后的结果回到,过滤的经过能够是 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();

表露上线

大家单位有和好的布告上线的工具叫 hera
能够把代码宣布到docker机上开始展览编译,然后把编写翻译后的纯html文件发表到先行安插好的服务器的钦点目录中

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

因为老是编写翻译都要求安装注重,速度尤其慢,所以我们有一个 diffinstall
的逻辑,每一回安装注重都会进展一遍diff,把有缓存的第2手用缓存copy到node_modules,没缓存的采纳qnpm安装,之后会把此次新安装的借助缓存1份。依赖缓存了后来每一回安装正视速度明显快了成都百货上千。

今天项目曾经得以符合规律成本和上线啦~

 

api-proxy

就算品类能够健康开支了,但笔者以为还不够,作者梦想项目得以有 mock
数据的功效并且能够检查服务端再次回到的数额是不是科学,能够制止因为接口重回数据不科学的难题debug好久。

从而本人付出了叁个简单易行的模块 api-proxy ,正是包装了2个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玖’:
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(…)

设想到优秀景况,也并不是挟持必须那样使用,笔者要么抛出了二个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
屏蔽掉,并从未入到版本库中,所以就拉动了多少个主题素材,每一次有新人进入到这一个类型,在第1次搭建项目标时候,总是要手动创设1个dev.conf 文件,小编梦想能自动创设布局文件

刚好从前本身写了3个类似于 vue-cli 的工具
speike-cli,也是经过沙盘生成项目的1个工具,所以那2次正好派上用场,笔者把布置文件定义了八个模板,然后利用
speike 来生成了3个配备文件

// 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全部的根Kevin件引进如下:(路线自行配制)

重新整建与总括

透过地点一密密麻麻做的事,最终整理一下类型工程化的生命周期

美高梅开户网址 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’);
//IE八下载要求安装重返头尾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’

                }

            }

发表评论

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

网站地图xml地图