【前端知识点】webpack 打包 + es6 + react入门(一)webpack打包

webpack 打包 + es6 + react入门

本文主要针对webpack打包流程,注意事项,es6新特性变化,以及es6 开发react的入门教程:

  • webpack打包流程
  • webpack注意事项
  • webpack,gulp,grunt差异对比
  • webpack进阶:关于加载优化与缓存
  • es6 新标准及新特性
  • es6 核心特性分析
  • react 基本语法
  • react 生命周期
  • react 父子组件的通信总结

【第一部分】Webpack入门


webpack打包流程


React开发和模块管理的主流工具webpack也被大家所熟知。
web开发中常用到的静态资源主要有JavaScript、CSS、图片、Jade等文件,webpack中将静态资源文件称之为模块。webpack是一个module bundler(模块打包工具),其可以兼容多种js书写规范,且可以处理模块间的依赖关系,具有更强大的js模块化的功能。

【前端知识点】webpack 打包 + es6 + react入门(一)webpack打包_第1张图片

webpack特性

webpack具有requireJs和browserify的功能,但仍有很多自己的新特性:

序号 特点 备注
1 对 CommonJS 、 AMD 、ES6的语法做了兼容 兼容性强
2 对js、css、图片等资源文件都支持打包 打包范围广
3 串联式模块加载器以及插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、ES6的支持 灵活易扩展
4 有独立的配置文件webpack.config.js 独立配置,高内聚
5 可以将代码切割成不同的chunk,实现按需加载,降低了初始化时间 按需,高效,低耦合
6 支持 SourceUrls 和 SourceMaps,易于调试 [不很懂]就是即使代码压缩,也可以转化为非混淆压缩形式调试
7 具有强大的Plugin接口,大多是内部插件,使用起来比较灵活 灵活
8 webpack 使用异步 IO 并具有多级缓存。这使得 webpack 很快且在增量编译上更加快 异步,缓存,性能优

1.相比Grunt,WebPack除了具备丰富的插件外,同时带有一套加载(Loader)系统。使它支持多种规范的加载方式,包括ES6、CommonJS、AMD等方式,这是Grunt、Gulp所不具备的。
2.代码混淆的角度来看,WebPack更加的极致
3.代码分片为处理单元(而不是文件),使得文件的分片更为灵活。

Webpack安装和配置

1.安装
webpack 可以作为 全局的npm模块安装,也可以在 当前项目中安装。
npm install -g webpack //全局安装
npm install --save-dev webpack //产品模式用dependencies,开发模式用devDep; save就是存到依赖列表里package.json

全局安装的webpack,直接执行webpack命令,会默认使用当前目录的webpack.config.js作为配置文件。如果要指定另外的配置文件,可以执行:

webpack -config webpack.chauncey.config.js //指定新文件
配置
每个项目下需配置一个webpack.config.js, 如同gulpfile.js/Gruntfile.js, 通俗一点,他就是你的一个初始化设置,配置项,告诉webpack,你想怎么去处理你的文件。

环境变量
通过NODE_ENV可以来设置环境变量(默认值为development)。区分开发和生产环境,对于文件的不同处理。
linux & mac: export NODE_ENV=production
windows:set NODE_ENV=production
运行前可以设置当前环境,SET NODE_ENV=production(开发环境)
set PORT=1234设置接口

entry
entry参数: 打包的输入文件,参数值代表输出后文件形式,字符串(单个文件)、数组(一大个文件)、对象(不同属性为不同文件)

{
    entry: {
        page1: "./page1",
        //支持数组形式,将加载数组中的所有模块,但以最后一个模块作为输出
        page2: ["./entry1", "./entry2"],
        page3: {
            subp1: "./sp1",
            subp2: "./sp2"
        }

    },
    output: {
        path: "dist/js/page",//目标目录【文件夹】
        publicPath: "/output/",
        filename: "[name].bundle.js"
    }
}

output
output参数为对象,定义了输出文件的位置及名字

    output: {
        path: "dist/js/page",//打包文件存放的绝对路径
        publicPath: "/output/",//网站运行时的访问路径
        filename: "[name].bundle.js"//打包后的文件名
    }

当我们在entry中定义构建多个文件时,filename可以对应的更改为[name].js用于定义不同文件构建后的名字.

