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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | <?php /** * Created by PhpStorm. * User: LeoKim * Date: 2017/5/13 * Time: 9:10 */ class BaseProcess{ private $process ; private $process_list = []; private $process_use = []; private $min_worker_num = 3; private $max_worker_num = 6; private $current_num ; public function __construct() { $this ->process = new swoole_process( array ( $this , 'run' ), false, 2); $this ->process->start(); swoole_process::wait(); } public function run( $worker ) { $this ->current_num = $this ->min_worker_num; //创建初始进程 for ( $i =0; $i < $this ->current_num; $i ++){ $process = new swoole_process( array ( $this , 'task_run' ), false, 2); $pid = $process ->start(); echo $pid . ': 我被初始创建了.' . date ( 'H:i:s' ).PHP_EOL; $this ->process_list[ $pid ] = $process ; $this ->process_use[ $pid ] = 0; } foreach ( $this ->process_list as $process ){ //pipe管道被读操作的时候执行闭包的function? $this ->bind_set_empty( $process ); } swoole_timer_tick(1000, function ( $timer_id ){ static $index =0; $index = $index +1; $flag = true; //我们在前面定义过 当pid对应的值为0的时候表示该进程现在空闲 foreach ( $this ->process_use as $pid => $used ){ if ( $used == 0){ $flag = false; //我们要使用空闲的进程,把进程标记成工作状态 $this ->process_use[ $pid ] = 1; $this ->process_list[ $pid ]->write( $index . " Hi 我开始工作了." ); break ; } } //如果没有进程是空闲的, 那么检查进程是否超过最大值,没超过的话创建新的进程 if ( $flag && $this ->current_num < $this ->max_worker_num) { $process = new swoole_process( array ( $this , 'task_run' ), false, 2); $pid = $process ->start(); $this ->process_list[ $pid ] = $process ; $this ->process_use[ $pid ] = 1 ; $this ->process_list[ $pid ]->write( $index . " Hi 我是新来的,我开始工作了." ); $this ->current_num++; $this ->bind_set_empty( $process ); } //执行n次退出 if ( $index ==20){ foreach ( $this ->process_list as $process ){ foreach ( $this ->process_list as $process ){ $process ->write( "任务完毕 我退出了." ); } swoole_timer_clear( $timer_id ); $this ->process-> exit (); } } }); } //进程在创建的时候被执行 public function task_run( $worker ) { //为每个进程绑定回调,当进程执行write的时候触发 swoole_event_add( $worker ->pipe, function ( $pipe ) use ( $worker ){ $data = $worker ->read(); var_dump( $worker ->pid. ": " . $data . ' -- ' . date ( 'H:i:s' )); echo PHP_EOL; if ( $data == '任务完毕 我退出了.' ) { $worker -> exit (); exit ; } sleep(5); //当worker进程执行write的时候会出发line:43的回调函数 //把进程标记为空闲 $worker ->write( $worker ->pid); }); } public function bind_set_empty( $worker ){ swoole_event_add( $worker ->pipe, function ( $pipe ) use ( $worker ){ $pid = $worker ->read(); echo $pid . ' 报告,我处理完了之前的任务现在空下来了.' . date ( 'H:i:s' ).PHP_EOL; $this ->process_use[ $pid ] = 0; }); } } new BaseProcess(); |
月度归档: 2017年5月
swoole 简单聊天室
服务端
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 47 48 49 50 51 | <?php /** * Created by PhpStorm. * User: LeoKim * Date: 2017/5/12 * Time: 23:05 */ class Server{ private $serv ; private $test ; public function __construct() { $this ->serv = new swoole_server( "0.0.0.0" , 9502); $this ->serv->set( array ( 'worker_num' => 1, ) ); $this ->serv->on( 'Start' , array ( $this , 'onStart' )); $this ->serv->on( 'Connect' , array ( $this , 'onConnect' )); $this ->serv->on( 'Receive' , array ( $this , 'onReceive' )); $this ->serv->on( 'Close' , array ( $this , 'onClose' )); $this ->serv->start(); } public function onStart( $serv ) { echo "Start\n" ; } public function onConnect( $serv , $fd , $from_id ) { echo "Client {$fd} connect\n" ; } public function onClose( $serv , $fd , $from_id ) { echo "Client {$fd} close connection\n" ; } public function onReceive( swoole_server $serv , $fd , $from_id , $data ){ echo "Get Message From Client {$fd}:{$data}\n" ; foreach ( $serv ->connections as $client ){ if ( $fd != $client ) $serv ->send( $client , $data ); } } } $server = new Server(); |
客户端
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 47 | <?php /** * Created by PhpStorm. * User: LeoKim * Date: 2017/5/12 * Time: 23:13 */ $socket = stream_socket_client( "tcp://127.0.0.1:9502" , $errno , $errstr , 30); function OnRead() { global $socket ; $buffer = stream_socket_recvfrom( $socket , 1024); if (! $buffer ) { echo "Server clised\n" ; } echo "\nRECV: {$buffer}\n" ; fwrite(STDOUT, "Enter Msg:" ); } function onWrite() { global $socket ; echo "on Write\n" ; } function onInput() { global $socket ; $msg = trim( fgets (STDIN)); if ( $msg == 'exit' ){ swoole_event_exit(); exit (); } swoole_event_write( $socket , $msg ); fwrite(STDOUT, "Enter Msg:" ); } swoole_event_add( $socket , 'onRead' , 'onWrite' ); swoole_event_add(STDIN, 'onInput' ); fwrite(STDOUT, "Enter Msg:" ); |
vsftpd设置被动模式
完整配置
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 | listen= yes listen_port=21 max_clients=100 max_per_ip=10 local_max_rate=5120000 anonymous_enable=no local_enable= yes write_enable=no chroot_local_user= yes chroot_list_enable= yes chroot_list_file= /etc/vsftpd/chroot_list guest_enable= yes guest_username=kingsoft virtual_use_local_privs= yes user_config_dir= /etc/vsftpd/user_config pasv_enable= yes pasv_min_port=4500 pasv_max_port=5000 tcp_wrappers= yes xferlog_enable= yes xferlog_file= /var/log/ftp/vsftpd .log idle_session_timeout=600 data_connection_timeout=120 accept_timeout=60 connect_timeout=60 connect_from_port_20=no local_umask=022 pam_service_name=vsftpd.vu pasv_address=本机ip pasv_addr_resolve= yes |
主动模式:
1 2 3 | Port_enable=YES 开启主动模式 Connect_from_port_20=YES 当主动模式开启的时候 是否启用默认的20端口监听 Ftp_date_port=%portnumber% 上一选项使用NO参数是 指定数据传输端口 |
被动模式
1 2 3 4 5 6 7 8 9 | 被动模式 PASV_enable=YES 开启被动模式 PASV_min_port=%number% 被动模式最低端口 PASV_max_port=%number% 被动模式最高端口 iptables中开放这段端口 service iptables start 打开防火墙 iptables -I INPUT -p tcp --dport 10020:10040 -j ACCEPT iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT |
在被动模式,服务器做了NAT,例如云主机,这时候我们用特定的IP访问机器,其实还转了一层。FTP客户端访问机器可能会没响应。具体情况为登录成功,但是list目录和文件的时候卡住。
1 2 | vsftpd 22411 nobody 0u IPv4 68905 0t0 TCP 10.140.41.65: ftp ->10.10.10.98:43380 (ESTABLISHED) vsftpd 22411 nobody 1u IPv4 68905 0t0 TCP 10.140.41.65: ftp ->10.10.10.98:43380 (ESTABLISHED) |
这时候可以看到机器的真正IP。
1 2 | pasv_address=本机ip【就是我们能访问的外网IP】 pasv_addr_resolve= yes |
这样ftp客户端就可以解析IP,访问成功
IO多路复用
1.epoll函数会监听注册在自己名下的所有的socket描述符
2.当有socket感兴趣的时间发生时,epoll函数才会相应,并返回有时间发生的socket集合
3.epoll的本质是阻塞IO,他的优点在于能同时处理大量socket连接
在这个epoll进程之内同时处理多个描述符
其实并不是异步的
WebSocket 是什么原理(知乎上的很搞笑)
作者:Ovear
链接:https://www.zhihu.com/question/20215561/answer/40316953
来源:知乎
一、WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)
首先HTTP有1.1和1.0之说,也就是所谓的keep-alive,把多个HTTP请求合并为一个,但是Websocket其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充可以通过这样一张图理解
有交集,但是并不是全部。
另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议本身只有1.0和1.1,而且跟Html本身没有直接关系。。
通俗来说,你可以用HTTP协议传输非Html数据,就是这样=。=
再简单来说,层级不一样。
二、Websocket是什么样的协议,具体有什么优点
首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。
简单的举个例子吧,用目前应用比较广泛的PHP生命周期来解释。
1) HTTP的生命周期通过Request来界定,也就是一个Request 一个Response,那么在HTTP1.0中,这次HTTP请求就结束了。
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。
但是请记住 Request = Response , 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。
教练,你BB了这么多,跟Websocket有什么关系呢?
_(:з」∠)_好吧,我正准备说Websocket呢。。
首先Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。
在握手阶段是一样的
——-以下涉及专业技术内容,不想看的可以跳过lol:,或者只看加黑内容——–
首先我们来看个典型的Websocket握手(借用Wikipedia的。。)
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com
熟悉HTTP的童鞋可能发现了,这段类似HTTP协议的握手请求中,多了几个东西。
我会顺便讲解下作用。
Upgrade: websocket Connection: Upgrade
这个就是Websocket的核心了,告诉Apache、Nginx等服务器:注意啦,窝发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13
首先,Sec-WebSocket-Key 是一个Base64 encode的值,这个是浏览器随机生成的,告诉服务器:泥煤,不要忽悠窝,我要验证尼是不是真的是Websocket助理。
然后,Sec_WebSocket-Protocol 是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。简单理解:今晚我要服务A,别搞错啦~
最后,Sec-WebSocket-Version 是告诉服务器所使用的Websocket Draft(协议版本),在最初的时候,Websocket协议还在 Draft 阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome用的不是一个版本之类的,当初Websocket协议太多可是一个大难题。。不过现在还好,已经定下来啦~大家都使用的一个东西~ 脱水:服务员,我要的是13岁的噢→_→
然后服务器会返回下列东西,表示已经接受到请求, 成功建立Websocket啦!
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat
这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~
Upgrade: websocket Connection: Upgrade
依然是固定的,告诉客户端即将升级的是Websocket协议,而不是mozillasocket,lurnarsocket或者shitsocket。
然后,Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key。服务器:好啦好啦,知道啦,给你看我的ID CARD来证明行了吧。。
后面的,Sec-WebSocket-Protocol 则是表示最终使用的协议。
至此,HTTP已经完成它所有工作了,接下来就是完全按照Websocket协议进行了。
具体的协议就不在这阐述了。
——————技术解析部分完毕——————
你TMD又BBB了这么久,那到底Websocket有什么鬼用,http long poll,或者ajax轮询不都可以实现实时信息传递么。
好好好,年轻人,那我们来讲一讲Websocket有什么用。
来给你吃点胡(苏)萝(丹)卜(红)
三、Websocket的作用
在讲Websocket之前,我就顺带着讲下 long poll 和 ajax轮询 的原理。
首先是 ajax轮询 ,ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
场景再现:
客户端:啦啦啦,有没有新信息(Request)
服务端:没有(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:没有。。(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:好啦好啦,有啦给你。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:。。。。。没。。。。没。。。没有(Response) —- loop
long poll
long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
场景再现
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop
从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性。
何为被动性呢,其实就是,服务端不能主动联系客户端,只能有客户端发起。
简单地说就是,服务器是一个很懒的冰箱(这是个梗)(不会、不能主动发起连接),但是上司有命令,如果有客户来,不管多么累都要好好接待。
说完这个,我们再来说一说上面的缺陷(原谅我废话这么多吧OAQ)
从上面很容易看出来,不管怎么样,上面这两种都是非常消耗资源的。
ajax轮询 需要服务器有很快的处理速度和资源。(速度)
long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)
所以ajax轮询 和long poll 都有可能发生这种情况。
客户端:啦啦啦啦,有新信息么?
服务端:月线正忙,请稍后再试(503 Server Unavailable)
客户端:。。。。好吧,啦啦啦,有新信息么?
服务端:月线正忙,请稍后再试(503 Server Unavailable)
客户端:
然后服务端在一旁忙的要死:冰箱,我要更多的冰箱!更多。。更多。。(我错了。。这又是梗。。)
————————–
言归正传,我们来说Websocket吧
通过上面这个例子,我们可以看出,这两种方式都不是最好的方式,需要很多资源。
一种需要更快的速度,一种需要更多的'电话'。这两种都会导致'电话'的需求越来越高。
哦对了,忘记说了HTTP还是一个无状态协议。(感谢评论区的各位指出OAQ)
通俗的说就是,服务器因为每天要接待太多客户了,是个健忘鬼,你一挂电话,他就把你的东西全忘光了,把你的东西全丢掉了。你第二次还得再告诉服务器一遍。
所以在这种情况下出现了,Websocket出现了。
他解决了HTTP的这几个难题。
首先,被动性,当服务器完成协议升级后(HTTP->Websocket),服务端就可以主动推送信息给客户端啦。
所以上面的情景可以做如下修改。
客户端:啦啦啦,我要建立Websocket协议,需要的服务:chat,Websocket协议版本:17(HTTP Request)
服务端:ok,确认,已升级为Websocket协议(HTTP Protocols Switched)
客户端:麻烦你有信息的时候推送给我噢。。
服务端:ok,有的时候会告诉你的。
服务端:balabalabalabala
服务端:balabalabalabala
服务端:哈哈哈哈哈啊哈哈哈哈
服务端:笑死我了哈哈哈哈哈哈哈
就变成了这样,只需要经过一次HTTP请求,就可以做到源源不断的信息传送了。(在程序设计中,这种设计叫做回调,即:你有信息了再来通知我,而不是我傻乎乎的每次跑来问你)
这样的协议解决了上面同步有延迟,而且还非常消耗资源的这种情况。
那么为什么他会解决服务器上消耗资源的问题呢?
其实我们所用的程序是要经过两层代理的,即HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(PHP等)来处理。
简单地说,我们有一个非常快速的接线员(Nginx),他负责把问题转交给相应的客服(Handler)。
本身接线员基本上速度是足够的,但是每次都卡在客服(Handler)了,老有客服处理速度太慢。,导致客服不够。
Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持久连接,有信息的时候客服想办法通知接线员,然后接线员在统一转交给客户。
这样就可以解决客服处理速度过慢的问题了。
同时,在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输identity info(鉴别信息),来告诉服务端你是谁。
虽然接线员很快速,但是每次都要听这么一堆,效率也会有所下降的,同时还得不断把这些信息转交给客服,不但浪费客服的处理时间,而且还会在网路传输中消耗过多的流量/时间。
但是Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity info的信息。
同时由客户主动询问,转换为服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的客服(Handler)了
——————–
至于怎么在不支持Websocket的客户端上使用Websocket。。答案是:不能
但是可以通过上面说的 long poll 和 ajax 轮询来 模拟出类似的效果
Comporser安装
早上在centos7 上安装comporser 怎么都装不上 常规方法会报如下错误
Failed to decode zlib stream
最后是下载了https://getcomposer.org/composer.phar
然后设置全局就可以了
1 | mv composer.phar /usr/local/bin/composer |
swoole安装
swoole项目已收录到PHP官方扩展库,除了手工下载编译外,还可以通过PHP官方提供的pecl命令,一键下载安装swoole很方便
1 | pecl install swoole |
然后添加swoole.so到php.ini
如何用命令将本地项目上传到git
1、(先进入项目文件夹)通过命令 git init 把这个目录变成git可以管理的仓库
git init
2、把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点“.”,意为添加文件夹下的所有文件
git add .
3、用命令 git commit告诉Git,把文件提交到仓库。引号内为提交说明
git commit -m 'first commit'
4、关联到远程库
git remote add origin 你的远程库地址
如:
git remote add origin https://github.com/cade8800/ionic-demo.git
5、获取远程库与本地同步合并(如果远程库不为空必须做这一步,否则后面的提交会失败)
git pull --rebase origin master
6、把本地库的内容推送到远程,使用 git push命令,实际上是把当前分支master推送到远程。执行此命令后会要求输入用户名、密码,验证通过后即开始上传。
git push -u origin master
*、状态查询命令
git status
备:详细请参考 http://www.cnblogs.com/tugenhua0707/p/4050072.html
laravel5集成angular2
这个问题我之前一直在思考
学习angular的过程中都是把angular视为一个完整的前端存在
也就是脱离了后端的独立存在
在代码里不去插入动态语言
在前端完成数据的存储,通信,绑定,修改
与后端可以用http协议交互,像app一样只做展示的前端操作
angular2通过ng server创建http服务
我想要把angular2结合laravel5一起使用
开始我觉得是不是angular2就像上面说的那样还是通过ng server创建服务
运行在4200端口 然后nginx反向代理到4200端口访问angular
然后angular通过http协议与laravel后端通信
google了之后发现使用angular2的开发模式(development mode)可以直接使用
而之前ng server只是单独为了让程序跑起来提供的一个服务
如今又laravel了 就可以不用创建那个服务 直接在这个上面跑
哎 还是基础不好思维有限 慢慢补吧
让我们开始吧!首先要安装基础laravel应用
我们需要获取angular2和typescript源码
在新创建的文件夹(larangular)中可以看到package.json文件
修改
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 | { "private" : true , "scripts" : { "dev" : "npm run development" , "development" : "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" , "watch" : "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" , "watch-poll" : "npm run watch -- --watch-poll" , "hot" : "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js" , "prod" : "npm run production" , "production" : "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" }, "devDependencies" : { "axios" : "^0.15.3" , "bootstrap-sass" : "^3.3.7" , "cross-env" : "^3.2.3" , "jquery" : "^3.1.1" , "laravel-mix" : "0.*" , "lodash" : "^4.17.4" , "vue" : "^2.1.10" , "concurrently" : "^1.0.0" , "del" : "^2.2.0" , "gulp" : "^3.8.8" }, "dependencies" : { "angular2" : "2.0.0-beta.0" , "bootstrap-sass" : "^3.0.0" , "elixir-typescript" : "^1.1.2" , "es6-promise" : "^3.0.2" , "es6-shim" : "^0.33.3" , "laravel-elixir" : "^4.0.0" , "reflect-metadata" : "0.1.2" , "rxjs" : "5.0.0-beta.0" , "systemjs" : "0.19.6" , "zone.js" : "0.5.10" } } |
现在执行npm install,所需要的文件将被下载到node_modules文件夹
完成之后,我们要添加Typescript在laravel项目的resouce/assets目录
在这个文件夹里我们要创建2个文件app.component.ts
和 boot.ts
1 2 3 4 5 6 7 | import {Component} from 'angular2/core' ; @Component({ selector: 'my-app' , template: '<h1>My First Angular 2 App</h1>' }) export class AppComponent { } |
1 2 3 4 | import {bootstrap} from 'angular2/platform/browser' import {AppComponent} from './app.component' bootstrap(AppComponent); |
下面我们需要编写一个简单的Elixir task来完成Typescript
在主文件夹中创建gulpfile.js
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 | var elixir = require( 'laravel-elixir' ); var elixirTypscript = require( 'elixir-typescript' ); /* |-------------------------------------------------------------------------- | Elixir Asset Management |-------------------------------------------------------------------------- | | Elixir provides a clean, fluent API for defining some basic Gulp tasks | for your Laravel application. By default, we are compiling the Sass | file for our application, as well as publishing vendor resources. | */ elixir( function (mix) { mix.sass( 'app.scss' ); mix.copy( 'node_modules/angular2' , 'public/angular2' ); mix.copy( 'node_modules/rxjs' , 'public/rxjs' ); mix.copy( 'node_modules/systemjs' , 'public/systemjs' ); mix.copy( 'node_modules/es6-promise' , 'public/es6-promise' ); mix.copy( 'node_modules/es6-shim' , 'public/es6-shim' ); mix.copy( 'node_modules/zone.js' , 'public/zone.js' ); mix.typescript( 'app.js' , 'public/' , '/**/*.ts' ,{ "target" : "ES5" , "module" : "system" , "moduleResolution" : "node" , "sourceMap" : true , "emitDecoratorMetadata" : true , "experimentalDecorators" : true , "removeComments" : false , "noImplicitAny" : false , }); }); |
然后安装gulp
修改如下文件 node_modules/elixir_typescript/index.js
1 2 3 4 5 6 7 8 9 | new Task(pluginName, function () { var tsResult = gulp.src(assetPath + search) .pipe(ts(options, undefined, _laravelReporter.ElixirMessage())); return tsResult // .pipe(concat(outputFileName)) .pipe(gulp.dest(outputFolder)); }) |
如果不修改会出现下面的错误
现在在程序根目录下执行gulp
全部执行完成
修改views
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | <!doctype html> < html lang = "{{ config('app.locale') }}" > < head > < meta charset = "utf-8" > < meta http-equiv = "X-UA-Compatible" content = "IE=edge" > < meta name = "viewport" content = "width=device-width, initial-scale=1" > < title >Laravel</ title > <!-- Fonts --> < link href = "https://fonts.googleapis.com/css?family=Raleway:100,600" rel = "stylesheet" type = "text/css" > <!-- Styles --> < style > html, body { background-color: #fff; color: #636b6f; font-family: 'Raleway', sans-serif; font-weight: 100; height: 100vh; margin: 0; } .full-height { height: 100vh; } .flex-center { align-items: center; display: flex; justify-content: center; } .position-ref { position: relative; } .top-right { position: absolute; right: 10px; top: 18px; } .content { text-align: center; } .title { font-size: 84px; } .links > a { color: #636b6f; padding: 0 25px; font-size: 12px; font-weight: 600; letter-spacing: .1rem; text-decoration: none; text-transform: uppercase; } .m-b-md { margin-bottom: 30px; } </ style > < script src = "es6-shim/es6-shim.min.js" ></ script > < script src = "systemjs/dist/system-polyfills.js" ></ script > < script src = "angular2/bundles/angular2-polyfills.js" ></ script > < script src = "systemjs/dist/system.src.js" ></ script > < script src = "rxjs/bundles/Rx.js" ></ script > < script src = "angular2/bundles/angular2.dev.js" ></ script > < script > System.config({ "defaultJSExtensions": true, packages: { app: { format: 'register', defaultExtension: 'js' } } }); System.import('typescript/boot') .then(null, console.error.bind(console)); </ script > </ head > < body > < div class = "flex-center position-ref full-height" > @if (Route::has('login')) < div class = "top-right links" > @if (Auth::check()) < a href = "{{ url('/home') }}" >Home</ a > @else < a href = "{{ url('/login') }}" >Login</ a > < a href = "{{ url('/register') }}" >Register</ a > @endif </ div > @endif < div > < div class = "title m-b-md" > Laravel </ div > < my-app >Loading...</ my-app > < div > < a href = "https://laravel.com/docs" >Documentation</ a > < a href = "https://laracasts.com" >Laracasts</ a > < a href = "https://laravel-news.com" >News</ a > < a href = "https://forge.laravel.com" >Forge</ a > < a href = "https://github.com/laravel/laravel" >GitHub</ a > </ div > </ div > </ div > </ body > </ html > |
成功了!!!
我把它放在了这里
https://git.oschina.net/iamleokim/larangular.git
ng2-admin分析
ng2-admin\src\index.html
通过<app></app>作为容器
1 2 3 4 5 6 7 | <body> <app> </app> <div id= "preloader" > <div></div> </div> </body> |
ng2-admin\src\app\app.routing.ts
可以看到这里用的是HashLocationStrategy(路由策略)
1 2 3 4 5 6 | export const routes: Routes = [ { path: '' , redirectTo: 'pages' , pathMatch: 'full' }, { path: '**' , redirectTo: 'pages/dashboard' } ]; export const routing: ModuleWithProviders = RouterModule.forRoot(routes, { useHash: true }); |
ng2-admin\src\app\app.component.ts
Conponent 的 selector选择‘app’
template 里写了外层div class=“addtional-bg”
设置子路由 router-outlet
1 2 3 4 5 6 7 8 9 10 | @Component({ selector: 'app' , styleUrls: [ './app.component.scss' ], template: ` <main [class.menu-collapsed]= "isMenuCollapsed" baThemeRun> <div class= "additional-bg" ></div> <router-outlet></router-outlet> </main> ` }) |
ng2-admin\src\app\pages\pages.routing.ts
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 | export const routes: Routes = [ { path: 'login' , loadChildren: 'app/pages/login/login.module#LoginModule' }, { path: 'register' , loadChildren: 'app/pages/register/register.module#RegisterModule' }, { path: 'pages' , component: Pages, children: [ { path: '' , redirectTo: 'dashboard' , pathMatch: 'full' }, { path: 'dashboard' , loadChildren: './dashboard/dashboard.module#DashboardModule' }, { path: 'editors' , loadChildren: './editors/editors.module#EditorsModule' }, { path: 'components' , loadChildren: './components/components.module#ComponentsModule' }, { path: 'charts' , loadChildren: './charts/charts.module#ChartsModule' }, { path: 'ui' , loadChildren: './ui/ui.module#UiModule' }, { path: 'forms' , loadChildren: './forms/forms.module#FormsModule' }, { path: 'tables' , loadChildren: './tables/tables.module#TablesModule' }, { path: 'maps' , loadChildren: './maps/maps.module#MapsModule' } ] } ]; |