0%

处理静态资源

js的打包基本处理完了,还有图片、音频等静态资源需要处理。

依然先装依赖:

1
2
$ npm i -D url-loader file-loader
$ npm i -D @svgr/webpack # 顺带支持一下导入svg图片

增加webpack配置:

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
// webpack.base.js
{
test: /\.svg$/,
use: ['@svgr/webpack']
},
{
test: /\.(jpg|jpeg|bmp|png|webp|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024, // 小于这个大小的图片,会自动base64编码后插入到代码中
name: 'img/[name].[hash:8].[ext]',
outputPath: config.assetsDirectory,
publicPath: config.assetsRoot
}
},
// 下面这个配置必须放在最后
{
exclude: [/\.(js|mjs|ts|tsx|less|css|jsx)$/, /\.html$/, /\.json$/],
loader: 'file-loader',
options: {
name: 'media/[path][name].[hash:8].[ext]',
outputPath: config.assetsDirectory,
publicPath: config.assetsRoot
}
}

tips: 生产环境需要合理使用缓存,需要拷贝一份同样的配置在webpack.prod.js中,并将name中的hash改为contenthash

阅读全文 »

完善webpack打包配置

有了webpack的基础配置,还不足以支持打生产环境能够使用的包,我们还需要增加一些配置。

首先,每次打包前最好能把上一次生成的文件删除,这里可以用clean-webpack-plugin插件实现:

1
$ npm i -D clean-webpack-plugin

然后修改webpack基础配置:

1
2
3
4
5
6
7
8
// webpack.base.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
plugins: [
new CleanWebpackPlugin(),
]
}

在生产环境,我们希望部署新版本后能够丢弃缓存,又希望保留没有被改动的文件的缓存,而在开发环境,我们希望完全不使用缓存,因此我们需要在当前配置的基础上,分别扩展生产和开发两套配置。

阅读全文 »

引言

项目github仓库地址: https://github.com/mecoepcoo/ts-react-boilerplate

这个系列的文章主要讲述如何从一个空目录建立webpack+react+typescript+eslint脚手架,书写此文时各主要工具的版本为:

  • webpack v4
  • react v16.9
  • typescript v3.5
  • babel v7
  • eslint v6.2

本文涉及的内容大致包含:

  • webpack的配置
  • 对静态资源(图片,模板等)的处理
  • 使react项目支持typescript,eslint,prettier等工具
  • 优化webpack配置,减小代码的体积
  • 支持不同的css预处理器(less,sass等)
  • 一套好用的样式方案
  • 使项目支持多个环境切换(开发,测试,预发布,生产等)
  • 使用规则来自动约束代码规范
  • 优化开发体验
  • 一些优化项目性能的建议

阅读这个系列的文章需要具备的条件:

  • 你使用过vuereactangular等任意一种前端框架
  • 你了解过vue-clicreate-react-appangular-cli等任意一种脚手架生成工具
  • 你了解webpack的基本原理或用法
  • 你有生产环境代码的开发经验,了解生产环境中的代码与自娱自乐代码的区别
阅读全文 »

本文介绍如何使用docker在本地搭建一个简单的mysql开发环境。

准备工作

使用本文用例需要预先安装好docker,windows用户直接下载windows版本的docker客户端即可,使用linux容器或windows容器都不影响结果。

启动mysql

运行命令:

1
$ docker run -p 3308:3306 -v /home/dev-enviroment/:/var/lib/mysql -d -e MYSQL_ROOT_PASSWORD=1234 mysql

这句命令的意思是,使用docker启动一个名为mysql的容器,如果本地没有这个容器,则从远程仓库中寻找,容器启动后,将容器内的3306端口映射到宿主机的3308端口,并将容器内的/var/lib/mysql目录映射到宿主机的/home/dev0enviroment目录,-d表示在后台运行,容器启动后仅返回容器id,-e表示配置环境变量

注意:windows用户使用cmd, powershell或者gitbash等不用的命令行工具时,需要输入的路径可能不同,视终端和容器类型而定,可以尝试d:/dev或者/d/dev等形式。

配置远程访问

对于容器内服务来说,宿主机是一台远程主机,需要修改配置以支持数据库连接。

1
2
3
4
5
$ docker exec -it 01873d bash # 以交互模式进入容器,并运行bash,这里的01873d是container id的前几位
# windows用户需要以管理员身份运行,如果在cmd中无法进入,可尝试使用git bash等工具,如果提示要加前缀,就在docker命令前增加前缀

