webpack和gulp的差异:
webpack比gulp功能强大,升级换代出来的,webpack主要用于react vue angular2
1.webpack是什么?
CommonJS和AMD是用于JavaScript模块管理的两大规范,前者定义的是模块的同步加载,主要用于NodeJS;而后者则是异步加载,通过requirejs等工具适用于前端。随着npm成为主流的JavaScript组件发布平台,越来越多的前端项目也依赖于npm上的项目,或者 自身就会发布到npm平台。因此,让前端项目更方便的使用npm上的资源成为一大需求。
web开发中常用到的静态资源主要有JavaScript、CSS、图片、Jade等文件,webpack中将静态资源文件称之为模块。 webpack是一个module bundler(模块打包工具),其可以兼容多种js书写规范,且可以处理模块间的依赖关系,具有更强大的js模块化的功能。Webpack对它们进行统 一的管理以及打包发布,其官方主页用下面这张图来说明Webpack的作用
官网:http://webpack.github.io/docs/
Webpack-handlebook: http://zhaoda.net/webpack-handbook/
Gitbook: http://fakefish.github.io/react-webpack-cookbook/index.html
参考网站:
https://segmentfault.com/a/1190000003970448
https://github.com/ruanyf/webpack-demos
https://segmentfault.com/a/1190000002551952
http://blog.csdn.net/yczz/article/details/49250623
https://github.com/petehunt/webpack-howto#8-optimizing-common-code
2.为什么使用webpack(主要用于单应用程序)
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 很快且在增量编译上更加快
3.快速开始
在项目根目录打开命令窗口引入项目依赖,全局安装
npm install webpack -g // 全局安装webpack
1.1.1 创建配置文件
在项目根目录创建三个或多个webpack配置文件
(1)webpack.base.config.js //公用的配置放在这里面(可通过插件继承)
(2)webpack.develop.config.js //开发环境中用到的配置文件
(3)webpack.publish.config.js //生产环境中用到的配置文件
1.1.2 修改配置文件
注意:开发环境的配置和生产环境的配置是不一样的,具体的配置内容请看
http://webpack.github.io/docs/configuration.html
在项目根目录打开命令窗口引入项目依赖,全局安装
npm install webpack -g // 全局安装webpack
1.1.1 创建配置文件
在项目根目录创建三个或多个webpack配置文件
(1)webpack.base.config.js //公用的配置放在这里面(可通过插件继承)
(2)webpack.develop.config.js //开发环境中用到的配置文件
(3)webpack.publish.config.js //生产环境中用到的配置文件
1.1.2 修改配置文件
注意:开发环境的配置和生产环境的配置是不一样的,具体的配置内容请看以后章节的介绍
详细的请看这里:
http://webpack.github.io/docs/configuration.html
// 这是最基本的一个配置文件
// 编写配置文件,要有最基本的文件入口和输出文件配置信息等
// 里面还可以加loader和各种插件配置使用
var path = require('path');
module.exports = {
entry:path.resolve(__dirname,'src/js/app.js'),
output: {
path: path.resolve(__dirname, 'deploy'),
filename: 'bundle.js',
},
}
1.1.3 运行webpack
1、通过配置文件运行(通用)
(1)在根目录运行webpack的命令,默认会去查找名称为webpack.config.js的文件执行,如果没有就会报配置信息没有配置的错误。
Webpack
(2)这时候我们可以通过运行下面的命令进行配置文件的选择
webpack –-config webpack.develop.config.js
2、通过cli命令运行(了解)
(1)webpack的cli也提供了命令可以进行运行,例如:
Webpack -watch // webpack的监视命令,文件发生变化自动编译
webpack --entry ./entry.js --output-path dist --output-file bundle.js
//配置文件的启动目录和输出目录
webpack 最基本的启动webpack命令
webpack -w 提供watch方法,实时进行打包更新
webpack -p 对打包后的文件进行压缩
webpack -d 提供SourceMaps,方便调试
webpack --colors 输出结果带彩色,比如:会用红色显示耗时较长的步骤
webpack --profile 输出性能数据,可以看到每一步的耗时
webpack --display-modules 默认情况下 node_modules 下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块
webpack --display-error-details 方便出错时能查阅更详尽的信息(比如 webpack 寻找模块的过程),从而更好定位到问题。
(2)你可以运行webpack -h查看webpack的其他命令,自行了解,或者通过英文官网了解webpack Cli部分
3、作为nodejs的api运行(了解)
var webpack = require('webpack');
webpack({
//configuration
}, function(err, stats){});
4、注意:但是我们基本上不用这种直接提供的命令,因为我们需要手动的敲打很多字母,我们现在开发通用的方法都是使用配置文件的方式运行。
4.npm 的script的使用
1、你首先需要安装webpack,这时候不全局安装
npm i webpack --save
2、配置npm的package.json文件中
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"develop": "webpack --config
webpack.develop.config.js",
"publish": "webpack --config
webpack.publish.config.js"
},
3、在根目录打开的命令窗口运行
npm run develop
5.为发布目录启动服务
1、安装webpack-dev-server
npm i webpack-dev-server –save-dev
2、调整npm的package.json scripts 部分中开发命令的配置
{
"scripts": {
"develop": "webpack-dev-server --config webpack.develop.config.js --devtool eval --progress --colors --hot --content-base src",
"publish": "webpack --config webpack.publish.config.js",
"watch": "webpack --config webpack.develop.config.js --watch --hot"
}
}
注释:
webpack-dev-server - 在 localhost:8080 建立一个 Web 服务器
--devtool eval - 为你的代码创建源地址。当有任何报错的时候可以让你更加精确地定位到文件和行号
--progress - 显示合并代码进度
--colors -- hot,命令行中显示颜色!
--content-base 指向设置的输出目录//这点一定是我们的发布目录
3、访问 http://localhost:8080 你会看到效果。
总的来说,当你运行 npm run develop 的时候,会启动一个 Web 服务器,然后监听文件修改,然后自动重新合并你的代码。真的非常简洁!
4、注意
(1)用webpack-dev-server生成bundle.js文件是在内存中的,并没有实际生成
(2)如果引用的文件夹中已经有bundle.js就不会自动刷新了,你需要先把bundle.js文件手动删除
(3)用webstorm的注意了,因为他是自动保存的,所以可能识别的比较慢,你需要手动的ctrl+s一下
5.浏览器的自动刷新
修改webpack.develop.config.js的配置中的entry:
var path = require('path'); module.exports = { entry:[ 'webpack/hot/dev-server', 'webpack-dev-server/client?http://localhost:8080', path.resolve(__dirname,'src/js/app.js') ], output: { path: path.resolve(__dirname, 'deploy'), filename: 'bundle.js', }, module: { loaders: [ { test: /\.css$/, loader: "style!css" } ] } }
6.常用的加载器
Loader:这是webpack准备的一些预处理工具
1>babel-loader:代码预处理加载器
1.编译jsx和ES6到原生js
jsx语法:允许html写在js文件中
安装依赖项:
npm install babel-loader --save-dev
npm install babel-core babel-preset-es2015 babel-preset-react --save-dev
2.修改配置文件
module: { loaders: [ { test: /\.jsx?$/, // 用正则来匹配文件路径,这段意思是匹配 js 或者 jsx loader: 'babel',// 加载模块 "babel" 是 "babel-loader" 的缩写 query: { presets: ['es2015', 'react'] } } ] }
3.运行:
直接从新运行npm run develop即可
2>css-loader :css样式处理加载器
1.下载依赖:
npm install css-loader style-loader --save-dev
2.修改配置文件
{ test: /\.css$/, // Only .css files loader: 'style!css' // Run both loaders 多个加载器,加载顺序是从右到左 }
!
用来定义loader的串联关系,"-loader"是可以省略不写的,多个loader之间用“!”连接起来
***************************************************************
css加载处理:
1、在主入口文件中,比如 src/app.js 你可以为整个项目加载所有的 CSS
Import './project-styles.css';
CSS 就完全包含在合并的应用中,再也不需要重新下载。
2、懒加载(推荐)
如果你想发挥应用中多重入口文件的优势,你可以在每个入口点包含各自的 CSS。
你把你的模块用文件夹分离,每个文件夹有各自的 CSS 和 JavaScript 文件。再次,当应用发布的时候,导入的 CSS 已经加载到每个入口文件中。
3、定制组件css
你可以根据这个策略为每个组件创建 CSS 文件,可以让组件名和 CSS 中的 class 使用一个命名空间,来避免一个组件中的一些 class 干扰到另外一些组件的 class。
4、使用内联样式取代 CSS 文件
在 “React Native” 中你不再需要使用任何 CSS 文件,你只需要使用 style 属性,可以把你的 CSS 定义成一个对象,那样就可以根据你的项目重新来考略你的 CSS 策略。
注意:这点的样式都没有-
3>sass-loader:sass加载器
1.下载依赖:
npm install sass-loader --save-dev
2.修改配置文件:
{ test: /\.scss$/, loader: 'style!css!sass' }
4>url-loader file-loader:图片加载器
1.下载依赖npm install url-loader file-loader --save-dev
2.修改配置文件
{ test: /\.(png|jpg)$/, loader: 'url?limit=25000'//?+limit=25000(图片大小超过limit的值)会将图片路径转换成字符串,反之是base64的字符串
//base64会减少http请求(图片太小了,不用发送请求,)
}
加载器,它会把需要转换的路径变成 BASE64 字符串,在其他的 Webpack 书中提到的这方面会把你 CSS 中的 “url()” 像其他 require 或者 import 来处理。意味着如果我们可以通过它来处理我们的图片文件。
url-loader 传入的 limit 参数是告诉它图片如果不大于 25KB 的话要自动在它从属的 css 文件中转成 BASE64 字符串。
3.大图片的处理方法:
在代码中是一下情况: div.img{ background: url(../image/xxx.jpg) } //或者 var img = document.createElement("img"); img.src = require("../image/xxx.jpg"); document.body.appendChild(img);
你可以这样配置 module: { { test: /\.(png|jpg)$/, loader: 'url-loader?limit=10000&name=build/[name].[ext]' }] }
针对上面的两种使用方式,loader可以自动识别并处理。根据loader中的设置,webpack会将小于指点大小的文件转化成 base64 格式的 dataUrl,其他图片会做适当的压缩并存放在指定目录中。
处理结果:
After launching the server, small.png and big.png will have the following URLs.
<img src="data:image/png;base64,iVBOR...uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">
5>处理font字体
{ test: /\.(woff|eot|ttf|woff2|svg)$/,//多种字体格式 loader: 'url?limit=100000' }
7.部署策略
1>发布配置
*:修改npm的package.json文件
"publish": " webpack --config webpack.publish.config.js -p",
指向生产的配置文件,并且加上了webpack的cli的-p,他会自动做一些优化
*: 修改webpack.publish.config.js文件
var path = require('path'); var node_modules = path.resolve(__dirname, 'node_modules');
module.exports = {
entry: path.resolve(__dirname,'src/js/app.js'),
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
module: {
loaders: [
{
test: /\.jsx?$/, // 用正则来匹配文件路径,这段意思是匹配 js 或者 jsx
loader: 'babel',// 加载模块 "babel" 是 "babel-loader" 的缩写
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.css$/, // 处理css文件
loader: 'style!css' // Run both loaders
},
{
test: /\.scss$/, //处理sass文件
loader: 'style!css!sass'
},
{
test: /\.(png|jpg)$/,
loader: 'url?limit=25000'
}
]
}
}
可以看到,其实生产环境的配置和开发的配置没有太大的不同,主要是把不需要的东西给去掉了
*:再运行 npm run publish
最后会生成一个bundle.js文件
2>合并成单文件
一般情况下只有在下面的情况下才使用单入口模式:
1、应用很小
2、很少会更新应用
3、你不太关心初始加载时间
3>分离第三方包
*:何时分离??
当你的应用依赖其他库尤其是像 React JS 这种大型库的时候,你需要考虑把这些依赖分离出去,这样就能够让用户在你更新应用之后不需要再次下载第三方文件。当满足下面几个情况的时候你就需要这么做了:
1、当你的第三方的体积达到整个应用的 20% 或者更高的时候。
2、更新应用的时候只会更新很小的一部分
3、你没有那么关注初始加载时间,不过关注优化那些回访用户在你更新应用之后的体验。
4、有手机用户。
*:修改配置文件
var webpack=require("webpack");//在头部引入
结果:
注意:记住要把这些文件都加入到你的 HTML 代码中,不然你会得到一个错误:Uncaught ReferenceError: webpackJsonp is not defined
。
4>和gulp的集成
分为使用流和不使用流
http://webpack.github.io/docs/usage-with-gulp.html
gulp + webpack 构建多页面前端项目
http://cnodejs.org/topic/56df76559386fbf86ddd6916
github-demo实际例子: https://github.com/MeCKodo/webpack
8.常用插件
webpack提供了[丰富的组件]用来满足不同的需求,当然我们也可以自行实现一个组件来满足自己的需求:
plugins: [ //your plugins list ]
详细的请看这里:
http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
注释:Word中出现的所有的包,都可以通过npm进行包查找,然后查看具体的使用方法;
1>压缩插件:这个插件是webpack自带的
2>提取css插件
在webpack中编写js文件时,可以通过require的方式引入其他的静态资源,可通过loader对文件自动解析并打包文件。通常会将js 文件打包合并,css文件会在页面的header中嵌入style的方式载入页面。但开发过程中我们并不想将样式打在脚本中,最好可以独立生成css文 件,以外链的形式加载。这时extract-text-webpack-plugin插件可以帮我们达到想要的效果。需要使用npm的方式加载插件,然后 参见下面的配置,就可以将js中的css文件提取,并以指定的文件名来进行加载。
npm install extract-text-webpack-plugin --save-dev
我发现这个有一个问题,就是他只能把css抽出来,但是sass的样式不能分离出来。
var ExtractTextPlugin = require("extract-text-webpack-plugin");
3>创建index.html页面插件
4>自动打开浏览器插件
open-browser-webpack-plugin
https://github.com/baldore/open-browser-webpack-plugin
5> 提取js公共部分插件
CommonsChunkPlugin
6> 提取公共文件
写法二:
7>自定义公共模块抽取
8>ProvidePlugin
插件
自动添加引用插件,全局暴露插件,直接使用
9>删除目录插件
10>拷贝文件插件
11> 合并配置文件插件
webpack-config
https://github.com/mdreizin/webpack-config
12>定义生产环境
new webpack.DefinePlugin({ //去掉react中的警告,react会自己判断 // 'process.env':{ NODE_ENV:'"production"'//另一个值是developer(自动帮你优化js代码) } })
9.其他知识:
1.resolve属性:(自动帮你处理文件的扩展名,建议自己都写上文件扩展名)
webpack在构建包的时候会按目录的进行文件的查找,resolve
属性中的extensions数组中用于配置程序可以自行补全哪些文件后缀:
resolve: { //查找module的话从这里开始查找 root: '/pomy/github/flux-example/src', //绝对路径 //自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名 //注意一下, extensions 第一个是空字符串! 对应不需要后缀的情况. extensions: ['', '.js', '.json', '.scss',’jsx’], //模块别名定义,方便后续直接引用别名,无须多写长长的地址 alias: { AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可 ActionType : 'js/actions/ActionType.js', AppAction : 'js/actions/AppAction.js' } }
2. Externals属性
// externals: { // // 配置了这个属性之后react和react-dom这些第三方的包都不会被构建进js中,那么我们就需要通过cdn进行文件的引用了 // // 前边这个名称是在项目中引用用的,相当于import React from ‘react1’中的react, // //'react1':"react", // 'react1':"react", // 'react-dom1':"react-dom", // '$1':"jQuery" // // },
外部依赖不需要打包进bundle,当我们想在项目中require一些其他的类库或者API,而又不想让这些类库的源码被构建到运行时文件中,这在实际开发中很有必要。
比如:你在页面里通过script标签引用了jQuery:<script src="//code.jquery.com/jquery-1.12.0.min.js"></script>,所以并不想在其他js里再打包进入一遍,比如你的其他js代码类似:
其实就是不是通过require或者import引入的,而是直接写在html中的js地址。
3.chunk(代码分割)
代码使用时才会去下载,不使用不下载,减少网络请求
http://webpack.github.io/docs/code-splitting.html
4.可以在服务端用webpack
node+webpack
5.热加载组件(不刷新浏览器就自动把新的东西更新出来)
http://fakefish.github.io/react-webpack-cookbook/Hot-loading-components.html