webpack配置
⼀、全⾯理解webpack
1、什么是 webpack?
webpack是近期最⽕的⼀款模块加载器兼打包⼯具,它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、图⽚等都作为模块来使⽤和处理,它能有Grunt或Gulp所有基本功能。webpack的官⽹是,⽂档地址是,官⽹对webpack的定义是MODULE BUNDLER,他的⽬的就是把有依赖关系的各种⽂件打包成⼀系列的静态资源。请看下图:
2、webpack 的优势
其优势主要可以归类为如下⼏个:
1. webpack 是以 commonJS 的形式来书写脚本滴,但对 AMD/CMD 的⽀持也很全⾯,⽅便旧项⽬进⾏代码迁移。
2. ⽀持很多模块加载器的调⽤,可以使模块加载器灵活定制,⽐如babel-loader加载器,该加载器能使我们使⽤ES6的语法来编写代
码;less-loader加载器,可以将less编译成css⽂件;
3. 开发便捷,能替代部分 grunt/gulp 的⼯作,⽐如打包、压缩混淆、图⽚转base64等。
4. 可以通过配置打包成多个⽂件,有效的利⽤浏览器的缓存功能提升性能。
3、wepback它的⽬标是是什么?
webpack它能将依赖的模块转化成可以代表这些包的静态⽂件
将依赖的模块分⽚化,并且按需加载
解决⼤型项⽬初始化加载慢的问题
每⼀个静态⽂件都可以看成⼀个模块
可以整合第三⽅库
能够在⼤型项⽬中运⽤
可以⾃定义切割模块的⽅式
4、webpack较之其他类似⼯具有什么不同?
有同步和异步两种不同的加载⽅式
Loader,加载器可以将其他资源整合到JS⽂件中,通过这种⽅式,可以讲所有的源⽂件形成⼀个模块
优秀的语法分析能⼒,⽀持 CommonJs AMD 规范
有丰富的开源插件库,可以根据⾃⼰的需求⾃定义webpack的配置
5、webpack为什么要将所有资源放在⼀个⽂件⾥⾯?
我们知道,对于浏览器来说,加载的资源越少,响应的速度也就越快,所以有时候我们为了优化浏览器的性能,会尽可能的将资源合并到⼀个主⽂件app.js⾥⾯。但是这导致的很⼤的缺点:
当你的项⽬⼗分庞⼤的时候,不同的页⾯不能做到按需加载,⽽是将所有的资源⼀并加载,耗费时间长,性能降低。
会导致依赖库之间关系的混乱,特别是⼤型项⽬时,会变得难以维护和跟踪。⽐如:哪些⽂件是需要A模块加载完后才能执⾏的?哪些页⾯会受到多个样式表同时影响的?等许多问题。
⽽webpack可以很好的解决以上缺点,因为它是⼀个⼗分聪明的模块打包系统,当你正确配置后,它会⽐你想象中的更强⼤,更优秀。
⼆、开启wbpack之旅
安装步骤如下:
1、⽣成package.json⽂件;
先装好node和npm,因为webpack是⼀个基于node的项⽬。然后⾸先我们需要在根⽬录下⽣成package.json⽂件,需要进⼊项⽬⽂件内根⽬录下执⾏如下命令:npm init
如上通过⼀问⼀答的⽅式后会在根⽬录下⽣成package.json⽂件,如下所⽰:
2 . 通过全局安装webpack
执⾏命令如下:npm install -g webpack 如下所⽰:
在c盘下会⽣成node_modules⽂件夹中会包含webpack,此时此刻我们可以使⽤webpack命令了;
在常规项⽬中把webpack依赖加⼊到package.json
npm init npm install webpack --save
更详尽的安装⽅法个可以参考
3. 配置webpack
每个⽬录下都必须有⼀个fig.js,它的作⽤就好⽐Gulpfile.js、或者 Gruntfile.js,就是⼀个项⽬配置,告诉webpack需要做什么。
⾸先先贴上⼀个⽐较完整的fig.js的代码,再详细介绍:
1
2
3
4
5 6 7 8
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72//详细的fig.js结构分析:
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var TransferWebpackPlugin = require('transfer-webpack-plugin');
devtool: 'source-map',//由于打包后的代码是合并以后的代码,不利于排错和定位,只需要在config中添加,这样出错以后就会采⽤source-map的形式直接显⽰你出错代码的位置。
//noParse:[/jquery/],//表⽰跳过jquery,不对其进⾏编译,这样可以提⾼打包的速度
//页⾯⼊⼝⽂件配置
entry: {
page1: "./src/index.js",
//page2: ["./src/index.js", "./src/main.js"],⽀持数组形式,将加载数组中的所有模块,但以最后⼀个模块作为输出
},
//⼊⼝⽂件输出配置
output: {
path: "dist/js/page",
filename: "[name].bundle.js",// page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page ⽂件夹下。
publicPath: "/dist/"//⽹站运⾏时的访问路径。
},
resolveLoader: {
//指定默认的loader路径,否则依赖⾛到上游会不到loader
root: path.join(__dirname, 'node_modules'),
alias: {//给⾃⼰写的loader设置别名
"seajs-loader": solve( __dirname, "./web_modules/seajs-loader.js")
}
},
//新建⼀个开发服务器,并且当代码更新的时候⾃动刷新浏览器。
devServer: {
historyApiFallback: true,
noInfo: true,
hot: true,
inline: true,
progress: true,
port:9090 //端⼝你可以⾃定义
},
module: {
// module.loaders 是最关键的⼀块配置。它告知 webpack每⼀种⽂件都需要使⽤什么加载器来处理:
loaders: [
{ test: /\.css$/, loader: 'style-loader!css-loader'},//.css ⽂件使⽤ style-loader 和 css-loader 来处理.
//{ test: /\.css$/, loader: 'style!css' },其他写法1、"-loader"其实是可以省略不写的,多个loader之间⽤“!”连接起来。
//{ test: /\.css$/, loaders: ["style", "css"] },其他写法2、⽤loaders数组形式;
//.scss ⽂件使⽤ style-loader、css-loader 和 sass-loader 来编译处理。
//在chrome中我们通过sourcemap可以直接调试less、sass源⽂件⽂件
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
{ test: /\.less$/, loader: 'style!css!less?sourceMap'},//.less ⽂件使⽤ style-loader、css-loader 和 less-loader 来编译处理
//.js ⽂件使⽤babel-loader来编译处理,设置exclude⽤来排除node_modules这个⽂件夹中的代码
{ test: /\.js$/, loader: 'babel!jsx',exclude: /node_modules/ },
{ test: /\.jsx$/, loader: "jsx-loader?harmony"},//.jsx ⽂件使⽤ jsx-loader 来编译处理
{ test: /\.json$/,loader: 'json'},
//{ test: /\.(png|jpg|jpeg|gif)$/, loader: 'url-loader?limit=8192'}, //图⽚⽂件使⽤ url-loader 来处理,⼩于8kb的直接转为base64
{test: /\.(png|jpg|gif|svg)$/,loader: 'url',
query: {limit: 10000,name: '[name].[ext]?[hash]'}//设置图⽚名称扩展名
},
{ test: /\.jade$/, loader: "jade-loader"},//.jade ⽂件使⽤ jade-loader 来编译处理
{ test: /\.ejs$/, loader: "ejs-loader"},//.ejs ⽂件使⽤ ejs-loader 来编译处理
{ test: /\.handlebars$/, loader: "handlebars-loader"},//.handlebars ⽂件使⽤handlebars-loader来编译处理handlebars模板⽂件
{ test: /\.dot$/, loader: "dot-loader"},//.dot ⽂件使⽤ dot-loader 来编译处理dot模板⽂件
{ test: /\.vue$/, loader: "vue-loader"},//.vue ⽂件使⽤ vue-loader 来编译处理
{ test: /\.coffee$/, loader: 'coffee-loader'},//.coffee ⽂件使⽤ coffee-loader 来编译处理
{ test: /\.html$/,loader: 'vue-html'},
{ test: /\.woff$/,loader: "url?limit=10000&minetype=application/font-woff"},
{ test: /\.ttf$/,loader: "file"},
{ test: /\.eot$/,loader: "file"},
{ test: /\.svg$/,loader: "file"}
]
},
//分内置插件和外置插件
plugins: [
//使⽤了⼀个 CommonsChunkPlugin 的插件,它⽤于提取多个⼊⼝⽂件的公共脚本部分,然后⽣成⼀个common.js来⽅便多页⾯之间进⾏复⽤。
new webpack.optimize.CommonsChunkPlugin('common.js'),
new webpack.optimize.UglifyJsPlugin({//压缩⽂件
compressor: {
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 12
7 128 129 130 131 132 133 warnings: false,//supresses warnings, usually from module minification
},
except: ['$super', '$', 'exports', 'require'] //排除关键字(可选)
}),
new webpack.DefinePlugin({// definePlugin 接收字符串插⼊到代码当中, 所以你需要的话可以写上 JS 的字符串
__DEV__: JSON.stringify(JSON.v.BUILD_DEV || 'true')),
__PRERELEASE__: JSON.stringify(JSON.v.BUILD_PRERELEASE || 'false'))
}),
new webpack.ProvidePlugin({//把⼀个全局变量插⼊到所有的代码中,⽀持jQuery plugin的使⽤;使⽤ProvidePlugin加载使⽤频率⾼的模块 //provide $, jQuery and window.jQuery to every script
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
}),
new webpack.NoErrorsPlugin(), //允许错误不打断程序
new TransferWebpackPlugin([ //把指定⽂件夹下的⽂件复制到指定的⽬录
{from: 'www'}
], solve(__dirname,"src")),
new HtmlwebpackPlugin({//⽤于⽣产符合要求的html⽂件;
title: 'Hello World app',
filename: 'assets/admin.html'
})
],
//其它解决⽅案配置
resolve: {
root: 'E:/github/flux-example/src', //绝对路径, 查module的话从这⾥开始查(可选)
extensions: ['', '.js', '.html', '.css', '.scss'], //⾃动扩展⽂件后缀名,意味着我们require模块可以省略不写后缀名resolve a doi name
alias: { //模块别名定义,⽅便后续直接引⽤别名,⽆须多写长长的地址//后续直接 require('AppStore') 即可
AppStore : 'js/stores/AppStores.js',
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
},
modulesDirectories: [//取相对路径,所以⽐起 root ,所以会多很多路径。查module(可选)
'node_modules',
'bower_components',
'lib',
'src'
]
}
};
v.NODE_ENV === 'production') {
/
/ /en/workflow/production.html
new webpack.DefinePlugin({
'v': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
//为组件分配ID,通过这个插件webpack可以分析和优先考虑使⽤最多的模块,并为它们分配最⼩的ID
new webpack.optimize.OccurenceOrderPlugin()
])
}
plugins中包含很多的内置插件和外部插件,它们都有各⾃的功能,⽤来处理相关的⽂件,这⾥只是罗列了部分,具体⽤法请看。就像我在前⾯提到的,fig.js的写法和在Node⾥的写法相同,我们主要看的就是⽂件中的ports⾥⾯的内容entry 是指⼊⼝⽂件的配置项,它是⼀个数组的原因是webpack允许多个⼊⼝点。
output是指输出⽂件的配置项
path -表⽰输出⽂件的路径
filename - 表⽰输出⽂件的⽂件名
plugins 顾名思义,使⽤插件可以给webpack添加更多的功能,使webpack更加的灵活和强⼤,webpack有两种类型的插件: webpack内置的插件
// ⾸先要先安装webpack模块
var webpack = require("webpack");
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false,
},
})
};
webpack外置插件
//npm install component-webpack-plugin 先要在安装该模版
var ComponentPlugin = require("component-webpack-plugin");
plugins: [
new ComponentPlugin()
]
}
更多的插件以及插件的⽤法,⼤家可以到上查看。
module 配置处理⽂件的选项
loaders ⼀个含有wepback中能处理不同⽂件的加载器的数组
test ⽤来匹配相对应⽂件的正则表达式
loaders 告诉webpack要利⽤哪种加载器来处理test所匹配的⽂件
loaders 的安装⽅法
$ npm install xxx-loader --save-dev
resolve:其它解决⽅案配置;
<,绝对路径, 查module的话从这⾥开始查(可选)
resolve.alias,模块别名定义,⽅便后续直接引⽤别名,⽆须多写长长的地址
三、利⽤webpack实现在页⾯上合理使⽤打包过后的js⽂件和图⽚
⽰例如下:
webpack_test⽬录结构如下:
最终完成版的⽬录结构为:
index.html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo1</title>
</head>
<body>
<div id="content"></div>
<img src="./build/img/demo.png">
<script src="./build/js/index.js"></script>
</body>
</html>
index.js代码如下:
require('./index.css');
index.css代码如下:
#content{
width:121px;
height:140px;
background-color: red;
}
demo.png⾃⼰随便⼀张即可;
根据fig.js的配置情况,操作步骤如下:
全局安装webpack,npm install webpack -g
进⼊到webpack_test⽬录下,初始化⽣成package.json⽂件,npm init
需要安装的loader有css-loader、style-loader、url-loader,webpack, npm install css-loader style-loader url-loader webpack--save-dev 执⾏webpack,⽣成打包过后的build/js/index.js,build/img/demo.png
在index.html中引⼊即可
效果如下:
源码地址为:,有需要的同学可以⾃⾏下载练习;
四、理解webpack⽀持commonJS和AMD/CMD两种模块机制进⾏打包
1.AMD/CMD模式:
AMD 规范在这⾥:,CMD 规范在这⾥:
AMD(Asynchronous Module Definition) 是 RequireJS 在推⼴过程中对模块定义的规范化产出。(即RequireJS模块规范)
RequireJS是⼀个⼯具库,主要⽤于客户端的模块管理。它可以让客户端的代码分成⼀个个模块,实现异步或动态加载,从⽽提⾼代码的性能和可维护性。它的模块管理遵守(Asynchronous Module Definition)。RequireJS的基本思想是,通过define⽅法,将代码定义为模块;通过require⽅法,实现代码的模块加载。⾸先,将require.js嵌⼊⽹页,然后就能在⽹页中进⾏模块化编程了。<script data-main="scripts/main" src="scripts/require.js"></script>上⾯代码的data-main属性不可省略,⽤于指定主代码所在的脚本⽂件,在上例中为scripts⼦⽬录下的main.js⽂件。⽤户⾃定义的代码就放在这个main.js⽂件中。
CMD(Common Module Definition )是 SeaJS 在推⼴过程中对模块定义的规范化产出。(即SeaJS模块规范)
SeaJS是⼀个遵循CMD规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。
CommonJS Modules/2.0 规范,是 BravoJS 在推⼴过程中对模块定义的规范化产出。
CommonJS API定义很多普通应⽤程序(主要指⾮浏览器的应⽤)使⽤的API,从⽽填补了这个空⽩。它的终极⽬标是提供⼀个类似Python,Ruby和Java标准库。这样的话,开发者可以使⽤CommonJS API编写应⽤程序,然后这些应⽤可以运⾏在不同的JavaScript解释器和不同的主机环境中。在兼容CommonJS的系统中,你可以实⽤JavaScript程序开发:
服务器端JavaScript应⽤程序
命令⾏⼯具
图形界⾯应⽤程序
混合应⽤程序(如,Titanium或Adobe AIR)
还有不少⋯⋯这些规范的⽬的都是为了 JavaScript 的模块化开发,特别是在浏览器端的。⽬前这些规范的实现都能达成浏览器端模块化开发的⽬的。
2、AMD/CMD模式区别
2.1从官⽅推荐的写法上⾯得出:
CMD ----- 依赖就近
Js代码
//CMD
define(function(require,exports,module){
var a = require('./a');
a.doSomthing();
});
AMD ----- 依赖前置
Js代码
//AMD
define(['./a','./b'],function(a,b){
//......
a.doSomthing();
//......
b.doSomthing();
})
当然AMD也⽀持CMD的写法。
2.2、执⾏顺序上:
CMD是延迟执⾏,推崇的是as lazy as possible
AMD是提前执⾏,requireJS从2.0开始可以延迟执⾏
2.3、api设计⾓度:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论