前面两篇文章的例子中采用的开发方式被称作standalone
,意思是说把所有需要用到的js文件定义好并放在<script>标签中,然后在另起一个<script>标签用于撰写实际业务场景需要的自定义代码;这种方式的好处是代码的引入、撰写和阅读都非常清晰明了,缺点是所有源码都暴露在html中。
通过利用gulp和其丰富插件库可以完成对多个js文件进行预编译(指定一个文件,工具可以将它所有的依赖组织起来)和压缩,最终产生一个具有混淆性的单js文件;详细的gulp文档说明请移步到这里。
简单的合并
# 创建项目目录结构
[root@localhost ~]# mkdir -p simple_merge/src
[root@localhost ~]# cd simple_merge
# 安装gulp打包组件和react相关的js组件
[root@localhost simple_merge]# cnpm install react react-dom gulp gulp-concat --save-dev
# 将react.js和react-dom.js文件复制到src目录中.
[root@localhost simple_merge]# cp node_modules/react/dist/react.js node_modules/react-dom/dist/react-dom.js src/
# 创建gulpfile.js任务管理文件.
[root@localhost simple_merge]# vim gulpfile.js
var gulp = require('gulp'),
concat = require('gulp-concat')
gulp.task('compress', function() {
return gulp.src('src/*js')
.pipe(concat('bundle.js'))
.pipe(gulp.dest('dist/'))
})
# 合并文件
[root@localhost simple_merge]# ./node_modules/gulp/bin/gulp.js compress
[21:30:29] Using gulpfile ~/simple_merge/gulpfile.js
[21:30:29] Starting 'compress'...
[21:30:29] Finished 'compress' after 53 ms
# 查看产出的目录(dist)
[root@localhost simple_merge]# ls
dist gulpfile.js node_modules src
# 查看合并前的文件
[root@localhost simple_merge]# ls -alh src/
total 736K
drwxr-xr-x 2 root root 42 Mar 20 21:25 .
drwxr-xr-x 5 root root 68 Mar 20 21:30 ..
-rw-r--r-- 1 root root 606K Mar 20 21:25 react-dom.js
-rw-r--r-- 1 root root 125K Mar 20 21:25 react.js
# 查看合并后的文件
[root@localhost simple_merge]# ls -alh dist/
total 732K
drwxr-xr-x 2 root root 23 Mar 20 21:30 .
drwxr-xr-x 5 root root 68 Mar 20 21:30 ..
-rw-r--r-- 1 root root 731K Mar 20 21:30 bundle.js
小结: 通过上面gulpfile.js任务管理文件中的代码,是将两个js文件进行简单的合并,可以看得出来原来两个文件的大小分别是606k和125k,合并成单文件bundle.js后,文件的大小是731K正好是两个文件大小的总和。
压缩和混淆
# 创建项目目录结构
[root@localhost ~]# mkdir -p simple_uglify/src
[root@localhost ~]# cd simple_uglify/
# 安装gulp和gulp-uglify
[root@localhost simple_uglify]# cnpm install react react-dom gulp gulp-uglify --save-dev
# 将react.js和react-dom.js文件复制到src目录中.
[root@localhost simple_uglify]# cp node_modules/react/dist/react.js node_modules/react-dom/dist/react-dom.js src/
# 创建gulpfile.js任务管理文件.
[root@localhost simple_uglify]# vim gulpfile.js
var gulp = require('gulp'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify')
gulp.task('compress', function() {
return gulp.src('src/*js')
.pipe(concat('bundle.js'))
.pipe(uglify())
.pipe(gulp.dest('dist/'))
})
# 将react.js和react-dom.js文件复制到src目录中.
[root@localhost simple_uglify]# cp node_modules/react/dist/react.js node_modules/react-dom/dist/react-dom.js src/
# 创建gulpfile.js任务管理文件.
[root@localhost simple_uglify]# vim gulpfile.js
var gulp = require('gulp'),
uglify = require('gulp-uglify')
gulp.task('compress', function() {
return gulp.src('src/*js')
.pipe(uglify())
.pipe(gulp.dest('dist/'))
})
# 合并文件
[root@localhost simple_uglify]# ./node_modules/gulp/bin/gulp.js compress
[21:56:35] Using gulpfile ~/simple_uglify/gulpfile.js
[21:56:35] Starting 'compress'...
[21:56:39] Finished 'compress' after 3.24 s
# 查看合并前的文件
[root@localhost simple_uglify]# ls -alh src/
total 736K
drwxr-xr-x 2 root root 42 Mar 20 21:54 .
drwxr-xr-x 5 root root 88 Mar 20 21:59 ..
-rw-r--r-- 1 root root 606K Mar 20 21:53 react-dom.js
-rw-r--r-- 1 root root 125K Mar 20 21:53 react.js
# 查看合并后的文件
[root@localhost simple_uglify]# ls -alh dist/
total 216K
drwxr-xr-x 2 root root 23 Mar 20 21:59 .
drwxr-xr-x 5 root root 88 Mar 20 21:59 ..
-rw-r--r-- 1 root root 216K Mar 20 21:59 bundle.js
小结: 仅仅是将两个源码文件进行合并其实并没有什么意义,这里将采用uglify插件对合并后的文件进行压缩和混淆。
解决依赖问题
上面两个例子都是针对源码库文件进行合并、压缩和混淆,实际上意义也不大,因为这两个代码跟项目业务代码并没有直接作用。所以这里将会单独列出一个业务代码的js文件,并通过gulp的相关插件来完成依赖问题解决。
# 创建项目目录结构
[root@localhost ~]# mkdir -p spa_jsx/src
[root@localhost ~]# cd spa_jsx/
# 安装相关插件
[root@localhost spa_jsx]# cnpm install babel babel-core babel-preset-es2015 babel-preset-react babelify gulp gulp-uglify gulp-streamify gulp-uglify browserify vinyl-source-stream react react-dom react-remarkable --save-dev
# 创建.babelrc文件(声明支持es2015和react)
[root@localhost spa_jsx]# vim .babelrc
{ presets: ["es2015", "react"] }
# 创建源码组件(Component)文件
[root@localhost spa_jsx]# vim src/markdown_editor.js
import React, {Component} from 'react';
import Remarkable from 'remarkable';
class MarkdownEditor extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {value: 'Type some *markdown* here!'};
}
handleChange(e) {
this.setState({value: e.target.value});
}
getRawMarkup() {
var md = new Remarkable();
return { __html: md.render(this.state.value) };
}
render() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<textarea onChange={this.handleChange}
defaultValue={this.state.value} />
<h3>Output</h3>
<div className="content"
dangerouslySetInnerHTML={this.getRawMarkup()} />
</div>
);
}
}
export default MarkdownEditor;
# 创建源码模版(JSX)文件
[root@localhost spa_jsx]# vim src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './markdown_editor';
ReactDOM.render(
<App />,
document.getElementById('root')
);
# 创建gulpfile.js任务配置管理文件.
[root@localhost spa_jsx]# vim gulpfile.js
var gulp = require('gulp'),
uglify = require('gulp-uglify'),
browserify = require('browserify'),
babelify = require('babelify'),
source = require('vinyl-source-stream'),
streamify = require('gulp-streamify')
gulp.task('compress', function() {
process.env.NODE_ENV = 'production';
// 这里仅制定单个index.js文件, browserify会根据
// import和from关键字去提取相关的依赖库。
return browserify('src/index.js')
.transform(babelify)
.bundle()
.pipe(source('bundle.js'))
.pipe(streamify(uglify()))
.pipe(gulp.dest('dist/'))
})
# 编译文件(指的是根据index.js去寻找相关的依赖代码,然后整合、压缩和混淆)。
[root@localhost spa_jsx]# ./node_modules/gulp/bin/gulp.js compress
# 查看编译前的源文件
[root@localhost spa_jsx]# ls -alh src/
total 8.0K
drwxr-xr-x 2 root root 48 Mar 21 00:18 .
drwxr-xr-x 5 root root 104 Mar 21 01:19 ..
-rw-r--r-- 1 root root 169 Mar 21 00:07 index.js
-rw-r--r-- 1 root root 902 Mar 21 00:06 markdown_editor.js
# 查看合并后的文件
[root@localhost spa_jsx]# ls -alh dist/
total 336K
drwxr-xr-x 2 root root 23 Mar 21 01:19 .
drwxr-xr-x 5 root root 104 Mar 21 01:19 ..
-rw-r--r-- 1 root root 334K Mar 21 01:19 bundle.js
提示: .babalrc文件用来声明babel环境变量,像.bashrc一样。如果不声明.babelrc的话,那么执行gulpfile.js时就会报错。 若不想声明.babelrc文件,但又要编译es2015的代码,那么可以在将gulpfile.js文件中的.transform(babelify)
改为.transform(babelify, {presets: ["es2015", "react"]})
即可。
小结: 这个例子是提供单个index.js文件,browserify会根据import和from关键字去提取相关的依赖库。
使用browserify压缩混淆(不采用gulp)
不使用.babelrc
# 安装 uglifyify
[root@localhost spa_jsx]# cnpm install uglifyify --save-dev
# 清除原来的文件
[root@localhost spa_jsx]# rm dist/* -rf
# 压缩混淆
# 这里要特别注意:命令中的[]两边一定要有空格,否则会报模块找不到。
[root@localhost spa_jsx]# NODE_ENV=productioin browserify -t [ babelify --presets [ react es2015 ] ] src/index.js | ./node_modules/uglify-js/bin/uglifyjs -c > dist/bundle.js
# 查看压缩混淆后的文件
[root@localhost spa_jsx]# ls -alh dist/
total 472K
drwxr-xr-x 2 root root 20 Mar 23 02:16 .
drwxr-xr-x 5 root root 106 Mar 22 21:47 ..
-rw-r--r-- 1 root root 471K Mar 23 02:17 bundle.js
使用.babelrc
# 清除原来的文件
[root@localhost spa_jsx]# rm dist/* -rf
# 创建.babelrc文件
[root@localhost spa_jsx]# vim .babelrc
{ presets: [ "react", "es2015" ] }
# 压缩混淆
[root@localhost spa_jsx]# NODE_ENV=productioin browserify -t [ babelify ] src/index.js | ./node_modules/uglify-js/bin/uglifyjs -c > dist/bundle.js
# 查看压缩混淆后的文件
[root@localhost spa_jsx]# ls dist/ -alh
total 472K
drwxr-xr-x 2 root root 20 Mar 23 02:16 .
drwxr-xr-x 5 root root 122 Mar 23 02:19 ..
-rw-r--r-- 1 root root 471K Mar 23 02:20 bundle.js
使用npm + browserify
# 在package.json中加入npm脚本指令
[root@localhost spa_jsx]# cat package.json
{
"devDependencies": {
"babel": "^6.23.0",
"babel-core": "^6.24.0",
"babel-preset-es2015": "^6.24.0",
"babel-preset-react": "^6.23.0",
"babelify": "^7.3.0",
"browserify": "^14.1.0",
"gulp": "^3.9.1",
"gulp-babel": "^6.1.2",
"gulp-sourcemaps": "^2.4.1",
"gulp-streamify": "^1.0.2",
"gulp-uglify": "^2.1.2",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-remarkable": "^1.1.1",
"reactify": "^1.1.1",
"uglifyify": "^3.0.4",
"vinyl-source-stream": "^1.1.0"
},
"scripts": {
"clean": "rm -rf dist/*"
"build": "NODE_ENV=productioin browserify -t [ babelify ] src/index.js | ./node_modules/uglify-js/bin/uglifyjs -c > dist/bundle.js"
}
}
# 执行指令(清除目录)
[root@localhost spa_jsx]# npm run clean
> @ clean /root/spa_jsx
> rm -rf dist/*
# 压缩混淆
[root@localhost spa_jsx]# npm run build
# 查看压缩混淆后的文件
[root@localhost spa_jsx]# ls -alh dist/
total 472K
drwxr-xr-x 2 root root 23 Mar 23 02:44 .
drwxr-xr-x 5 root root 122 Mar 23 02:43 ..
-rw-r--r-- 1 root root 471K Mar 23 02:44 bundle.js