module
在webpack中JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,图片等静态文件都是模块,不同模块的加载是通过模块加载器(webpack-loader)来统一管理的。loaders之间是可以串联的,一个加载器的输出可以作为下一个加载器的输入,最终返回到JavaScript上:

module: {
   //加载器配置
   loaders: [
       //.css 文件使用 style-loader 和 css-loader 来处理
       { test: /\.css$/, loader: 'style-loader!css-loader' },

       //.js 文件使用 jsx-loader 来编译处理
       { test: /\.js$/, loader: 'jsx-loader?harmony' },

       //.scss 文件使用 style-loader、css-loader 和 sass-loader 来编译处理
       { test: /\.scss$/, loader: 'style!css!sass?sourceMap'},

       //图片文件使用 url-loader 来处理,小于8kb的直接转为base64
       { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
   ]
}

其中, test:表示匹配的资源类型
loader或loaders:表示用来加载这种类型资源的loader(加载器);[可参考using loaders]
用来定义loader的串联关系,”-loader”是可以省略不写的,多个loader之间用“!”连接起来,但所有的加载器都需要通过 npm 来加载。

此外,还可以添加用来定义png、jpg这样的图片资源在小于10k时自动处理为base64图片的加载器:

{ test: /\.(png|jpg)$/,loader: 'url-loader?limit=10000'}

给css和less还有图片添加了loader之后,我们不仅可以像在node中那样require js文件了,我们还可以require css、less甚至图片文件:

 require('./bootstrap.css');
 require('./myapp.less');
 var img = document.createElement('img');
 img.src = require('./glyph.png');

注意,require()还支持在资源path前面指定loader,即require(![loaders list]![source path])形式:

require("!style!css!less!bootstrap/less/bootstrap.less");
// “bootstrap.less”这个资源会先被"less-loader"处理,
// 其结果又会被"css-loader"处理,接着是"style-loader"
// 可类比pipe操作

require()时指定的loader会覆盖配置文件里对应的loader配置项。

resolve
webpack在构建包的时候会按目录的进行文件的查找,resolve属性中的extensions数组中用于配置程序可以自行补全文件后缀

resolve: {
    //查找module的话从这里开始查找
    root: '/pomy/github/flux-example/src', //绝对路径

    //自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
    extensions: ['', '.js', '.json', '.scss'],

    //模块别名定义,方便后续直接引用别名,无须多写长长的地址
    alias: {
        AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可
        ActionType : 'js/actions/ActionType.js',
        AppAction : 'js/actions/AppAction.js'
    }
}

然后我们想要加载一个js文件时,只要require(‘common’)就可以加载common.js文件了。
注意一下, extensions 第一个是空字符串! 对应不需要后缀的情况.

plugin
webpack提供了[丰富的组件]用来满足不同的需求,当然我们也可以自行实现一个组件来满足自己的需求:

plugins: [
     //your plugins list
 ]

在webpack中编写js文件时,可以通过require的方式引入其他的静态资源,可通过loader对文件自动解析并打包文件。通常会将js文件打包合并,css文件会在页面的header中嵌入style的方式载入页面。但开发过程中我们并不想将样式打在脚本中,最好可以独立生成css文件,以外链的形式加载。这时extract-text-webpack-plugin插件可以帮我们达到想要的效果。需要使用npm的方式加载插件,然后参见下面的配置,就可以将js中的css文件提取,并以指定的文件名来进行加载。

npm install extract-text-webpack-plugin --save-dev
plugins: [
    new ExtractTextPlugin('styles.css')
]

externals
当我们想在项目中require一些其他的外部类库或者API,而又不想让这些类库的源码被构建到运行时文件中,这在实际开发中很有必要。此时我们就可以通过配置externals参数来解决这个问题:

externals: {
    "jquery": "jQuery"
}

这样我们就可以放心的在项目中使用这些API了:var jQuery = require(“jquery”);

context
当我们在require一个模块的时候,如果在require中包含变量,像这样:

require("./mods/" + name + ".js");

那么在编译的时候我们是不能知道具体的模块的。但这个时候,webpack也会为我们做些分析工作:

1.分析目录:’./mods’;
2.提取正则表达式:’/^.*.js$/’;

于是这个时候为了更好地配合webpack进行编译,我们可以给它指明路径,像在cake-webpack-config中所做的那样(我们在这里先忽略abcoption的作用):

var currentBase = process.cwd();
 var context = abcOptions.options.context ? abcOptions.options.context : 
 path.isAbsolute(entryDir) ? entryDir : path.join(currentBase, entryDir);

关于 webpack.config.js 更详尽的配置可以参考这里

webpack常用命令

webpack的使用通常有三种方式:

1、命令行使用:webpack

var webpack = require('webpack');
webpack({
//configuration
}, function(err, stats){});

3、默认使用当前目录的webpack.config.js作为配置文件。如果要指定另外的配置文件,可以执行:webpack –config webpack.custom.config.js
webpack 的执行也很简单,直接执行

$ webpack --display-error-details

即可,后面的参数“–display-error-details”是推荐加上的,方便出错时能查阅更详尽的信息(比如 webpack 寻找模块的过程),从而更好定位到问题。
常用命令
webpack的使用和browserify有些类似,下面列举几个常用命令:

即可,后面的参数“--display-error-details”是推荐加上的,方便出错时能查阅更详尽的信息(比如 webpack 寻找模块的过程),从而更好定位到问题。
常用命令
webpack的使用和browserify有些类似,下面列举几个常用命令:

前面的四个命令比较基础,使用频率会比较大,后面的命令主要是用来定位打包时间较长的原因,方便改进配置文件,提高打包效率。

图片打包和静态资源服务器

图片打包
webpack中对于图片的处理,可以通过url-loader来实现图片的压缩。

div.img{
    background: url(../image/xxx.jpg)
}

//或者
var img = document.createElement("img");
img.src = require("../image/xxx.jpg");
document.body.appendChild(img);

针对上面的两种使用方式,loader可以自动识别并处理。根据loader中的设置,webpack会将小于指点大小的文件转化成 base64 格式的 dataUrl,其他图片会做适当的压缩并存放在指定目录中。

module: {
    {
      test: /\.(png|jpg)$/,
      loader: 'url-loader?limit=10000&name=build/[name].[ext]'
    }]
}

