我相信,有很多的朋友对webpack都有或多或少的了解。网上也有了各类各样的文章,文章内做者也写出了很多本身对于webpack这个工具的理解。在我刚刚接触webpack的时候,老实说,网上大部分的文章我是看不懂的。。webpack里面有不少名词,是没有接触和理解过模块化的同窗都难以理解的。我感受,学习任何一项新技术,要弄清楚为何使用它,它是什么,它有什么用等概念,弄清楚这些概念以后,我相信,在往后的webpack学习中会达到事半功倍的效果。这篇文章,我会以最简单的方式,阐述什么是webpack。固然,这是我我的对webpack的一些理解,也是在学习中总结。javascript
另外,最好的学习webpack的资源是webpack的官网。传送门:webpackcss
固然,若是你早已经是webpack的实践者,对webpack认识足够深刻,这篇文章不太适合您阅读。若是你是小白,那就能够开启webpack的探索之路了。html
webpack是目前流行的一款模块化打包工具。前端
webpack定义:一款前端资源模块化和打包工具。vue
webpack做用:java
1. 将许多松散的模块按照依赖关系和规则打包成符合生产环境环境部署的前端资源。 2. 将按需加载的模块进行代码分割,等到实际须要的时候再异步加载。 3. 经过加载器loader的转换,全部的前端资源均可以看做是模块。好比说CommonJS模块,AMD模块,ES6模块,css,sass,json,图片等。
短短的几句话,就有太多让人难以明白的地方。python
1. 什么是前端资源?jquery
2. 什么是模块?webpack
3. 什么是模块化?css3
4. 什么叫按需加载?
5. 如何实现按需加载?
6. 什么是plugins?
7. 什么是loader?
所谓前端资源,就是咱们在建立html时,引入的script,link,img,json等文件。webpack足够的优秀,只须要在html文件中引入一个js文件,在定义一个入口文件js,用于存放依赖的模块,就能够将其余前端资源按照依赖关系和规则打包。
之前咱们须要这样来引入文件。
<link rel="stylesheet" href="style/stylesheets/screen.css" media='screen'/ > <script src='script/jquery-2.2.1.min.js'></script> <script src='script/bootstrap.js'></script> <script src="script/index.js" ></script>
index.js依赖bootstrap.js,而bootstrap又依赖于jquery。咱们必须按照DOM顺序来写每个js文件。
如今只须要在html中引入一个主文件index.js,其余依赖的前端资源都写在另一个入口文件js中,这个入口文件不用写在html中,而后配置好config,在cmd中输入webpack执行编译,全部前端资源都被引入了。而且webpack会帮咱们入口文件entry.js的每一个模块的类型和依赖关系,等到须要的时候再按需加载。
//html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script src='js/main.js'></script> <!-- 引入引入主模块 main.js --> </body> </html> //entry.js import $ from 'jquery'; import other...
在webpack中,全部的前端资源都是模块,能够经过加载器loader进行转换。在javascript方面,有几大模块系统,CommonJS模块,AMD模块,CMD模块,ES6模块。谈谈我对这几大模块的理解。
在CommonJS中,有一个全局方法require(),用于加载依赖模块。
//main.js var jquery = require('jquery'); var bootstrap = require('bootstrap');
主文件main.js模块依赖于这两个模块,CommonJS缺点就是同步加载。也就是说,会先加载jquery模块,等到jquery加载完了再去加载bootstrap模块。引用阮一峰老师的话
同步加载意味着阻塞加载,当依赖的模块太大时,浏览器会处于假死的状态。
假死意味着浏览器任然处在加载中,仍然仍是空白页面。这种假死的状态带来的后果就是用户的离开。
AMD也叫异步模块定义,英文Asynchronous Module Definition。AMD是requirejs对模块定义时的产出。它采用异步方式加载模块,每一个独立模块的加载不影响回调函数中定义的模块的运行。在回调函数中定义一个模块,只有当依赖的模块加载完成以后,该模块才会编译执行。AMD也采用require()语句来加载一个模块,可是不一样于CommonJS,它有两个参数。第一个参数是数组,须要传入依赖模块;第二个参数是回调函数,回调函数中也接受参数,而参数是形式参数,来自于每个依赖模块。举个例子。
//main.js require(['jquery','bootstrap'],function($, boot){ //写入的模块 })
主模块main.js依赖于jquery,Bootstrap模块,main只有在这两个模块加载完成以后才会编译执行main定义的模块,属于同步加载。而在两个依赖模块中,属于异步加载。也就是说bootstrap不用等到jquery加载完成以后再加载,被依赖的模块是哪个模块小,就先加载哪个,这就避免了CommonJS模块中同步加载依赖模块而出现浏览器假死的状态。稍微总结一下,
主模块须要等到依赖模块加载完成以后才编译执行,属于同步加载;而被依赖模块之间属于异步加载,哪个模块小,就先加载哪个。
AMD模块的一大不足就是全部依赖的模块都须要提早加载,依赖前置。
CMD模块跟AMD很类似,这里引用玉伯老师的话看看CMD和AMD的区别。
对于依赖的模块,AMD是提早执行,CMD是延迟执行。
CMD推从依赖就近,AMD推从依赖前置
依赖就近的意思就是当我须要某个模块的时候再去异步加载。也就是按须要加载前端资源,懒加载。
能够用八个字来总结CMD。依赖就近,延迟执行。
ES6模块的设计思想,是尽可能的静态化,使得编译时就能肯定模块的依赖关系,以及输入和输出的变量。ES6中与CommonJS,AMD模块一个区别在于ES6是经过import关键字来输入某个模块提供的功能,export或者export default规定该模块的对外接口,通俗易懂一些,也就是暴露该模块定义的一些属性和方法,供其余模块调用。
ES6和CommonJS,AMD模块最大的区别在于,ES6模块能够实现编译时加载,简单的说就是按需加载。然后两种方法只能是运行时加载。上一段代码。
ES6:
import {get, post, ajax} from 'jQuery'; CommonJS: var
webpack是支持以上的模块系统的。在头脑中要造成某种技术的知识框架才能学好该技术,因此花费了一些时间作了些介绍。模块化就是webpack使用某种方法将每个松散的模块按照依赖关系编译的过程。webpack须要一个入口js文件,主模块js文件,config文件就能够实现前端资源模块化。看个简单的例子。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script src='js/main.js'></script> 1. <!-- 引入主模块 main.js --> </body> </html> 2. //入口文件 entry.js document.write("<h1>I'm Uncke Keith!</h1>"); 3. //webpack.config.js module.exports = { entry :'./app/js/entry.js', output : { path: './dist/js' filename: 'main.js' } }; 4. //打开cmd,在文件目录下,输入webpack执行编译就能够看到document.write()的结果了。
webpack的其中一个做用就是能够将按需加载的模块进行代码分割,根据实际须要进行异步加载。按需加载,顾名思义就是按照用户须要某个功能的时候在加载相应的模块。举个例子,当咱们在浏览一些图片网站的时候,若是图片在你打开该网站的时候就所有一块儿加载好,那形成的后果就是页面会保持一段时间的空白状态,直到所有图片加载完成以后才会显示。若是是按须要加载,就能够在用户刚进入页面的时候加载可视区域窗口的图片,当用户拖动滚动条下拉的时候再去加载图片,这样不只减小HTTP请求,同时提升了页面加载速度。在举一个例子。在单页应用中,为了减小http请求次数,会把全部js文件合并为一个文件,这样请求数量减小了,但是请求的文件体积却变大了。按需加载就能够解决这个问题。
ES6的一大涉及思想就是想让前端资源静态化,在编译的过程当中,而非运行过程当中就肯定模块的依赖关系。webpack在编译的过程当中,就会对整个代码进行静态分析,分析出各个模块的类型和它们依赖关系,而后将不一样类型的模块提交给适配的加载器来处理。好比一个用 Sass 写的样式模块,能够先用 Sass-Loader加载器将它转成一个CSS 模块,在经过 CSS 模块把他插入到页面的 style 标签中执行。而且在你编译的时候就肯定了依赖关系。
webpack跟咱们提供了不少内置的插件,能够实现loader作不到的事情。在这里介绍几个经常使用的插件。
咱们在入口文件中import(或者require)进一些css文件时,webpack会帮咱们把css样式与其余前端资源打包到output的filename文件中,而后在head标签中会自动加载一个style标签。可是,咱们可能会须要独立出一个css文件,这时候就须要使用extract-text-webpack-plugin插件了。具体用法以下:
var ExtractTextPlugin = require("extract-text-webpack-plugin"); //这里须要使用CommonJS语法来引入一个依赖。 module.exports = { module: { loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") } //loader的执行顺序是 先执行css-loader给css文件加上地址,而后执行style-loader在头部加上style标签。 ] }, plugins: [ new ExtractTextPlugin("styles.css") //使用plugins选项对象,使用new调用ExtractTextPlugin构造函数,传入的参数是须要单独生成的css文件,路径与output中的path路径相同。详细的参数能够到extract-text-webpack-plugin官网查看。 ] }
当咱们成功生成了单独的css文件以后,就能够经过link标签引入了。
Webpack 自己只能处理原生的 JavaScript 模块,可是 loader 转换器能够将各类类型的资源转换成 JavaScript 模块。这样,任何资源均可以成为 Webpack 能够处理的模块。每个loader都会针对入口文件entry.js的依赖模块引入的前端资源进行转换。站在更高的角度上看问题,咱们在webpack.config.js里面的全部配置都是针对入口文件的,始终记住这点很重要。由于这就是咱们配置webpack.config.js的目的。在这里介绍一些经常使用loader。
我是一名sass实践者,而且用着一个封装了不少mixins的compass库,这个库的最大好处就是能够直接include一些compass封装好的的css3的mixin时,编译以后会帮咱们加上css前缀。若是想在.vue中也实现这种自动前缀的功能,可使用webpack给咱们提供的postcss-loader。(能够去官网查看相关介绍)。postcss?这又是什么鬼,其实postcss只是一个平台,咱们须要用的是基于postcss平台上的一些经常使用的插件。
若是想使用这个插件,须要下载一些依赖。
cnpm install autoprefixer --save-dev //autoprefixer用于添加css3前缀
具体的webpack.config.js配置以下
//注意先引入依赖 var ExtractTextPlugin = require('extract-text-webpack-plugin'); var autoprefixer = require('autoprefixer'); module.exports = { entry: __dirname + '/app/entry.js', output: { path: __dirname + '/dist', filename: 'bundle.js' }, module: { config... }, postcss:[ autoprefixer() ] };
若是你的入口文件entry.js是这样的。
...
import './assets/main.scss';
那么固然你在main.scss使用scss语法写一些css3属性时,在编译以后就能够看到css3前缀了。可是若是你的样式是写在*.vue组件里面的
好比说,入口文件entry.js是这样的。
...
import app from './app.vue';
topBar.vue
<template> config... </template> <script> config... </script> <style lang='sass' scoped> .main{ font-weight: bold; p { border-radius: 10px; box-shadow: 3px 3px 3px #ccc; transition: all 0.3s; 此处测试css3的属性前缀 } } </style>
在浏览器中查看效果,你会发现,.vue组件中定义的style样式并无加上属性前缀。
.main p[data-v-a64cfc10] { background-color: red; border-radius: 10px; box-shadow: 3px 3px 3px #ccc; color: red; display: inline-block; font-weight: bold; height: 100px; transition: all 0.3s ease 0s; }
难道是postcss-loader失效了?其实并非。出现这种状况的缘由主要仍是对vue-loader不熟悉致使的。由于你是把样式写在了单个*.vue组件中,因此这里会涉及另一个lodaer,也就是Vue官方提供的vue-loader。在vue-loader中若是也想让样式拥有前缀,在webpack.config.js要进行以下配置。
module.exports = {
entry: ... , output: { ... }, module: { ... }, 这里配置vue指的是vue-loader,咱们须要在vue-loader中再一次配置postcss。 vue: { postcss: [require('autoprefixer')()], autoprefixer: true }, postcss:[ autoprefixer() ] //也就是说,postcss须要配置两处。一是解析entry.js中引入的css模块;一处是解析 单个*.vue组件的<style>标签中的样式。 }
执行编译,你会发现正常显示了。