参考:http://www.javashuo.com/article/p-gqgzutje-er.htmlcss
1.什么是webpack,为何要使用它html
一些优秀的网站每每有许多JavaScript文件,不少依赖项,为了简化开发的复杂度,前端有不少实践方法:前端
这些方法每每有不少文件浏览器不能直接识别,须要二次处理后才能够,此时webpack应允而生node
WebPack能够看作是模块打包机:react
它作的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用webpack
Webpack的工做方式是:es6
把你的项目当作一个总体,经过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的全部依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件web
2.开始使用webpack正则表达式
2.1 开始安装webpacknpm
Webpack可使用npm安装,新建一个空的练习文件夹(此处命名为webpack sample project),在终端中转到该文件夹后执行下述指令就能够完成安装
//全局安装 npm install -g webpack //安装到你的项目目录 npm install --save-dev webpack
2.2 开始前准备
2.2.1 在这个路径的cmd中输入npm init,自动生成package.json文件写入项目的信息,若是不作正式使用能够回车默认便可
2.2.2 在本项目中安装Webpack做为依赖包
// 安装Webpack npm install --save-dev webpack
2.2.3 回到以前的空文件夹,并在里面建立两个文件夹,app文件夹和public文件夹,app文件夹用来存放原始数据和咱们将写的JavaScript模块,public文件夹用来存放以后供浏览器读取的文件(包括使用webpack打包生成的js文件以及一个index.html
文件)。接下来咱们再建立三个文件:
index.html
--放在public文件夹中;Greeter.js
-- 放在app文件夹中;main.js
-- 放在app文件夹中;
在index.html文件中写入最基础的html代码,它在这里目的在于引入打包后的js文件(这里咱们先把以后打包后的js文件命名为bundle.js
,以后咱们还会详细讲述)
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Webpack Sample Project</title> </head> <body> <div id='root'> </div> <script src="bundle.js"></script> </body> </html>
咱们在Greeter.js
中定义一个返回包含问候信息的html
元素的函数,并依据CommonJS规范导出这个函数为一个模块:
// Greeter.js module.exports = function() { var greet = document.createElement('div'); greet.textContent = "Hi there and greetings!"; return greet; };
main.js
文件中咱们写入下述代码,用以把Greeter模块
返回的节点插入页面。
//main.js const greeter = require('./Greeter.js'); document.querySelector("#root").appendChild(greeter());
2.2.4 正式使用webpack
webpack能够在终端中使用,在基本的使用方法以下:
# {extry file}出填写入口文件的路径,本文中就是上述main.js的路径, # {destination for bundled file}处填写打包文件的存放路径 # 填写路径的时候不用添加{} webpack {entry file} {destination for bundled file}
指定入口文件后,webpack将自动识别项目所依赖的其它文件,不过须要注意的是若是你的webpack不是全局安装的,那么当你在终端中使用此命令时,须要额外指定其在node_modules中的地址,继续上面的例子,在终端中输入以下命令
# webpack非全局安装的状况 node_modules/.bin/webpack app/main.js public/bundle.js
运行完成后就会在public文件夹中自动生成bundle.js,被index.html引用成功!至此一个完整的小webpack项目结束
有没有以为在cmd中输入的webpack命名比较繁琐,好的,这里有较为简单的命令方法,但须要修改下配置文件package.json
{ "name": "webpack-sample-project", "version": "1.0.0", "description": "Sample webpack project", "scripts": { "start": "webpack" // 修改的是这里,JSON文件不支持注释,引用时请清除 }, "author": "zhang", "license": "ISC", "devDependencies": { "webpack": "3.10.0" } }
以后想要启动启动webpack只需在对应的项目目录下只需npm start效果就能完整的命令效果同样
3.webpack 强大功能
3.1 可调试
通常经过打包后的文件,不容易找到出错的地方,对应你写的代码的位置,配置了Source maps就能帮咱们解决这个问题,经过简单的配置,webpack能够帮咱们生成Source Maps,这为咱们提供了一种对应的编译文件与源文件方法,使得编译后的代码可读性更高:配置devtool便可
devtool选项 | 配置结果 |
---|---|
source-map |
在一个单独的文件中产生一个完整且功能彻底的文件。这个文件具备最好的source map ,可是它会减慢打包速度; |
cheap-module-source-map |
在一个单独的文件中生成一个不带列映射的map ,不带列映射提升了打包速度,可是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试形成不便; |
eval-source-map |
使用eval 打包源文件模块,在同一个文件中生成干净的完整的source map 。这个选项能够在不影响构建速度的前提下生成完整的sourcemap ,可是对打包后输出的JS文件的执行具备性能和安全的隐患。在开发阶段这是一个很是好的选项,在生产阶段则必定不要启用这个选项; |
cheap-module-eval-source-map |
这是在打包文件时最快的生成source map 的方法,生成的Source Map 会和打包后的JavaScript 文件同行显示,没有列映射,和eval-source-map 选项具备类似的缺点; |
对小到中型的项目中,eval-source-map
是一个很好的选项,再次强调你只应该开发阶段使用它,咱们继续对上文新建的webpack.config.js
,进行以下配置:
module.exports = { devtool: 'eval-source-map', entry: __dirname + "/app/main.js", output: { path: __dirname + "/public", filename: "bundle.js" } }
方法构建速度更快,可是不利于调试,推荐在大型项目考虑时间成本时使用。
cheap-module-eval-source-map
3.2 配置本地服务器
这个本地服务器是基于node.js,须要将webpack-dev-server在项目根目录下安装
npm install --save-dev webpack-dev-server
devserver做为webpack配置选项中的一项,如下是它的一些配置选项,更多配置可参考这里
devserver的配置选项 | 功能描述 |
---|---|
contentBase | 默认webpack-dev-server会为根文件夹提供本地服务器,若是想为另一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public"目录) |
port | 设置默认监听端口,若是省略,默认为”8080“ |
inline | 设置为true ,当源文件改变时会自动刷新页面 |
historyApiFallback | 在开发单页应用时很是有用,它依赖于HTML5 history API,若是设置为true ,全部的跳转将指向index.html |
把这些命令加到webpack的配置文件中,如今的配置文件webpack.config.js
以下所示
module.exports = { devtool: 'eval-source-map', entry: __dirname + "/app/main.js", output: { path: __dirname + "/public", filename: "bundle.js" }, devServer: { contentBase: "./public",//本地服务器所加载的页面所在的目录 historyApiFallback: true,//不跳转 inline: true//实时刷新 } }
在package.json
中的scripts
对象中添加以下命令,用以开启本地服务器:
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack", "server": "webpack-dev-server --open" },
在终端中输入npm run server
便可在本地的8080
端口查看结果
3.3 Loaders
Loaders的功能就强大了,他能够将不是js的文件类型转为js让浏览器能够识别
好比说分析转换scss为css,或者把下一代的JS文件(ES6,ES7)转换为现代浏览器兼容的JS文件,对React的开发而言,合适的Loaders能够把React的中用到的JSX文件转换为JS文件
Loaders须要单独安装而且须要在webpack.config.js
中的modules
关键字下进行配置,Loaders的配置包括如下几方面:
test
:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)loader
:loader的名称(必须)include/exclude
:手动添加必须处理的文件(文件夹)或屏蔽不须要处理的文件(文件夹)(可选);query
:为loaders提供额外的设置选项(可选) 不过在配置loader以前,咱们把Greeter.js
里的问候消息放在一个单独的JSON文件里,并经过合适的配置使Greeter.js
能够读取该JSON文件的值,各文件修改后的代码以下:
在app文件夹中建立带有问候信息的JSON文件(命名为config.json
)
{ "greetText": "Hi there and greetings from JSON!" }
更新后的Greeter.js
var config = require('./config.json'); module.exports = function() { var greet = document.createElement('div'); greet.textContent = config.greetText; return greet; };
在看如何具体使用loader以前咱们先看看Babel是什么?
Babel实际上是一个编译JavaScript的平台,它能够编译代码帮你达到如下目的:
Babel实际上是几个模块化的包,其核心功能位于称为babel-core
的npm包中,webpack能够把其不一样的包整合在一块儿使用,对于每个你须要的功能或拓展,你都须要安装单独的包(用得最多的是解析Es6的babel-env-preset
包和解析JSX的babel-preset-react
包)。
// npm一次性安装多个依赖模块,模块之间用空格隔开 npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react
在webpack
中配置Babel的方法以下:
module.exports = { entry: __dirname + "/app/main.js",//已屡次说起的惟一入口文件 output: { path: __dirname + "/public",//打包后的文件存放的地方 filename: "bundle.js"//打包后输出文件的文件名 }, devtool: 'eval-source-map', devServer: { contentBase: "./public",//本地服务器所加载的页面所在的目录 historyApiFallback: true,//不跳转 inline: true//实时刷新 }, module: { rules: [ { test: /(\.jsx|\.js)$/, use: { loader: "babel-loader", options: { presets: [ "env", "react" ] } }, exclude: /node_modules/ } ] } };
如今你的webpack的配置已经容许你使用ES6以及JSX的语法了。继续用上面的例子进行测试,不过此次咱们会使用React,记得先安装 React 和 React-DOM
npm install --save react react-dom
接下来咱们使用ES6的语法,更新Greeter.js
并返回一个React组件
//Greeter,js import React, {Component} from 'react' import config from './config.json'; class Greeter extends Component{ render() { return ( <div> {config.greetText} </div> ); } } export default Greeter
修改main.js
以下,使用ES6的模块定义和渲染Greeter模块
// main.js import React from 'react'; import {render} from 'react-dom'; import Greeter from './Greeter'; render(<Greeter />, document.getElementById('root'));
从新使用npm start
打包,若是以前打开的本地服务器没有关闭,你应该能够在localhost:8080
下看到与以前同样的内容,这说明react
和es6
被正常打包了。
Babel其实能够彻底在 webpack.config.js
中进行配置,可是考虑到babel具备很是多的配置选项,在单一的webpack.config.js
文件中进行配置每每使得这个文件显得太复杂,所以一些开发者支持把babel的配置选项放在一个单独的名为 ".babelrc" 的配置文件中。咱们如今的babel的配置并不算复杂,不过以后咱们会再加一些东西,所以如今咱们就提取出相关部分,分两个配置文件进行配置(webpack会自动调用.babelrc
里的babel配置选项),以下:
module.exports = { entry: __dirname + "/app/main.js",//已屡次说起的惟一入口文件 output: { path: __dirname + "/public",//打包后的文件存放的地方 filename: "bundle.js"//打包后输出文件的文件名 }, devtool: 'eval-source-map', devServer: { contentBase: "./public",//本地服务器所加载的页面所在的目录 historyApiFallback: true,//不跳转 inline: true//实时刷新 }, module: { rules: [ { test: /(\.jsx|\.js)$/, use: { loader: "babel-loader" }, exclude: /node_modules/ } ] } };
//.babelrc { "presets": ["react", "env"] }
到目前为止,咱们已经知道了,对于模块,Webpack能提供很是强大的处理功能,那那些是模块呢。
Webpack有一个不可不说的优势,它把全部的文件都都当作模块处理,JavaScript代码,CSS和fonts以及图片等等经过合适的loader均可以被处理。
webpack提供两个工具处理样式表,css-loader
和 style-loader
,两者处理的任务不一样,css-loader
使你可以使用相似@import
和 url(...)
的方法实现 require()
的功能,style-loader
将全部的计算后的样式加入页面中,两者组合在一块儿使你可以把样式表嵌入webpack打包后的JS文件中。
//安装 npm install --save-dev style-loader css-loader
//使用 module.exports = { ... module: { rules: [ { test: /(\.jsx|\.js)$/, use: { loader: "babel-loader" }, exclude: /node_modules/ }, { test: /\.css$/, use: [ { loader: "style-loader" }, { loader: "css-loader" } ] } ] } };
接下来,在app文件夹里建立一个名字为"main.css"的文件,对一些元素设置样式
/* main.css */ html { box-sizing: border-box; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } *, *:before, *:after { box-sizing: inherit; } body { margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } h1, h2, h3, h4, h5, h6, p, ul { margin: 0; padding: 0; }
咱们这里例子中用到的webpack
只有单一的入口,其它的模块须要经过 import
, require
, url
等与入口文件创建其关联,为了让webpack能找到”main.css“文件,咱们把它导入”main.js “中,以下
//main.js import React from 'react'; import {render} from 'react-dom'; import Greeter from './Greeter'; import './main.css';//使用require导入css文件 render(<Greeter />, document.getElementById('root'));
上面的代码说明webpack是怎么把css当作模块看待的,我们继续看一个更加真实的css模块实践。