对于上面的配置,如果图片资源小于10kb就会转化成 base64 格式的 dataUrl,其他的图片会存放在build/文件夹下。

静态资源服务器

除了提供模块打包功能,Webpack还提供了一个基于Node.js Express框架的开发服务器,它是一个静态资源Web服务器,对于简单静态页面或者仅依赖于独立服务的前端页面,都可以直接使用这个开发服务器进行开发。在开发过程中,开发服务器会监听每一个文件的变化,进行实时打包,并且可以推送通知前端页面代码发生了变化,从而可以实现页面的自动刷新。

Webpack开发服务器需要单独安装,同样是通过npm进行:

npm install -g webpack-dev-server

可以使用webpack-dev-server直接启动,也可以增加参数来获取更多的功能,具体配置可以参见官方文档。默认启动端口8080,通过localhost:8080/webpack-dev-server/可以访问页面,文件修改后保存时会在页面头部看到sever的状态变化,并且会进行热替换,实现页面的自动刷新。

Webpack注意事项-Tips


1.建议,主页尽量做到最精简,毕竟决定用户存留时间。按需。
2.【推荐很好】http://www.cnblogs.com/giveiris/p/5237080.html
【前端构建】WebPack实例与前端性能优化
3.【有雪碧图,gulp和webpack】【基于webpack搭建纯静态页面型前端工程解决方案模板】https://github.com/chemdemo/webpack-seed
4.所有资源都是模块。

Webpack、gulp、grunt异同


webpack实践

webpack安装

npm install webpack -g

webpack配置

// webpack.config.js
var path = require("path");
module.exports = {
  entry: './public/js/entry.js', //演示单入口文件
  output: {
    path: path.join(__dirname, './public/pro'),  //打包输出的路径
    filename: 'bundle.js',            //打包后的名字
    publicPath: "./pro"             //html引用路径,在这里是本地地址。
  }
};

编写入口文件
接下来就编写我们的入口文件 entry.js 和第一个模块文件 module1.js 。我们一切从简,里面只用来加载一个Js模块。

