demo地址:https://github.com/yonglijia/...javascript
首先来介绍下webpack是干吗的。 css
webpack简单的来说,是一个前端模块化管理和打包工具,能够将你的文件所依赖的js,css,node包等所有打包成一个bundle文件,而且可以处理各类模块之间依赖问题。在webpack的世界里,一切皆模块!但它又不只仅是一个打包工具。它不只可以轻松处理你项目中的依赖关系和加载顺序,还能让这个流程更加智能化,自动化。html
webpack的使用,最复杂的一部分是莫过于它的配置项。webpack经过你的配置项,放置全部与打包相关的信息。一个基本的配置包括前端
module.exports = { entry: '', output: {}, module: { rules: [] }, plugins: [], };
咱们能够这样理解这几个配置:java
你若是要打包一个文件,那首先要指定文件的地址,也就是entry;打包以后放在那里呢,也就是output;打包过程当中文件要通过怎么样的处理,也就是rules中的loader;如何可以使webpack打包更快,体积更小呢,也就是plugins。这些配置相辅相成,紧密结合node
这些配置命名须要写入webpack.config.js中。在项目中,执行webpack
,就会自动引用这个文件。react
下面咱们详细介绍下这些配置。创建一个简单的项目,包含webpack
testWebpck.jsgit
module.exports = function() { var testDiv = document.createElement('div'); testDiv.textContent = "hello world"; return testDiv; };
index.jsgithub
var testWebpack = require('./testWebpack.js'); document.querySelector("#root").appendChild(testWebpack());
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>learn webpack</title> </head> <body> <div id="root"> </div> <script src="build/bundle.js"></script> </body> </html>
webpack.config.js
module.exports = { entry: __dirname+"/app/index.js",//打包的js output: { path: __dirname + "/build",//打包后的文件存放的地方 filename: "bundle.js",//打包后bundle文件的文件名 }, module: { rules: [] }, plugins: [], };
咱们在项目根目录中,执行webpack
,
浏览器打开index.html,能够看到hello world!
。修改testWebpck, 修改成“hello webpack!”,从新执行webpack,再次打开index.html,能够看到浏览器中变为hello webpack!
咱们可使用webpack-dev-server,来构建一个本地服务器,经过这个服务器,监听你的代码,实时更新你修改的内容。
首先
npm install webpack-dev-server
而后在package.json中添加脚本
"scripts": { "start": "webpack-dev-server --config webpack.config.js", },
npm的
start
命令是一个特殊的脚本,直接使用npm start
就能够执行其对于的命令;而若是不是start
,想要在命令行中运行时,须要这样用npm run {script name}
如npm run build
执行npm start
,在浏览器中输入http://127.0.0.1:8080
,能够看到咱们所看到的如出一辙的页面。
Webpac-dev-server须要添加devServer配置
devServer{ hot:true,// inline:true,// port:8080,//默认8080 proxy:{//接口代理 '/xxx/**': {//接口匹配的地址 target:"代理地址", secure: false }, } }
目前为止,咱们已经使用wepack成功完成了一个文件的打包,而且能在开发环境中使用。可是未使用任何的loader,plugin,由于这里面涉及到的文件还太少,种类也很少。下面来一步步丰富这个小项目,引入所须要的配置。
咱们在项目中引入css
index.css
#root{ border:1px solid red; }
在index.js中引入require('./index.css');
执行npm start
,
这时已经报错,提示咱们要引入相应的loader来处理css。是时候展现真正的技术了——— loader。
loader是什么呢?正如咱们上面所讲的是,它用来如何处理咱们的打包文件的;如今若是不引入loader,那就没法处理css文件。loader不只仅是处理css,还能够用来css的预处理、js的中使用ES6等高级语法处理成浏览器能兼容的格式。文件、图片、json等处理,都须要用到loader;通过loader的处理,这些文件可以很好的打入打包后的bundle中。
一个loader所须要的配置包括四个方面
test、loader、includer/exclude、query
首先来看个示范
{ test: /\.js$|\.jsx$/, loader: 'babel-loader', exclude: /(node_modules|bower_components)/, query: { presets: ['es2015', 'react'], plugins: ['transform-class-properties', 'lodash'] }, },
test是一个正则表达式,它用来匹配适用于loader文件的扩展名
loader中是loader的名称,1.x版本不须要加上“-loader”,日后的版本须要加上“-loader”.
这两个都是必须添加的配置,下面两个是可选的。
include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不须要处理的文件(文件夹)
query:为loaders提供额外的设置
那咱们来根据上面的配置来设置loader,来处理css。
webpack提供两个工具处理样式表,css-loader 和 style-loader;安装这两个npm包,修改咱们的配置
module.exports = { entry: __dirname+"/app/index.js",//打包的js output: { path: __dirname + "/build",//打包后的文件存放的地方 filename: "bundle.js",//打包后bundle文件的文件名 }, module: { rules: [ {test: /\.css$/, loaders: ["style-loader", "css-loader"]},]//引入多个loader,loader要写成loaders,属性为一个数组,存放各个loader }, plugins: [], };
执行npm start
,在浏览器中咱们发现,helllo world中已经添加上了红色的边框了。
css-loader使你可以使用相似@import和url(...)的方法实现require的功能,style-loader将全部的计算后的样式加入页面中,两者组合在一块儿使你可以把样式表嵌入webpack打包后的js文件中
有一点要注意的是:loader是有顺序的。webpack确定是先将全部css模块依赖解析完获得计算结果再建立style标签。所以应该把style-loader放在css-loader的前面(webpack loader的执行顺序是从右到左),顺序不对,会报错。
这样咱们基本上使用了完成了一个loader的基本配置。
咱们来配置下添加其余loader的配置项:
处理图片
须要同时安装url-loader和file-loader
{test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'},
url-loader与file-loader的工做方式类似,若是文件的体积比byte limit小,就能返回Data Url。若是图片比limit小,将直接以base64的形式内联在代码中。若是图片比limit(以bytes为单位)大,那么webpack就会使用file-loader去处理文件,而且全部的查询参数都会传递给file-loader。
咱们想把js和图片打包成不一样的文件夹,须要把output配置项修改一下
output: { path: __dirname + "/build",//打包后的文件存放的地方 filename: "js/bundle.js",//打包后bundle文件的文件名 },
在项目app文件夹中分别添加两个图片,一个大于1024,一个小于1024,circle_loaction.png,data_update.gif
添加上面的配置,执行weibpack,发现一个有一个文件在build/images中生成。
这里面有一个路径的点须要注意:
若是在output中添加publicPath,好比说/xxx/
module.exports = { entry: __dirname+"/app/index.js",//打包的js output: { publicPath: '/xxx/', path: __dirname + "/build",//打包后的文件存放的地方 filename: "bundle.js",//打包后bundle文件的文件名 }, module: { rules: [ {test: /\.css$/, loaders: ["style-loader", "css-loader"]}, {test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'}, ] }, plugins: [], };
那咱们访问http://127.0.0.1:8080
,发现bundle找不到。这是由于加上publicPath以后,访问内存中的文件bundle都须要加上/xxx/
(但实际上引用的是内存中的文件,既不是/build/js/也不是/xxx/)。因此要修改html中的引用地址方能使用。
<script src="xxx/js/bundle.js"></script>
publicPath表示资源的发布地址,加上该属性后,打包文件中全部经过相对路径引用的资源都会被配置的路径所替换。
若是此时修改index.css
#root{ border:1px solid red; height: 350px; background-image:url("./data_update.gif"); }
./data_update.gif 就会自动替换成xxx/images/data_update-37a1914078.gif。
path和publicPath的区别
path:/build/js
publicPaht:/online/
线下环境
path是打包后文件存放的路径,不能用于html中的js引用
publicPath表示的是资源发布的路径。自动指向path编译目录(/online/ => /build/js/),html中引用js文件时,必须引用此虚拟路径。
线上环境
webpack进行编译(固然是编译到/build/js/),咱们须要把目录(/build/js/)下的文件,所有复制到/online/目录下(注意:不是去修改index.html中引用bundle.js的路径)
处理jsx文件
webpack不能直接处理jsx,须要借助于babel.
babel堪称神器,被誉为下一代 JavaScript 语法的编译器。用它,你能够不用等浏览器的支持,就可使用最新的标准的语法。使用它能够解析jsx的语法。对于babel,不作过多介绍。
首先安装
npm install --save-dev babel-cli babel-preset-env babel-core babel-loader babel-preset-es2015 babel-preset-react react react-dom
建立 .babelrc
{ "presets": ["react","es2015"] }
添加loader
{ test: /\.js$|\.jsx$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', }
修改index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>learn webpack</title> </head> <body> <div id="root"> </div> <div id="react"> </div> <script src="build/js/index.js"></script> <script src="build/js/testReact.js"></script> </body> </html>
添加testWebpack.jsx,
import React from 'react'; import ReactDOM from 'react-dom'; class TestReact extends React.Component{ constructor(props){ super(props); } render(){ return <div>this is a react div <img src={require('./data_update.gif')}/> </div> } } ReactDOM.render(<TestReact/>,document.getElementById('react'))
修改配置
module.exports = { entry: { index :__dirname+"/app/index.js", testReact:__dirname+"/app/testReact.jsx", }, output: { path: __dirname + "/build",//打包后的文件存放的地方 filename: "js/[name].js"//打包后输出文件的文件名 }, module: { rules: [ {test: /\.css$/, loaders: ["style-loader", "css-loader"]}, {test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'}, { test: /\.js$|\.jsx$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', } ] }, plugins: [], };
这里咱们设置了两个入口文件,而且打包成不一样的js,这个js的名字和他们自己的js的名字相同,经过filename: "js/[name].js"
指定。
这样设置完咱们就完成了使用babel-loader处理jsx文件。
稍微展开一点entry:
entry 有三种类型字符串,数组和对象
entry:"xxx/index.js",
entry:["xxx/index.js","xxx/index2.js"],
entry:{
index:"xxx/index.js",
index2:"xxx/index2.js"
},
下面咱们介绍下,如何添加插件,使咱们的打包工程更快,更智能。
先介绍下一些经常使用的插件。
uglifyjs-webpack-plugin :JS压缩
var webpack = require('webpack'); var UglifyJSPlugin = require('uglifyjs-webpack-plugin') module.exports = { entry: { index :__dirname+"/app/index.js", testReact:__dirname+"/app/testReact.jsx", }, output: { path: __dirname + "/build",//打包后的文件存放的地方 filename: "js/[name].js"//打包后输出文件的文件名 }, module: { rules: [ {test: /\.css$/, loaders: ["style-loader", "css-loader"]}, {test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'}, { test: /\.js$|\.jsx$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', } ] }, plugins: [ new UglifyJSPlugin(), ], };
咱们这时候打开build/js中的js文件,发现里面都被压缩混淆了。
DefinePlugin:定义全局变量
Hot Module Replacement:
在webpack中实现HMR很简单,只须要两个配置
添加new webpack.HotModuleReplacementPlugin()
修改脚本 "start": "webpack-dev-server --config webpack.config.js"
,
插件分为内置和外置的,不过用法都是大同小异的。不一样的插件,配置参数也不同。
devtool:这个是用来配置soucemap的类型,在开发的时候调试特别有用。里面的配置特别多,后面会单独介绍这个地方。
resolve:配置短路径引用
resolve: { alias: { module: path.resolve(APP_PATH, 'module'), component: path.resolve(APP_PATH, "component"), service: path.resolve(APP_PATH, "service"), page: path.resolve(APP_PATH, "page"), node_modules: path.resolve(ROOT_PATH, 'node_modules') }, extensions: ['.js', '.jsx', '.json', '.scss'] },
使用这个选项的话,你能够直接使用好比require('page/index')
,其实就是path.resolve(APP_PATH, "page")+'/index'
,extensions是用来匹配所要引用的文件类型,匹配以index开头的 ['.js', '.jsx', '.json', '.scss']
文件,若是没有,就会报错。
这篇文章权当个入门文档,里面还有不少须要一一深刻挖掘的,好比devtool到底选择哪一个最好,怎么使项目的打包更快,怎么使用dll等等,后续会一点一点的写。