前端技术框架
如今的前端技术日趋成熟,再也不是以前html+js+css的时代了。
当然,比起后端的成熟,前端还处于一个混乱时期,但是很多技术开始崭露头角。基本的思想也是越来越趋向于面向组件化,
版本化,可复用性等后端的思想。也许未来,前端后端又和在一起了,想起了很久以前的swing,确实怀念。
历史
所谓前端,就是用户直接接触的东西,直接面对用户。早期的html只是个标记,并不能动态展示,后来加入js脚本语言,可以
做些动态的东西,然后css也统一了样式风格,似乎一切都美好起来了。但是,大多数的框架还是动态生成html页面,类似JSP,ASP,
PHP这些,都是由后端动态生成html,然后浏览器解读。这样的问题就是,后端的数据问题和前端的页面美化问题纠缠在一起。
ajax是个革新者,不再一页一页的动态生成前端页面,而是局部更新数据。当然,无论如何,浏览器这个障碍确实是无法跨越。
各种浏览器,很难统一兼容,前端开发者还是需要操作各种浏览器的ODM元素。jquery极大简化了对DOM的操作,所以一下火了起来,
几乎无所不用。前端技术不断发展,事实上,与后端一样,我们都想一劳永逸,避开那些重复的体力劳动。这就是我们的目标是:
可复用,可扩展,可阅读,可维护……
目标
复用是最迫切的渴望,至少能够做代码搬运工。扩展可不是在原有代码上改动,而是新增的方式。可读性,也是入门门槛,可读性强的代码
至少能够使人心情舒畅。可维护,就是以上几点都加上,那么维护起来就很惬意。
如何做
安装node 6.3
好了,废话太多,直接切入主题,后端的版本依赖,打包问题,我们有maven,gradle等工具,这些工具使我们清晰的了解一个项目。
并且在测试,部署,等等问题上都可以很好的集成。那么前端呢?nodejs提供了npm,这里可以看成是maven一样的工具。
首先下载https://nodejs.org/dist/v6.9.1/node-v6.9.1-x64.msi (linux版本请到主页下载 https://nodejs.org/en/ )
安装完成,请在命令行执行
C:\node --version
v6.3.0
C:\npm --version
3.10.3
npm设置
这里只需要配置下远程的库地址
使用以下命令
npm config set registry https://registry.npm.taobao.org/
这里实际上可以做私有的库,使用的是国内的淘宝镜像。只是为了快点。
首次使用,在webapp目录下,使用
npm install
会自动安装所有模块到 node_modules 目录下。这个目录的东西请不要提交到git
安装webpack
webpack 是用来打包的,当然打包过程中也对代码做了转换,所以我们可以使用es6,而最后再es5环境中执行。具体的webpack,下面
会说到。但是首先,先安装。
npm install webpack -g
g 表示全局
webpack安装好以后,使用起来也是很方便,
如果需要调试,可以使用
webpack -d
d会生成map文件,调试需要,映射原文件
如果上线,可用
webpack -p
如果需要动态调试,可以加上
webpack --watch -d
watch选项动态监控文件改变。有改变自动重新打包。
目录结构
工具好了,那么他们在目录中是一个什么样的结构呢?
* --build
* --common.js
* --common.js.map
* --main.js
* --main.js.map
* --
* --css
* --base.css
* --node_modules
* --src
* --main.js
* --index.html
* --package.json
* --webpack.config.js
build是打包后的最终目录,如果使用了d选项,那么我们可以看到map文件。
css目录存放css文件
node_modules目录下,是安装的各种组件。执行npm install时候安装的
src则是存放我们源码的地方
index.html可以理解成入口文件,最终加载我们的成果的。
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<link href="build/main.css" rel="stylesheet" type="text/css">
<link href="build/common.css" rel="stylesheet" type="text/css">
<title>标题</title>
</head>
<body>
<div id="wrap"></div>
</body>
<script src="./build/common.js"></script>
<script src="./build/main.js"></script>
</html>
package.json 打开发现很像maven的pom文件
{
"name": "webpk",
"version": "1.0.0",
"description": "mytest",
"main": "index.js",
"scripts": {
"test": "test"
},
"repository": {
"type": "git",
"url": ".."
},
"keywords": [
"test"
],
"author": "yinsx",
"license": "MIT",
"devDependencies": {
"webpack": "^1.13.3"
},
"dependencies": {
"style-loader": "^0.13.1",
"url-loader": "^0.5.7"
}
}
此文件可以用命令生成
npm init
接下根据提示一步一步完成即可。
最后是这个文件webpack.config.js,如果只是打包,估计也没啥讲的。
这里的配置,主要告诉webpack,打什么包,如何打包,同时如何处理各种文件(js,css,icon等)。
这里给个简易配置
var webpack = require('webpack');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
"main":"./src/main.js"
},
output: {
path:'./build',
filename:"[name].js"
},
module:{
loaders:[
{test:/\.jsx$/,loader:'babel-loader!jsx-loader?harmony'},
//css load
{test:/\.css$/,loader:ExtractTextPlugin.extract("style-loader","css-loader")},
{test:/\.js$/,
loader:'babel',
query:{
cacheDirectory:true,
plugins:[
"transform-decorators-legacy",
"transform-class-properties",
],
presets:["es2015","react"]}
},
{test:/\.(png|jpg)$/,loader:'url-loader?limit=8192'}
]
},
resolve:{
extensions:["",".js",".jsx",".json"],
alias: {
jquery: "jquery/src/jquery"
}
},
plugins:[
new ExtractTextPlugin("[name].css"),
new CommonsChunkPlugin({
names:['common'],
minChunks:Infinity
})
],
};
webpack.config.js 配置
在此过程中,我们会遇到很多问题。
第一句 require("webpack")这个webpack从何而来呢?
这就是我们开始安装的webpack,可以使用命令
npm install url-loader -save|-save-dev
这里save或者save-dev会把依赖存入package.json中
安装好这些组件,就可以在配置的时候使用了。
var ExtractTextPlugin = require("extract-text-webpack-plugin");
这句,引入一个外部插件,主要作用是把css文件独立作为.css,不打包到脚本中。这样可以使用link引用,而不是使用
style内嵌。
在plugins里,我们看到使用方法(创建):
pulugins:[
new ExtractTextPlugin("[name].css")
]
使用
module{
loaders:[
{test:/\.css$/,loader:ExtractTextPlugin.extract("style-loader","css-loader")},
]
}
CommonsChunkPlugin 这个插件则是用来提取公共的模块。这样我们能够控制把相似的模块打到一个包中。
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
p1: "./page1",
p2: "./page2",
p3: "./page3",
ap1: "./admin/page1",
ap2: "./admin/page2"
},
output: {
filename: "[name].js"
},
plugins: [
new CommonsChunkPlugin("admin-commons.js", ["ap1", "ap2"]),
new CommonsChunkPlugin("commons.js", ["p1", "p2", "admin-commons.js"])
]
};
entry 是入口文件(输入)可以是一个对象。
output是输出文件。
module则是各种加载器用于加载不同的语法语言
从module我们看到,加载css的,加载图片的,还有加载jsx的,加载js的
这里的加载js比较复杂。
module:{
loaders:[
{test:/\.jsx$/,loader:'babel-loader!jsx-loader?harmony'},
//css load
{test:/\.css$/,loader:ExtractTextPlugin.extract("style-loader","css-loader")},
{test:/\.js$/,
loader:'babel',
query:{
cacheDirectory:true,
plugins:[
"transform-decorators-legacy",
"transform-class-properties",
],
presets:["es2015","react"]}
},
{test:/\.(png|jpg)$/,loader:'url-loader?limit=8192'}
]
},
babel是个什么东西呢?其实就是一个转化器,他把ES6的语法转化成ES5,query是获取加载器的参数。曾经在这里坑了很久,
就是因为,忽略了版本问题,网上很多都是babel5的配置,而我的版本却是 babel6
* babel6
"babel-core":"6.18.2",
"babel-loader":"6.2.7",
* babel 5
"babel-core": "^5.8.25",
"babel-loader": "^5.3.2",
对于6的配置,可以参考前面的配置,对于5,则可以参考一下配置
module: {
loaders: [{
test: /\.js$/,
loader: 'babel-loader',
query: {
optional: ["es7.decorators", "es7.classProperties"]
}
}, {
test: /\.jsx$/,
loader: 'babel-loader!jsx-loader?harmony'
},{test:/\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader")},
{test: /\.scss$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")},
{test: /\.less$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")},
{ test: /\.(png|jpg|gif)$/, loader: 'url-loader?name=img/[hash:8].[name].[ext]' },
{ test: /\.(eot|ttf|svg|woff)$/, loader: 'url-loader?name=font/[hash:8].[name].[ext]' }]
},
resolve 其实简化了我们的后缀,也就是不需要写后缀。比如 require("abc")
使用别名alias也可以配置搜索路径,jquery就是一个独特的路径
module.exports = {
resolve: {
alias: {
js: path.join(__dirname, "src/scripts"),
src: path.join(__dirname, "src/scripts"),
styles: path.join(__dirname, "src/styles"),
img: path.join(__dirname, "src/img")
},
root: [
path.join(__dirname, "bower_components")
]
},
plugins: [
new webpack.ResolverPlugin(
new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin(".bower.json", ["main"])
)
]
}
好了,到目前,基本的配置就完成了。那么下面是我们如何开发呢?
编写代码
代码编写,最终有个html页面加载我们开发的页面。
还记得index.html吗?
里面有个div id="wrap"
这里就是入口的关键,看我们的代码src/main.js
import React,{ Component } from 'react';
import ReactDom from 'react-dom';
require("../css/base.css");
class Frame extends Component {
constructor(props) {
super(props);
}
render() {
return <div className="frame">
<div className='header'>{this.props.contents}</div>
</div>
}
};
class Page extends Component {
constructor(props) {
super(props);
}
render(){
return <div className="homePage">
<Frame contents="longen1">this is comment </Frame>
<Frame contents="logen2"> this is another comment </Frame>
</div>
}
};
export default Page;
ReactDom.render(<Page></Page>,document.getElementById("wrap"));
如果你是写java的,或者c# C++的都应该会有亲切感吧。这就是后端
化的前台代码。
在这个过程中,如果找不到相应的组件,请手动安装
npm install xxx
如果只是开发打包或编译的时候需要,那么--save-dev即可,如果是上线后用,则--save
执行了save后,可以再package.json中看到相应的项,这比maven的pom方便多了。
最后一句
ReactDom.render(<Page></Page>,document.getElementById("wrap"));
实现了与开始的index.html对接
接下来,就是要学习react,ES6的语法了。