// entry.js
require("./module1"); // 使用CommonJs来加载模块
// module1.js
console.log("hello,world! module1");
document.write("超哥威武");

启动webpack

一切准备好后,我们仅需要在项目根目录下,用命令行 webpack 执行一下即可。

// webpack 命令行的几种基本命令

$ webpack // 最基本的启动webpack方法
$ webpack -w // 提供watch方法,实时进行打包更新
$ webpack -p // 对打包后的文件进行压缩,提供production
$ webpack -d // 提供source map,方便调试。

多模块依赖
跑通webpack打包entry,现在尝试commonjs和amd,两种模块机制。

require(["./module3"], function(){
  console.log("hello,world! module1&&require(module3)");
  document.write("超哥威武");
});
// module2.js,使用的是CommonJs机制导出包
module.exports = function(a, b){
  return a + b;
}
// module3.js,使用AMD模块机制
define(['./module2.js'], function(sum){
  return console.log("1 + 2 = " + sum(1, 2));
})

混用两种不同机制非常不好,这里仅仅是展示用的;
在开发新项目时还是推荐CommonJs或ES2015的Module。ES2015的模块机制,是趋势。【这一块我会报个小错误,没有完全实现】

【loader加载器】

预处理器做一些CoffeeScript 和 Sass 的编译。我们以前要编译这些预处理器,用 gulp相对复杂,webpack可以一次性解决!

在这里我们用Sass和babel编译ES2015为例子,看一下loader是如何使用的。

安装loader

npm install style-loader css-loader url-loader babel-loader sass-loader file-loader --save-dev

配置loader

// webpack.config.js
module.exports = {
  entry: path.join(__dirname, 'src/entry.js'),
  output: {
    path: path.join(__dirname, 'out'),
    publicPath: "./out/",
    filename: 'bundle.js'
  },
  // 新添加的module属性
  module: {
    loaders: [
      {test: /\.js$/, loader: "babel"},
      {test: /\.css$/, loader: "style!css"},
      {test: /\.(jpg|png)$/, loader: "url?limit=8192"},
      {test: /\.scss$/, loader: "style!css!sass"}
    ]
  }
};

【webpack进阶:关于加载优化与缓存,及版本控制】

1.uglify
webpack提供插件UglifyJsPlugin,可以优化(支持压缩、混淆)代码。
配置以下列表,在混淆代码时,以下配置的变量,不会被混淆

new webpack.optimize.UglifyJsPlugin({
    mangle: {
        except: ['$super', '$', 'exports', 'require']
    }
})

以上变量‘ super, ’, ‘exports’ or ‘require’,不会被混淆

example

var UglifyJsPlugin = require("../../node_modules/webpack/lib/optimize/UglifyJsPlugin");

module.exports = {
    entry: "./entry.js",
    output: {
        path: __dirname,
        filename: "bundle.js",
    },
    plugins: [
        //使用丑化js插件
        new UglifyJsPlugin({
            compress: {
                warnings: false
            },
            mangle: {
                except: ['$scope', '$']
            }
        })
    ]
};
//entry.js
define("entry", function () {
    //变量 iabcdef 已引用,混淆
    var iabcdef = 11;
    //变量 $scope 已引用,但不混淆
    var $scope = "scope";

    document.write("entry module" + iabcdef);
    document.write($scope);

    //变量 ixzy 未被引用,剔除
    var ixzy = 3241;
});

2.版本控制
对于静态资源的版本控制,目前微信项目采取办法是版本号作为请求参数,版本号为发布日期,但有两个问题:
1、更新版本时,CDN不能及时更新;
2、没有发生变更的文件也被赋上新版本

Webpack的做法是,生成hash,区分文件。
配置方法

//所有代码块添加hash
module.exports = {
    entry: "./entry.js",
    output: {
        path: "assets/[hash]/",
        publicPath: "assets/[hash]/",
        filename: "bundle.js"
    }
};

【前端知识点】webpack 打包 + es6 + react入门(一)webpack打包_第2张图片

生成单个代码块文件的hash
配置方法

//单个代码块添加hash
module.exports = {
    entry: "./entry.js",
    output: {
        path: "build/",
        publicPath: "build/",
        chunkFilename: "[id].[hash].bundle.js",
        filename: "output.[hash].bundle.js",
    }
};

