node.js 开发之react 学习1
context:node.js 开发的工具和lib发展的很快,in other worlds, 出现了太多的新东东。
在facebook的威名下的react自然吸引了很多的关注。
下面开始react的第一个学习过程。
转载:
from fakefish
在 Web 开发历程上,我们构建了很多小型的技术解决方案,比如用 HTML 去描述页面结构,CSS 去描述页面样式,JavaScript 去描述页面逻辑,或者你也可以用一些比如 Jade 去取代 HTML,用 Sass 或 Less 去取代CSS,用 CoffeeScript 或者 TypeScript 之类的去取代 JavaScript,不过项目中的依赖可能是一件比较烦恼的事情。(需要安装额外很多的库)
这里有很多为什么我们需要尝试那些新技术的理由。不管我们用什么,总之,我们还是希望使用那些能够处理在浏览器端的方案,所以出来了编译方案。历史上已经有很多分享了,比如 Make 可能是很多解决方案中最知名且是可行的方案。Grunt 和 Gulp 是在是前端的世界中最流行的解决方案,他们两个都有很多非常有用的插件。NPM(Node.js 的包管理器)则包含了他们两个。
Grunt 是相比后面几个更早的项目,他依赖于各种插件的配置。这是一个很好的解决方案,但是请相信我,你不会想看到一个 300 行的 Grunt 文件。如果你好奇 Grunt 的配置会如何,那么这里是有个从 Grunt 文档 的例子:
module.exports = function(grunt) {
grunt.initConfig({
jshint: {
files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
options: {
globals: {
jQuery: true
}
}
},
watch: {
files: ['<%= jshint.files %>'],
tasks: ['jshint']
}
});
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['jshint']);
};
Gulp 提供了一个不一样的解决方案,而不是依赖于各种插件的配置。Gulp 使用了一个文件流的概念。如果你熟悉 Unix,那么 Gulp 对你来说会差不多,Gulp 会提供你一些简单化的操作。在这个解决方案中,是去匹配一些文件然后操作(就是说和 JavaScript 相反)然后输出结果(比如输出在你设置的编译路径等)。这里有一个简单的 Gulp文件的例子:
var gulp = require('gulp');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var del = require('del');
var paths = {
scripts: ['client/js/**/*.coffee', '!client/external/**/*.coffee'],
};
// 不是所有的任务需要使用 streams
// 一个 gulpfile 只是另一个node的程序,所以你可以使用所有 npm 的包
gulp.task('clean', function(cb) {
// 你可以用 `gulp.src` 来使用多重通配符模式
del(['build'], cb);
});
gulp.task('scripts', ['clean'], function() {
// 压缩和复制所有 JavaScript (除了第三方库)
// 加上 sourcemaps
return gulp.src(paths.scripts)
.pipe(sourcemaps.init())
.pipe(coffee())
.pipe(uglify())
.pipe(concat('all.min.js'))
.pipe(sourcemaps.write())
.pipe(gulp.dest('build/js'));
});
// 监听文件修改
gulp.task('watch', function() {
gulp.watch(paths.scripts, ['scripts']);
});
// 默认任务(就是你在命令行输入 `gulp` 时运行)
gulp.task('default', ['watch', 'scripts']);
这些配置都是代码,所以当你遇到问题也可以修改,你也可以使用已经存在的 Gulp 插件,但是你还是需要写一堆模板任务。
处理 JavaScript 模块一直是一个大问题,因为这个语言在 ES6 之前没有这方面的概念。因此我们还是停留在90年代,各种解决方案,比如提出了 AMD。在实践中只使用 CommonJS ( Node.js 所采用的格式)会比较有帮助,而让工具去处理剩下的事情。它的优势是你可以发布到 NPM 上来避免重新发明轮子。
Browserify 解决了这个问题,它提供了一种可以把模块集合到一起的方式。你可以用 Gulp 调用它,此外有很多转换小工具可以让你更兼容的使用(比如 watchify 提供了一个文件监视器帮助你在开发过程中更加自动化地把文件合并起来),这样会省下很多精力。毋庸置疑,一定程度来讲,这是一个很好的解决方案。
Webpack 扩展了 CommonJs 的 require 的想法,比如你想在 CoffeeScript、Sass、Markdown 或者其他什么代码中 require 你想要的任何代码的话,那么 Webpack 正是做这方面的工作。它会通过配置来取出代码中的依赖,然后把他们通过加载器把代码兼容地输出到静态资源中。这里是一个 Webpack 官网 上的例子:
module.exports = {
entry: "./entry.js",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" }
]
}
};
接下来的我们会使用 Webpack 来构建项目来展示它的能力。你可以用其他工具和 Webpack 一起使用。它不会解决所有事情,只是解决一个打包的难题,无论如何,这是在开发过程中需要解决的问题。
开始使用 Webpack 非常简单,这里会展示给你看使用它的一个简单的项目。
第一步,为你的项目新建一个文件夹。然后输入 npm init,然后填写相关问题。这样会为你创建了 package.json,不用担心填错,你可以之后修改它。当然,如果喜欢,你可以自己手动创建一个package.json文件,而不要使用npm init来操劳。
npm init 命令说明:
npm init [-f|--force|-y|--yes]
This will ask you a bunch of questions, and then write a package.json for you.
接下来我们安装 Webpack,我们要把它安装在本地,然后把它作为项目依赖保存下来。这样你可以在任何地方编译(服务端编译之类的)。
输入 npm i webpack –save-dev。如果你想运行它,就输入 node_modules/.bin/webpack。
推荐: 学习阶段,还是安装global模式,这样可以直接使用webpack
此项目的目录结构长这样:
我们会使用 Webpack工具, 基于我们的 /app 来自动创建 bundle.js 。
接下来,我们来设置 webpack.config.js。
把webpack.config.js修改一下,内容如下:
var path = require('path');
module.exports = {
entry: path.resolve(__dirname, 'app/main.js'),
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
};
现在我们有了一个最简单的配置,我们需要去编译一下,让我们开始一个经典的 Hello World,设置 /app 像这样:
app/component.js
'use strict';
module.exports = function () {
var element = document.createElement('h1');
element.innerHTML = 'Hello world';
return element;
};
app/main.js
'use strict';
var component = require('./component.js');
document.body.appendChild(component());
现在在命令行运行 webpack,然后你的应用会开始编译,一个 bundle.js 文件就这样出现在你的 /build 文件夹下,需要在 build/ 下的 index.html 去启动项目。
build/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
这个文件可以使用webpack的 html-webpack-plugin 来生成。如果你觉得新奇,可以操作一下。使用它几乎就只是一个配置的问题。通常使用 Webpack 来进行工作就是这么个套路。
只要双击build/ index.html 或者设置一个 Web 服务指向 build/ 文件夹。
类型make,或者java的ant、maven, 通过 npm 你可以执行build构建、运行、打开服务……,只要你在 package.json 中设置 scripts 的值就可以了,然后调用对应的指令就可以了。
在这个案例中我们把编译步骤放到 npm run build 中执行:
"scripts": {
"build": "webpack"
}
这时,就可以运行npm run build执行我们在package.js中的build项了。
当项目越发复杂的时候,这样的方法会变得越来越有效。你可以把所有复杂的操作隐藏在 scripts 里面来保证界面的简洁。
不过这种方法会导致潜在的问题,就是如果你使用一些特殊的指令的时候,它们只能在 Unix 环境中使用。所以如果你需要考虑一些未知的环境中的话,那么 gulp-webpack 会是一个好的解决方案。
注意 NPM 会找到 Webpack,npm run 会把他临时加到 PATH来让我们这个神奇的命令工作。
如果需要一直输入 npm run build 确实是一件非常无聊的事情,幸运的是,我们可以把让他安静的运行,让我们设置 webpack-dev-server。
第一步,输入 npm i webpack-dev-server –save,安装webpack-dev-server。这会耗费比较长的时间,保持耐心。
接着,我们需要去调整 package.json scripts 部分去包含这个指令,下面是基本的设置:
package.json
{
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build"
}
}
当你在命令行里运行 npm run dev 的时候他会执行 dev 属性里的值。这是这些指令的意思:
总结一下,当你运行 npm run dev 的时候,会启动一个 Web 服务器,再监听文件修改,然后自动重新合并打包bundle你的代码。真的非常简洁!
现在,访问 http://localhost:8080/webpack-dev-server/index.html 你会看到效果了。
你看到的页面是有webpack-dev-server提供服务的,所以页面上由其注入了服务状态的信息。而不是只有Hello World显示。
当运行 webpack-dev-server 的时候,它会监听你的文件修改。当项目重新bundle合并之后,会通知浏览器刷新。为了能够触发这样的行为,你需要把你的 index.html 放到 build/ 文件夹下,然后做这样的修改:
build/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
</head>
<body>
<script src="http://localhost:8080/webpack-dev-server.js"></script>
<script src="bundle.js"></script>
</body>
</html>
接着,在webpack.config.js中,我们需要增加一个脚本当发生改动的时候去自动刷新应用–自动bundle,你需要在配置中增加一个入口点。
var path = require('path');
module.exports = {
entry: ['webpack/hot/dev-server', path.resolve(__dirname, 'app/main.js')],
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
};
就是这些,现在,修改一下index.html,不需要手动build,直接刷新页面,你可以看到新的修改页面了。
Webpack 允许你使用不同的模块模式,如AMD、CommonJS…,但是 在一个项目中,“底层”必须使用同一种实现– 只需要选择一种模式。
比如:
import MyModule from './MyModule.js';
var MyModule = require('./MyModule.js');
define(['./MyModule.js'], function (MyModule) {
});
一个模块需要使用它的文件路径来加载,看一下下面的这个结构:
/app
/modules
MyModule.js
main.js (entry point)
utils.js
打开 main.js 然后可以通过下面两种方式引入 app/modules/MyModule.js
app/main.js
// ES6
import MyModule from './modules/MyModule.js';
// CommonJS
var MyModule = require('./modules/MyModule.js');
最开始的 ./ 是 “相对当前文件路径”。
在MyModule.js中打开utils,打开 MyModule.js 然后引入 app/utils:
app/modules/MyModule.js
// ES6 相对路径
import utils from './../utils.js';
// ES6 绝对路径
import utils from '/utils.js';
// CommonJS 相对路径
var utils = require('./../utils.js');
// CommonJS 绝对路径
var utils = require('/utils.js');
相对路径是相对当前目录。绝对路径是相对入口文件,此项目中是 main.js。
答案是:不,你不需要去特意去使用 .js。但是如果你引入之后高亮会更好。你可能有一些 .js 文件和一些 .jsx 文件,甚至一些图片和 css 可以用 Webpack 引入,甚至可以直接引入 node_modules 里的代码和特殊文件。
记住,Webpack 只是一个模块合并!也就是说你可以设置他去加载任何你写的匹配,只要有一个加载器。