Archives for : 前端

koa2后端项目打包成单个js文件

IMG_0998

(图:这两天爱上拍夜景)

之前发过一篇 node 后端项目文件打包,是用 webpack 把 express 项目打包成单个文件,坑相对少。

最近用 webpack 打包 koa2,踩了两个大坑。

第一坑:不支持 async

koa2 中间件支持三种写法

  • common function
  • async function
  • generatorFunction

可以用 common function 的写法,虽然用不了拉风的 async/await,但好处也有,省去了对 babel 的依赖。

第二坑:any-promise

这个库在打包的时候会报错,看了下它的 package.json,发现 devDependencies 依赖的库并没有 install。然后发现其实并不需要依赖 any-promise,直接用 node 6 及以上的版本就可以了。

编辑文件:

node_modules/koa-compose/index.js

注释掉开头的一行

const Promise = require(‘any-promise’)

填完这两个坑就好办了。

源码:https://github.com/taichenglu/koa-bundle

sublime 文件比对

IMG_1163

(图:Diffy)

之前一直用 sublimerge 这个比对插件,但是最近发现这货居然收费了,从以前的弹出窗口变成了 90 天试用,卖得还不便宜,35 刀。

于是下午找了两款插件配合起来用,效果也还不错。

第一个插件叫 diffy,这货超级简单,甚至可以用简陋来形容。

使用方法:

  1. 开两个窗口
  2. 在任意一个窗口点右键选择 Diffy 的 Compare

但是这样不能同步滚动两个窗口,所以要再装一个插件。

第二个插件叫 syncViewScroll,支持多个窗口同步滚动,但是刚开始用起来会有点不适应,有点小窍门。

比如开 A 和 B 两个窗口,使用方法:

  1. 先在 A 窗口,下拉菜单 -> View -> 勾选 Sync Scroll
  2. 然后在 B 窗口,执行相同操作
  3. 滚动 B 窗口,会同步滚动 A 窗口,但是滚动 A 窗口不会带动 B 窗口
  4. 如果有多个窗口,那就要在最后一个窗口滚动

这两个插件都可以定义快捷键来辅助使用,附上我的快捷键:

// syncViewScroll
{
  "keys": ["super+shift+ctrl+s"],
  "command": "toggle_sync_scroll"
},

// diffy
{
  "keys": ["super+shift+option+d"],
  "command": "diffy"
},

// diffy clear
{
  "keys": ["super+shift+option+c"],
  "command": "diffy", "args": {"action": "clear"}
},

node 后端项目文件打包

IMG_1073

(图:五点不到就天黑了)

node 后端文件理论上不需要打包,但是用了 docker,发现每次创建的镜像都很大。这几天研究了下,使用 webpack,像打包前端代码一样打包后端代码,以便在创建 docker 镜像时过滤 node_modules,使镜像变小,加快 push 速度。

项目地址:https://github.com/taichenglu/docker-node-bundle

参考:https://segmentfault.com/a/1190000006023471

微信小程序本地开发(https 解决方案)

IMG_0961

(图:吃完午饭遛遛)

微信小程序强制使用 https 请求,本地开发调试可以用以下两种方案。

  1. 如果自己没有域名,可以用 natapp,免费版不支持 https,购买最低档的 vip 是¥5/月。
  2. 如果自己有域名且已备案,可以注册一个腾讯云账户,然后免费申请 SSL 证书

附:wdcp 开启 https( nginx+apache 双引擎,或者 nginx 引擎)

  1. 后台防火墙 iptables 增加 443 端口
  2. 后台文件管理 /www/wdlinux/nginx/conf/vhost
  3. 编辑你的站点配置文件,加入以下代码(记得修改证书路径)
    listen 443 ssl;
    ssl_certificate /www/ssl/zhugao.net_bundle.crt;
    ssl_certificate_key /www/ssl/zhugao.net.key;
    ssl_session_timeout 5m;
  4. 后台重启服务 httpd 和 nginxd

nvm auto use

WechatIMG30

(图:liza 提供的迷你下午茶)

nvm 有一个 nvm use 的命令,可以切换不同版本的 node,方便在不同项目中使用不同版本的 node,但是切换项目时经常会忘记打 use 命令,于是想有没有一个类似 nvm auto use 的东东,还确实是有的。

官方提供了 zsh 的解决方案(zsh 应该是 mac 程序员的标配了,还没安装的同学赶紧去 Install 吧)。

1、在项目根目录下创建一个 .nvmrc 文件,只要在这个文件里写一个数字就行,比如写个 6

2、vim ~/.zshrc

3、把官方提供的那段代码粘贴到 .zshrc 文件里,建议到 官方网页 去拷贝以下代码,以确保无误:

# place this after nvm initialization!
autoload -U add-zsh-hook
load-nvmrc() {
  local node_version="$(nvm version)"
  local nvmrc_path="$(nvm_find_nvmrc)"

  if [ -n "$nvmrc_path" ]; then
    local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

    if [ "$nvmrc_node_version" != "N/A" ] && [ "$nvmrc_node_version" != "$node_version" ]; then
      nvm use 
    fi
  elif [ "$node_version" != "$(nvm version default)" ]; then
    echo "Reverting to nvm default version"
    nvm use default
  fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc

4、重启命令终端,以后 cd 到不同目录时,nvm 就会自动查找目录下的 .nvmrc 文件,然后自动执行 nvm use.

Mac 上使用 Genymotion 模拟器调试 Android

IMG_0179

(图:怀念童年的成年人们)

Mac 上使用 Genymotion 模拟器调试 Android,安装过程有点麻烦,不过对于调试频率不高,前期懒得用真机调试的同学可以试试。

安装

  1. 下载安装 VirtualBox(速度很慢,我是在 新浪科技 下的)
  2. 进入 Genymotion 官网,注册一个帐号,然后下载,速度比较慢(个人版免费,企业版收费)
  3. 安装完成,打开 Genymotion,点击 Add 按钮(用之前注册的帐号登录),选择一个设备,点 Next 下载,通常都会下载失败
  4. 如果下载失败(其实不用等到下载失败,有一点点进度时就可以取消了),然后打开终端输入命令
    open ~/.Genymobile
  5. 找到 genymotion.log 并打开,搜索字符 .ova
  6. 找到类似这样的地址: http://dl.genymotion.com/dists/7.0.0/ova/genymotion_vbox86p_7.0_160912_085006.ova
  7. 这个就是虚拟设备文件,用迅雷或者其他工具下载下来
  8. 打开 VirtualBox,菜单 -> 管理 -> 导入虚拟电脑,选择下载下来的文件进行导入
  9. 关闭 Genymotion 再重新打开,这时可以看到设备了
  10. 单击设备,右侧有一个设置按钮可以设置分辨率等信息
  11. 双击设备就可以进入系统了

使用

安装 App 很简单,直接把 apk 文件拖进去就行。

在 Android Studio 安装 Genymobile 插件,可以参考 这里

问题

React Native 项目修改后,Genymobile 无法刷新,网上有说可以双击 R,或者 cmd + m(拖动分隔线),然而并没有用,只能在 Android Studio 里重新 Run。

如果 Genymotion 模拟器已经运行,但是 Android Studio 在 Run 的时候检测不到,尝试以下操作:

  1. 进入 Genymotion 的 Settings,在 ADB 标签下选择 Use custom Android SDK tools,输入 Android SDK 路径,例如
    /Users/你的用户名/Library/Android/sdk
  2. 进入 Android Studio,菜单 Tools -> Android,勾选 Enable ADB Integration
  3. 重启  Android Studio
  4. 如果上述方法无效,打开 VirtualBox,删除虚拟设备,重新导入设备
  5. 重启  Android Studio

第一个 node 应用

WechatIMG44

(图:阳光下)

前几天边学边做的第一个 node 应用。通过微信 JS-SDK 实现:

  • 分享给朋友
  • 分享到朋友圈

https://github.com/taichenglu/wechat-sdk-node

如何在手机上玩代码、操作服务器

G20 放假那几天,在家捣鼓如何在手机上调试代码,初衷是如何在手机上调试 node。

找到了serverauditor 这款神器,可以用它来登录服务器,爱干啥干啥,比如今天上午在小区里遛小朋友的时候,我用它来作了一次代码发布,想想就醉。

Serverauditor is a desktop and mobile SSH terminal
Everywhere. Handy. Functional.

第2892天:h5页面下拉加载就这么简单

Q(window).scroll(function() {
    if ((Q(window).scrollTop() + Q(window).height() > Q(document).height() - 40)) {
        // do something
    }
});

第2851天:用swiper实现类似微信查看图片的效果

swiper中文)做了一个类似微信查看图片的效果。

线上效果可以用手机浏览有赞社区的这个帖(点击帖内图片后左右滑动):http://bbs.youzan.com/forum.php?mod=viewthread&tid=47601

js

/**
 * 场景: 手机浏览论坛帖子,左右滑动查看楼层图片
 * Author: zhugao
 * 注意:例中的 ’.message' 为每个楼层的容器
 */

var swipers = {};
function showSwiperImg(options) {
    var swiperId = 'js-swiper-' + options.pid;

    // 如果该楼层的swiper已经实例化
    if ($('#' + swiperId).size() > 0) {
        // 定位到当前点击的图片
        swipers[options.pid].slideTo(options.slideIndex, 0);
        // 直接显示该swiper
        $('#' + swiperId).fadeIn(200);
    } else {
        // append容器
        var swiperContainer = $(
            '<div class="swiper-container" id="' + swiperId + '">' +
            '   <div class="swiper-wrapper"></div>' +
            '</div>'
        );
        swiperContainer.hide().appendTo('body').fadeIn(200);

        // append内容
        $(options.elem).parents('.message').find('img').each(function() {
            var imageSource = $(this).data('img-source');
            var swiperSlide = $(
                '<div class="swiper-slide">' +
                '   <img data-src="' + imageSource + '" class="swiper-lazy">' +
                '   <div class="swiper-lazy-preloader"></div>' +
                '</div>'
            );
            swiperSlide.appendTo('#' + swiperId + ' .swiper-wrapper');
        });

        // 实例化swiper
        swipers[options.pid] = new Swiper('#' + swiperId, {
            // 间隔
            spaceBetween: 20,
            // 开启图片延迟加载
            lazyLoading : true,
            // 点击swiper
            onTap: function() {
                $('#' + swiperId).fadeOut(200);
            },
            // 单个图片加载结束
            onLazyImageReady: function(swiper, slide, image) {
                // 移除loading
                $(slide).find('.swiper-lazy-preloader').remove();
            }
        });

        // 定位到当前点击的图片
        swipers[options.pid].slideTo(options.slideIndex, 0);
    }
}

// 调用
$('.message').on('click', 'img', function() {
    // 图片所在的楼层
    var pid = $(this).parents('li').attr('id');
    // 点击了第几张小图
    var slideIndex = $(this).parents('.message').find('img').index(this);

    var options = {
        elem: this,
        pid: pid,
        slideIndex: slideIndex
    };
    showSwiperImg(options);
});

css

.swiper-container {
    position: fixed;
    z-index: 999;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.9);
}
.swiper-slide {
    text-aling: center;
    /* 图片垂直居中 */
    display: -webkit-box;
    -webkit-box-align: center;
}
.swiper-slide img {
    max-width: 100%;
    max-height: 100%;
}