【关于:chunkFilename意义】
http://react-china.org/t/webpack-output-filename-output-chunkfilename/2256

3.如何缓存
缓存控制要做到两件事情,提到缓存命中率
对于没有修改的文件,从缓存中获取文件
对于已经修改的文件,不要从缓存中获取
围绕这两点,演绎出了很多方案,此处列两种:
不处理,等待用户浏览器缓存过期,自动更新。这是最偷懒的,命中率低一些,同时可能会出现部分文件没有更新,导致报错的情况。

Http头对文件设置很大的max-age,例如1年。同时,给每个文件命名上带上该文件的版本号,例如把文件的hash值做为版本号,topic. ef8bed6c.js。即是让文件很长时间不过期。

当文件没有更新时,使用缓存的文件自然不会出错;

当文件已经有更新时,其hash值必然改变,此时文件名变了,自然不存在此文件的缓存,于是浏览器会去加载最新的文件。

从上面的截图可以看出来,通过WebPack是可以很轻松做到第二点的——只需要给文件名配置上[chunkhash:8]即可,其中8是指hash长度为8,默认是16。

output{
  path: _dirname + '/release/',
  filename: '[chunkhash:8].[name].js',
  chunkFilename: '[name].[chunkhash:8].js'
}

P.S.这样的处理效果已经很好了,但同样有劣处,即浏览器给这种缓存方式的缓存容量太少了,只有12Mb,且不分Host。所以更极致的做法是以文件名为Key,文件内容为value,缓存在localStorage里,命中则从缓存中取,不命中则去服务器取,虽然缓存容量也只有5Mb,但是每个Host是独享这5Mb的。

4.自动生成页面
文件名带上版本号后,每一次文件变化,都需要Html文件里手动修改引用的文件名,这种重复工作很琐碎且容易出错。html内部文件的名字如何动态改变。

使用 HtmlWebpackPlugin 和 ExtractTextPlugin 插件可以解决此问题。

生成带js的页面

【参考】http://www.cnblogs.com/haogj/p/5160821.html

new HtmlWebpackPlugin({
        filename: 'index.html',
        template: __dirname + '/public/index.html',
        inject: true,//是否injection 
        chunks: ['page1'],//所要控制的模块组

        //排序
        chunksSortMode: function(a, b){
            var index = {'page1': 1},
                aI = index[a.origins[0].name],
                bI = index[b.origins[0].name];
            return aI&&bI ? bI - aI : -1;
        }
    }),

生成带css的页面
  new ExtractTextPlugin(“comm.[contenthash:9].css”)

  插件介绍到此为止,然而,还有一个关于同步加载和异步加载的问题,否则入口文件还是会很臃肿。

5.同步/异步加载
一个原则是:首屏需要的同步加载,首屏过后才需要的则按需加载(异步)
同步的代码会被合成并且打包在一起;
异步加载的代码会被分片成一个个chunk,在需要该模块时再加载,即按需加载。
同步加载过多代码会造成文件过大影响加载速度,异步过多则文件太碎,造成过多的Http请求,同样影响加载速度。
同步写法
var TopicItem = require('../topic/topicitem');

异步写法

require.ensure([], function(){
    //to do
});

【遗留问题】

  1. webpackJsonp is not defined
    是因为commonschunkplugin引用了,但是页面没用到。
  2. 路径问题:
    entry: {
    page1: [‘./public/js/entry.js’], //演示单入口文件 path.join(__dirname, ‘./public/pro’)
    page2: [‘./public/js/module1.js’]
    },
    路径必须加./相对地址,否则会报错publick/js**

3.待学习的:
1)webpack在PC项目中的应用
http://web.jobbole.com/85396/
2)基于 Webpack 和 ES6 打造 JavaScript 类库
http://web.jobbole.com/84858/
3)webpack使用优化
http://web.jobbole.com/84847/
4)彻底解决 webpack 打包文件体积过大
http://www.jianshu.com/p/a64735eb0e2b
5)大公司里怎样开发和部署前端代码
https://github.com/fouber/blog/issues/6


【第二部分】ES6新特性


你可能感兴趣的:(react,前端,nodejs)