# 进入mysql命令行
$ mysql -uroot -p1234
1
2
3
4
5
6
7
8
-- 允许远程连接
GRANT ALL ON *.* TO 'root'@'%';
-- 更新权限配置
flush privileges;
-- 修改加密模式(navicat等不支持默认模式)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER;
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '1234';
flush privileges;

现在打开navicat等工具,连接localhost:3308即可访问数据库了。

如果docker被关闭,只需要运行以下命令就可以恢复数据库服务:

1
2
3
$ docker ps -a
# 从列出的容器列表中找出mysql的容器id
$ docker restart id

Win 系统的控制台默认编码不是utf-8,使用vscode,git bash等工具时经常在控制台看到乱码。

调整这些配置,就能让控制台正确显示中文。

  1. 使用 git bash 等工具时,先打开工具的设置,找找设置里有没有文本编码(character set)相关的选项,设置为”UTF-8”即可
  2. 快捷键 win+R 打开运行,输入 regedit 回车,打开注册表编辑器,找到HKEY_CURRENT_USER\Console\在里面的每一项中,新建名为CodePage(如果已有则修改)的DWORD值,数值设为十进制65001即可

node-canvas 是 node 环境用来绘制图形的工具,我在 windows 10 环境和 docker 中 node-alpine 安装此工具时遇到了一些困难,以此文记录 trouble shooting 经历。

阅读全文 »

在不同的设备上使用 vs code,配置可能会不一样,比如eslint工具,各种插件的配置。使用 vs code 的 Settings Sync 插件就可以简单地同步配置。

这个插件的原理其实就是利用 github gist(代码片段功能)来保存和同步配置信息。

  1. 在 vsc 中找到“插件(Extensions)”,搜索 Settings Sync (输入settings即可),找到插件点击安装。
  2. 使用快捷键:shift+alt+u (macbook是option键) 上传配置,首次使用将会看到一个界面,选择 “login with github”,登录 github 账号后,点击下方按钮来自动创建 gist。
  3. 在另一台电脑上,安装 Settings Sync 插件,同样登录到 github,这时会让你选择已有的 gist,从给出的列表中选出刚才创建好的 gist,即可完成绑定。
  4. 使用快捷键:shift+alt+d 来下载配置。

本文记录如何使用registry镜像创建docker私有仓库,并试验将一个本地镜像推送到私有仓库。

搭建私有仓库

docker官方提供了一个registry镜像供我们搭建本地私有的仓库环境。

执行命令,这个命令会自动下载registry容器,并创建私有仓库服务。仓库默认被创建在/tmp/registry下:

1
$ docker run -d -p 5000:5000 registry

用这种方式创建,一旦容器被删除,则镜像也会丢失。我们也可以指定一个其他目录来创建仓库:

1
2
3
$ docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry
# 看一下端口
$ netstat -nlp

现在本地已经在5000端口自动启动了一个私有仓库服务。

阅读全文 »

使用jenkins+github+docker是一个很常用的持续集成、持续交付方案了,这篇文章描述了搭建这套系统的流程,记录了一些坑点。

配置github

  1. 在’setting’里找到配置SSH key的地方:https://github.com/settings/keys
  2. 根据文档新建使用一个已有的key
  3. 开发设置(setting-Developer settings-)中配置一个带权限的access_token,注意,’repo’和’admin:repo hook’这两项是必选的,这个简单

安装docker

  1. 阅读官方CentOS安装文档,按步骤装,简单的很

安装jdk8

  1. java官网下一个,然后安装,配环境变量,比上面更简单
1
2
3
4
5
6
7
8
9
10
# 下载解压(注意用wget要先点下载,然后把带auth参数的链接放到wget)
$ wget jdk-download-url
$ tar -zxvf jdk-8u60-linux-x64.tar.gz

# 移动目录
$ mkdir /usr/java
$ cp -r jdk1.8.0_201 /usr/java/

# 配置环境变量
$ vim /etc/profile

在底部加入如下,注意目录名别配错了:

1
2
3
4
JAVA_HOME=/usr/java/jdk1.8.0_201
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=$JAVA_HOME/jre/lib/ext:$JAVA_HOME/lib/tools.jar
export PATH JAVA_HOME CLASSPATH

运行source /etc/profile让配置立即生效

验证安装:java -versionjavac

安装Jenkins

  1. 去官网下载
    1
    2
    $ wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war
    $ java -jar jenkins.war --httpPort=8080

