webpack
webpack是一个 现代JavaScript应用程序的静态模块打包器。当webpack处理应用程序时,它会递归地构建一个 依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle.
历史介绍
- 2009年初,commonjs规范还未出来, 此时前端开发人员编写的代码都是非模块化的
- 那个时候开发人员经常需要十分留意文件加载顺序所带来的依赖问题
- 与此同时nodejs开启了js全栈大门, 而requirejs在国外也带动着前端逐步实现模块化
- 同时国内seajs也进行 了大力推广
- AMD规范,具体实现是requirejs define(模块id’ ,[模块依赖1,模块依赖2],function(){ return ;}) , ajax请求文件并加载
- Commonjs |I CMD规范seajs淘宝玉伯
- commonjs和cmd非常相似的,cmd require/module.exports
- commonjs是js在后端语言的规范:模块、文件操作、操作系统底层
- CMD仅仅是模块定义
- UMD通用模块定义,-种既能兼容amd也能兼容commonjs也能兼容浏览器环境运行的万能代码
- npm/bower集中包管理的方式备受青睐,12年browserify/webpack诞生
- npm是可以下载前后端的js代码475000个包
- bower 只能下载前端的js代码,bower在下载bootstrap的时候会自动的下载jquery。
- browserify 解决让require可以运行在浏览器,分析require的关系,组装代码。
- webpack打包工具,占市场主流
(function [root, factory) |{
if (typeof exports == 'object' ) {
module.exports = factory(); //commonjs环境下能拿到返回值
} else if (typeof define === 'function' ) {
define(factory); //define(function(){return 'a'}) AMD方式
} else {
window.eventUtil = factory();
})(this, function() {
//module
return {
//具体模块代码
addEvent: function(el, type, handle) {
//...
},
emoveEvent: function(el, type, handle) {
//...
},
};
});
模块实现
1.下载webpack为项目开发依赖
npm install webpack@3.10.0 -D
// -D == --save-dev 开发环境下下载的模块
2.创建main.js作为项目的入口文件
//整个程序的入口文件
import Vue from ‘ ./vue.js '
import App from ' . /App.js'
//模块整体加载
// import {num, num2,add} from ' ./App.js'
// console. log(num);
// console. log(num2);
// add(3,5);
// import . as object from ' ./App.js'
// console.log(object);
// console. log(object .num);
// console.log(object .num2);
/ add(3,5);
new Vue({
el:'#app',
components:{
App
},
template:'<App/>',
})
3.创建一个App.js
var App = {
template : '<div>这是一个入口组件</div>'
}
//1.声明并导出
export var num = 2; //作为一整个对象key导出
//2.声明再导出
var num2 = 4;
export {num2};
//3.抛出一个函数
export function add(x,y) {
return console.1og(x+y);
}
//4.抛出一个对象
export default App;
4.在package.json文件中配置如下:
{
"name": "29_ module",
"version": "1.0.0",
"description" : "",
"main": "main.js",
"scripts": {
"build": "webpack ./main.js ./build.js"
},
"keywords": [],
"author":"",
"license": "ISC",
"devDependencies": {
"webpack":"^3.6.0"
}
}
5.新建一个index.html, script脚本引入打包完成的build.js如下:
< DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id=" app"></div>
<script type="text/javascript" src="./build.js"></script>
</body>
</html>
webpack编译之后的build.js文件解读
(
/*0导出一个全局变量指window"/
/***/
(function(module, exports) { ...}),
/*01导出了main. is的代码,一个vue示例对象*/
(function(module, __webpack_exports__, __webpack_require__){ ...}),
/* 2既vuei码wgbpack有所配置,所以昆出的 We实际上是yue,/dist/vue. esm. is的宗整编译版木。*/
(function(module, exports, __webpack_require__){...}),
/*3都和node_ modules/setimediate 有关,由于 vue的DOM异步更新机制使用到了它,所以被引入。 */
(function(module, exports, __webpack_require__){ ...}),
/*4*/
(function(module, exports, __webpack_require__) { ...}),
/*5*/
(function(module, exports) { ...}),
/*6和App. js解析有关,把App. vue中es6代码编译成严格版本得15最后将代码抛出最后供列表2中使用挂载到vue中*/
(function(module, __webpack_exports__ , __webpack_require__){ ...
<div>我是App</div>
关于setimmediate介绍链接:
http://www.ruanyifeng.com/blog/2014/10/event-loop.htm
webpack打包模块的源码执行顺序:
- 1:把所有模块的代码放入到函数中,用一个数组保存起来
- 2:根据require时传 入的数组索引,能知道需要哪一段代码
- 3:从数组中,根据索引取出包含我们代码的函数
- 4:执行该函数,传入一个对象module .exports
- 5:我们的代码,按照约定,正好是用module.exports = 'xxxx’进行赋值
- 6:调用函数结束后,module.exports从原来的空对象,就有值了
- 7:最终return module exports;作为require函数的返回值
webpack.config.js文件配置
webpack工具默认加载的是webpack.config.js配置文件
-
entry是一个对象,程序的入口
- okey:随意写
- value:入口文件
entry: { "main": './main.js', }
-
output是一个对象,产出的资源
- key: filename
- value:生成的 build js
output:{ path: __dirname, //如果省略该参数,webpack默认会生成到./dist/目录下 file: './build.js', }
-
module模块(对象)
- loaders:[]
- 存在一些loader‘ { test:正则,loader’style-loader!css-loader’ }
- loaders:[]
配置文件webpack.config.js的修改
修改配置文件名为:webpack.dev.configjs和webpack prod.config.js
在package.json文件中修改
"scripts": {
"dev": "webpack --config ./webpack.dev.config.js",
"prod": "webpack --config ./webpack.prod.config.js"
}
css文件处理
es6模块导入
import ' ./main.css'
编译之后报错
对于webpack来说,Css文件也是一 个模块,但是像这样的文件,webpack得 需要loaders去处理这些文件下载并配置 (以下测试,已将webpack升级到4.0以上)
npm i css-loader style-loader -D
module:{
rules:[
{
//遇到后缀为.Css的文件,webpack先用css - loader加载器去解析这个文件
//最后计算完的css,将会使用style-loader生成一 个内容为最终解析完的css代码的style标签,放到head标签里。
// webpack在打包过程中,遇到后缀为css的文件,就会使用style-loader和css-loader去加载这个文件。
test:/\.css$/,
loader:'style-loader!css-loader'
}
]
}
图片文件的处理
App.js导入图片资源
export default{
template:'<div> <img :src="imgSrc" alt="" /></div>',
data(){
return {
imgSrc:imgSrc
}
}
}
对文件的处理,webpack得需要url-loader和file- loader下载处理图片的loader模块
npm i url-loader file-loader -D
添加loader的配置
module:{
rules: [
{ //需要下载style-loader和css-loader 加载器
test:/\.css$/ ,
loader: 'style-loader!css-loader'
},
{ //需要下载url-loader和file-loader 加载器
test:/\.(jpglpngljpeglgif|svg)$/,
loader: 'url- loader?limit=4000'
},
]
}
webpack最终会将各个模块打包成一个文件,因此我们样式中的ur1路径是相对入口html页面的,而不是相对于原始css文件所在的路径的。这就会导致图片引入失败。这个问题是用file- Hoader解决的,file-loader可以解析项目中的ur1引入(不仅限于css),根据我们的配置,将图片拷贝到相应的路径,再根据我们的配置,修改打包后文件引用路径,使之指向正确的文件。
简易,对于比较小的图片,使用base64编码,可以减少一次图片的网络请求;那么对于比较大的图片,使用base64就不适合了,编码会和htm1混在一起,一方面可读性差,另一方面加大了html页面的大小,反而加大了下载页面的大小,得不偿失了呢,因此设置一个合理的limit是非常有必要的。
less的处理
对less的处理,webpack得需要less-loader和less的loader模块
npm i less-loader less -D
添加loader的配置
module:{
{ //less需要下载 less-loader 和less 加载器
test:/\.less$/,
loader: 'style-loader!css-loader!less-loader'
}
]
}
html-webpack-plugin插件的使用
下载模块
npm i html-webpack-plugin --save-dev
webpack.config.js文件配置
const path = require('path');
//2.导入模块
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//入口
entry:{
//可以有多个入口,也可以有一个,如果一个,就默认从这一个入口开始分析
"main" : './src/main.js'
},
output: {
//指定产出的目录
path: path.resolve('./dist'), //相对转绝对
filename: 'build. js'
},
//声明模块
//包含各个loader
module:{
rules:[
{
test: /\.css$/,
loader: 'style-loader!css-loader'
},
{
test:/\.(jpg|png|jpeg|gif|svg)$/,
loader: 'url-loader?limit=40000'
},
{
test:/\.less$/,
loader: 'style-loader!css-loader!less-loader'
}
],
},
watch:true, //文件监视改动自动产生build.js//添加插件
plugins:[
new HtmlWebpackPlugin({
//插件的执行运行与元素索引有关
templat:'./src/index.html', //参 照物
})
],
}
webpack-dev-server
下载模块
npm install webpack-dev-server --save-dev
常用配置参数
–open自动打开浏览器
–hot热更新,不在舒心的情况下替换cCss样式
–inline自动刷新
–port 9999指定端口
–process显示编译进度
在package.json文件中配置
"scripts": {
"dev": "webpack-dev-server --open --hot --inline --config ./webpack.dev.config.js"
"prod": "webpack --config ./webpack.prod.config.js"
直接运行
npm run dev
es6的解析
模块介绍
- babel-core :
javascript babel -core的作用是把js代码分析成ast (抽象语法树),方便各个插件分析语法进行相应的处理。有些新语法在低版本js中是不存在的,如箭头函数,rest 参数,函数默认值等,这种语言层面的不兼容只能通过将代码转为ast, 分析其语法后再转为低版本js
babel转译器本身,提供了babel的转译API,如babel.transform等, 用于对代码进行转译。像webpack的babel-loader就是调用这些API来完成转译过程的。
- babel- loader :
在将es6的代码transform进行转义,就是通过babel-loader来完成
- babel-preset-env
如果要自行配置转译过程中使用的各类插件,那太痛苦了,所以babel官方帮我们做了-些预设的插件集,称之为preset,这样我们只需要使用对应的preset就可以了。以S标准为例,babel提供 了如下的一些preset:
es2015
es2016
es2017
env
es20xx的preset只转译该年份批准的标准,而env则代指最新的标准,包括了latest和es20xx各年份另外,还有stage-0到stage 4的标准成形之前的各个阶段,这些都是实验版的preset,建议不要使用。
- babel-plugin-transform runt ime
babel编译时只转换语法,几乎所有的编译所有新的JavaScript语法,但不会转化DOM里面不兼容的API比如Promise,Set,Symbol,Array,from,async等等一些API
参考链接: https://www.jianshu.com/p/7bc7b0fadfc2
安装模块
npm install babel-core babel-loader babel-preset-env babel-plugin-transform-runtime -D
在webpack-dev-config.js配置
loader:[
//处理es6,7,8
test:/\.js$/,
loader: 'babel-loader',
options:{
presets:['env'],//处理关键字
plugins:['transform-runtime'],//处理函数
}
]
配置完成之后执行npm run dev发现!!!
解决:
排除不包含node_ modules的路径,然后再配置文件中修改
loader: [
{
//处理es6,7,8
test:/\.js$/,
loader: ' babel- loader' ,
exclude:/node_ modules/ ,
options:{
presets:['env'],//处理关键字
plugins:['transform- runtime'],//处理函数
}
}
]
也会发现,当排除掉node_ modules文件中的es6代码编译后,编译的时间也快了以前出错的,3601毫秒的时候就开始出错了。。。.
排除掉node_ modules之后