一、什么是Webpack?
WebPack可以看做是模块打包机。用于分析项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),将其转换和打包为合适的格式供浏览器使用。
二、WebPack和Grunt以及Gulp相比有什么特性?
Gulp/Grunt是一种能够优化前端开发流程的工具,而WebPack是一种模块化的解决方案。两者本身没有可比性,但如果一定要比较的话,Webpack的处理速度更快更直接,能打包更多不同类型的文件。这使得Webpack在很多场景下可以替代Gulp/Grunt类的工具。
Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译、组合、压缩等任务的具体步骤,然后这些工具可以自动替你完成这些任务。
Webpack的工作方式是:把项目看作一个整体,通过一个给定的主文件(如:main.js),Webpack将从这个文件开始找到项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
三、Webpack的配置和使用
(1)创建一个名为webpackProject的文件夹,保障网络通畅的条件下,使用npm在当前文件夹下安装webpack。在控制台执行以下命令行:
①全局安装webpack
npm install -g webpack
②安装到你的项目目录
npm install webpack --save-dev
执行成功后在当前文件夹下自动生成一个名为node_modules的文件夹。
(2)创建一个package.json的文件,执行命令行 npm init,进行npm的说明性基础配置,可以一直回车。该文件是npm的说明文件,包含丰富的配置信息,如:项目的依赖模块、自定义的脚本任务等等。
(3)
①在当前文件夹下创建文件夹app和public两个文件夹,app文件夹用于存放原始数据和编写的JavaScript模块;public文件夹用于存放供浏览器读取的文件,包含用webpack打包生成的js文件和index.html文件。在app文件夹中创建文件hello.js和main.js;在文件夹public文件夹中创建文件index.html。
②在index.html文件中写入最基础的html代码,它在这里目的在于引入打包后的js文件bundle.js,之后我们还会详细讲述。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webpackProject</title>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
在hello.js中进行配置,返回一个包含html元素的问候信息函数,并依据commonJs规范,导出这个函数模块。
module.exports=function(){
var greet=document.createElement('div');
greet.textContent="Hello Sun Yu , This is a great day !";
return greet;
};
在main.js中引入这个函数模块,并将它返回的节点插入到页面DOM树中。
var Hello = require('./hello.js');
document.getElementById('root').appendChild(Hello());
(4)正式使用webpack:
生成bundel.js的3种方法:
方法一:
执行命令行:webpack 入口文件main.js路径 存放bundle.js的文件夹public路径
(推荐)方法二:
在根目录下新建一个名为webpack.config.js的文件,并在其中进行最最简单的配置。
module.exports={
entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "bundle.js"//打包后输出文件的文件名
}
};
注:“__dirname”(双下划线)是node.js中的一个全局变量,它指向当前执行脚本所在的目录。
它包含入口文件路径和存放打包后文件的地方的路径。在控制台执行命令行:webpack。
(推荐)方法三:
配置package.json文件的
"scripts": { "start": "webpack" },然后执行命令行:npm start
可以看到webpack同时编译了hello.js和main.js生成bundle.js放置于public文件夹下。此时,打开index.html文件,页面显示“Hello Sun Yu , This is a great day !”。
webpack的强大功能:
(请确认您的npm版本在5.0以下,执行npm -v 查看npm版本号,2017/08/14)
1)生成Source Maps(使调试更容易)
开发总是离不开调试,如果可以更加方便的调试当然就能提高开发效率,不过打包后的文件有时候你是不容易找到出错了的地方对应的源代码的位置的,Source Maps就是来帮我们解决这个问题的。通过简单的配置后,Webpack在打包时可以生成source maps,这为我们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试。
在webpack的配置文件webpack.config.js中配置source maps,需要配置devtool。
devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
/**
* 学习阶段以及在小到中性的项目上,eval-source-map是一个很好的选项,
* 不过记得只在开发阶段使用它
*
* cheap-module-eval-source-map方法构建速度更快,但是不利于调试,
* 推荐在大型项目考虑da时间成本是使用。
* **/
2)使用webpack构建本地服务器
让浏览器监测代码的修改,并自动实时刷新修改后的结果。其实Webpack提供一个可选的本地开发服务器,这个本地服务器基于node.js构建,可以实现该功能,不过它是一个单独的组件,在webpack中进行配置之前需要单独安装它作为项目依赖执行命令行:
npm install webpack-dev-server --save-dev
在webpack.config.js中配置devserver.
module.exports={
devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
entry:__dirname+"/app/main.js",
output:{
path:__dirname+"/public",
filename:'bundle.js'
},
devServer: {
contentBase: "./public",//本地服务器所加载的页面所在的目录
historyApiFallback: true,//不跳转
inline: true,//实时刷新
port:8888//启用的端口号
}
};
在package.json中配置字段”start”
{
"name": "sunyuwebpack",
"version": "1.0.0",
"description": "this is a exercise of webpack",
"main": "main.js",
"scripts": {
"test": "sunyu is handsome.",
"start": "webpack-dev-server --inline"
},
"author": "sunyu",
"license": "ISC",
"devDependencies": {
"webpack": "^3.5.4",
"webpack-dev-server": "^2.7.1"
},
"dependencies": {},
"keywords": [
"webpack"
]
}
作为webpack配置选项中的一项,具有以下配置选项
devserver配置选项 |
功能描述 |
contentBase |
默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public"目录) |
port |
设置默认监听端口,如果省略,默认为”8080“ |
inline |
设置为true,当源文件改变时会自动刷新页面 |
historyApiFallback |
在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html |
注意:没有colors属性,可能是版本问题,可根据npm控制台的提示查看可配置的属性。
在命令行执行:npm start;页面中使用http://127.0.0.1:8888/刷新页面,可以看到页面效果。如果改动hello.js里的文本内容,看到页面内容实时刷新。
3)Loaders
通过使用不同的loader,webpack通过调用外部的脚本或工具可以对各种格式的文件进行处理,比如说分析JSON文件并把它转换为JavaScript文件,或者说把下一代的JS文件(ES6,ES7)转换为现代浏览器可以识别的JS文件。或者说对React的开发而言,合适的Loaders可以把React的JSX文件转换为JS文件。
Loaders需要单独安装并且需要在webpack.config.js下的modules关键字下进行配置,Loaders的配置选项包括以下几方面:
①test:一个匹配loaders所处理的文件的拓展名的正则表达式(必须)
②loader:loader的名称(必须)
③include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
④query:为loaders提供额外的设置选项(可选)
把hello.js里的问候消息放在一个单独的JSON文件里,并通过合适的配置使hello.js可以读取该JSON文件的值,配置方法如下,安装可以转换json的loader。
首先执行命令行:npm install json-loader --save-dev
在webpack.config.js中配置
module: {//在配置文件里添加JSON loader
loaders: [
{ test: /\.json$/,
loader: "json-loader" }
]
},
在app文件夹下定义一个config.json,并进行配置:
{
"TestText": "Hi there and greetings from JSON! _SunYu"
}
在hello.js中配置:
var json=require('./config.json');
module.exports=function(){
var des=document.createElement('div');
des.textContent=json.TestText;
return des;
};
执行命令行:npm start,可以看到页面实时刷新显示文本内容”Hi there and greetings from JSON! _SunYu”
4)Babel
Babel其实是一个编译JavaScript的平台,它的强大之处表现在可以通过编译达到以下目的:
①下一代的JavaScript标准(ES6,ES7),这些标准目前并未被当前的浏览器完全的支持;
②使用基于JavaScript进行了拓展的语言,比如React的JSX。
Babel的安装与配置
Babel其实是几个模块化的包,其核心功能位于称为babel-core的npm包中,不过webpack把它们整合在一起使用,但是对于每一个你需要的功能或拓展,你都需要安装单独的包(用得最多的是解析Es6的babel-preset-es2015包和解析JSX的babel-preset-react包)。
我们先来一次性安装这些依赖包
// npm一次性安装多个依赖模块,模块之间用空格隔开。
执行命令行:
npm install babel-core babel-loader babel-preset-es2015 babel-preset-react --save-dev
在webpack.config.js中配置
{ test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',//在webpack的module部分的loaders里进行配置即可
query: { presets: ['es2015','react'] }
}
现在你的webpack的配置已经允许你使用ES6以及JSX的语法了。继续用上面的例子进行测试,不过这次我们会使用React,记得先安装 React 和 React-DOM。
执行命令行:npm install react react-dom --save-dev
然后在hello.js中配置:
import React, {Component} from 'react';
import config from './config.json';
class Greeter extends Component{
render() {
return ( <div> {config.TestText} </div> );
}
}
export default Greeter;
在main.js中配置:
import React from 'react';
import {render} from 'react-dom';
import Greeter from './hello';
render(<Greeter/>, document.getElementById('root'));
执行命令行:npm start
刷新页面,可以看到页面文本效果。
Babel其实可以完全在webpack.config.js中进行配置,但是考虑到babel具有非常多的配置选项,在单一的webpack.config.js文件中进行配置往往使得这个文件显得太复杂,因此一些开发者支持把babel的配置选项放在一个单独的名为 ".babelrc" 的配置文件中。我们现在的babel的配置并不算复杂,不过之后我们会再加一些东西,因此现在我们就提取出相关部分,分两个配置文件进行配置(webpack会自动调用.babelrc里的babel配置选项)
//.babelrc文件,放置在根目录下
{
"presets": ["react", "es2015"]
}
5)CSS
(1)webpack提供两个工具处理样式表,css-loader 和 style-loader,二者处理的任务不同。
css-loader使你能够使用类似 @import 和 url(...)的方法实现require()的功能,
style-loader将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入webpack打包后的JS文件中。
继续上面的例子
//安装css-loader 和 style-loader,执行命令行:
npm install style-loader css-loader --save-dev
在webpack.config.js中配置
{
test: /\.css$/,
loader: 'style-loader!css-loader'//添加对样式表的处理
}
注意:感叹号的作用在于使同一文件能够使用不同类型的loader
CSS modules 技术意在把JS的模块化思想带入CSS中来,通过CSS模块,将所有的类名、动画名默认都只作用于当前模块。Webpack从一开始就对CSS模块化提供了支持,在CSS loader中进行配置后,你所需要做的一切就是把”modules“传递到所需要的地方,然后就可以直接把CSS的类名传递到组件的代码中,且这样做只对当前组件有效,不必担心在不同的模块中具有相同的类名可能会造成的问题。
在webpack.config.js中配置
{
test: /\.css$/,
loader: 'style-loader!css-loader?modules'//添加对样式表CSS的处理
}
在app下创建一个hello.css文件,并进行类child的定义和配置
.child {
color: #0f0;
width:400px;
height:200px;
font-weight: bold;
border:2px solid #00f;
}
导入.child到hello.js中
import React, {Component} from 'react';
import config from './config.json';
import styles from './hello.css';//导入
class Greeter extends Component{
render() {
return (
<div className={styles.child}>//添加类名
{config.TestText}
</div>
);
}
}
export default Greeter;
(2)PostCSS来为CSS代码自动添加适应不同浏览器的CSS前缀。
首先安装postcss-loader 和 autoprefixer(自动添加前缀的插件),执行命令行:
npm install autoprefixer postcss-loader --save--dev
然后,在webpack配置文件中进行设置,只需要新建一个postcss关键字,并在里面申明依赖的插件,如下,现在你写的css会自动根据Can i use里的数据添加不同前缀了。
注释:
Can I Use是一个检测浏览器对JS、HTML5、CSS、SVG或者其他Web前端相关特性支持程度的列表。可以检测的浏览器包括桌面和移动版的主流浏览器:IE, Firefox, Chrome, Safari和 Opera等。
loaders和插件的区别:
loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个,而插件并不直接操作单个文件,它直接对整个构建过程其作用。
webpack还有一些插件的应用,后续补充......