然后访问 ip:8080即可

  1. 也可以在docker里装,这样就不用什么jdk了
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ docker pull jenkins/jenkins:lts

    # 建个目录,给他权限
    $ mkdir /home/jenkins
    $ chown -R 1000:1000 jenkins/
    $ ls -nd jenkins/

    # 给镜像打个标签
    $ docker images
    $ docker tag jenkins/jenkins:lts jenkins:lts
    $ docker images

    # 容器跑起来,映射目录
    $ docker run -itd -p 8080:8080 -p 50000:50000 --name jenkins --privileged=true -v /home/jenkins:/var/jenkins_home jenkins:lts

这时候用 ip:8080 就可以访问了,进去以后设置好初始admin账户密码,插件选推荐就行了。

配置Jenkins

  1. 左侧’系统管理’-右侧’系统设置’,找github服务器,添加一个,添加凭据,凭据类型选secret text,凭据添刚才github生成的access_token,id不用填,保存,勾上manage hooks,然后点连接测试,通过即可。
  2. 新建个任务(job),把配置都填好,shell脚本写好即可。

至此,github+jenkins+docker的环境就搭好了,随后可以在jenkins中执行预先编写好的makefile和dockerfile来打包docker镜像和部署应用,本文不赘述makefile和dockerfile等的具体使用方法。

前言

用vue和react做开发,我们经常选择vuex,redux一类的状态管理工具来辅助管理状态,状态逻辑复杂的微信小程序,如果有状态管理工具的话,可以极大地提高开发效率和可维护性。

想象这样一个场景,一个用户修改了用户名,小程序中有十多个组件都用到了这个“用户名”这个状态,如果需要把这些显示都更新,用原生的方式来实现是很麻烦的,本文介绍一种方法,基于rxjs来管理小程序中的各种状态。

rxjs学习资料:

实现原理

引入rxjs

我们尽量避免多余的构建工具,直接使用umd版本的rxjs,下载地址:https://unpkg.com/rxjs/bundles/rxjs.umd.min.js,下载好后,把它放在lib目录中。

实现思路

新建一个stores目录,把状态相关的文件都放在里面,在stores下新建一个user.js,用来管理用户的状态。

新建services目录,存放api相关的服务,在services中新建user.js,用来存放请求用户数据的函数。

demo:

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
// services/user.js
export const userSvc = {
getUserInfo: () => {
console.log('执行获取用户信息');
return 'xiaoming'; // 第一次请求返回的值
}
};

// stores/user.js
import * as Rx from '../lib/rxjs.umd.min';
import { userSvc } from '../services/user';

const types = {
UPDATE_USER_INFO: 'UPDATE_USER_INFO'
};

const states = {
// BehaviorSubject把数据流中的最新值推送给订阅者
user$$: new Rx.BehaviorSubject(userSvc.getUserInfo())
};

const actions = {
[types.UPDATE_USER_INFO] () {
return 'laoming';
}
};

function dispatch(action, args) {
switch (action) {
case types.UPDATE_USER_INFO:
var newStates = actions[types.UPDATE_USER_INFO]();
states.user$$.next(newStates);
break;
}
}

export { types, states, actions, dispatch };

实现的思路是这样的:

首先创建一个status,用来保存用户的状态,用户状态是一个subject,这样就可以向各个组件中的订阅发送组播

然后写一系列的action,action的名称表示要执行的动作,在action函数中完成一些异步操作,比如重新获取用户信息,我们之后会把它的返回值广播给所有的订阅。

最后是dispatch函数,它描述了如何修改状态值,dispatch根据传入的action名称,执行不同的action和逻辑,最终用subject.next()方法把数据广播给每个订阅。

有了这组代码,我们只需要在使用数据的地方订阅就可以了:

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
// 在某个page中
import { states as userStates } from '../../stores/user';
Page({
data: {
name: '',
},
onLoad: function () {
// 订阅测试,此时,name的值应该为'xiaoming'
userStates.user$$.subscribe(data => {
console.log(data);
this.setData({
name: data
});
});
}
});

// 在page的某个组件中
import { states as userStates, types as userTypes, dispatch as userDispatch } from '../../stores/user';
Component({
data: {
name: ''
},

attached() {
userStates.user$$.subscribe(data => {
console.log(data);
this.setData({
name: data
});
});
setTimeout(() => {
userDispatch(userTypes.UPDATE_USER_INFO);
}, 3000);
}
});

3秒后,将会看到page和component中的name都变成了’laoming’,这样就实现了简单的状态管理。