问题: 1. 全局变量泛滥,2. 命名冲突, 3. 依赖关系管理,先去加载 a ,在去加载b, 否则就会报错;
二,模块化的初级阶段:立即执行函数
var moduleA = function(){
var a, b;
return {
message: function(c){
alert(a+b+c)
}
}
}()
(function(window){
// do something
window.jQuery = window.$ = jQuery;
})(window)
优点:模块内可以定义一些私有变量,缺点:仍然会污染全局变量,window.jquery ,没有解决模块依赖;
现代模块时代:
1. commonjs , node 提出,同步不太适合浏览器,
var math = require(‘math‘);
- math.add(2, 3);
在服务器端,文件都是在硬盘中,而在浏览器中,文件需要网络穿过来,如果一个模块没传过来,整个应用都要停在那里等,浏览器假死;
2. requireJSAMD) , SeaJS ( CMD ),
require([‘math‘], function(math){
math.add(2,3)
})
异步,传入回调函数作为参数,等加载完成后执行;
3. ES6 Module, 目前比较流行;
import math from ‘math‘;
math.add(2, 3);
模块化的目的:高内聚,低耦合;
前端的模块加载:
前端模块要在 浏览器中运行,必经的过程就是从服务器到浏览器的传输;两个极端方式:1. 每一个模块都发起一个请求; 2. 所有模块打包成一个,只请求一次;
显然,都不好;按需加载是比较合适的;
前端的模块不仅仅有js,还有css,less, sass,图片,他们都是模块,都可以用require的方式加载;
require(‘./style.css‘);
require(‘./style.less‘);
require(‘./style.jade‘);
require(‘./image.png‘);
webpack 本身只能处理js ,如果想处理其他类型的文件,就需要用到 loader 进行转换;loader 本身是一个函数,接受源文件作为参数,返回转换后的结果;
loader的特点:
- 可以链式调用,我处理完了交给你接着处理,但是最后一个loader必须返回javascript
- loader 可以同步或者异步执行
- loader 可以运行在 nodejs中,所以可能做任何事情
- loader 通过参数来传递配置
- 插件让loader 有更多的特性
var webpack = require(‘webpack‘);
module.exports = {
entry: ‘./entry.js‘,
output: {
path: __dirname,
filename: ‘bundle.js‘
},
module:{
loaders: [
{test: /\.css$/, loader: ‘style-loader!css-loader‘}
]
}
}
添加插件,可以让loader 更加强大。插件有内置的,也有第三方的;
var webpack = require(‘webpack‘);
module.exports = {
entry: ‘./entry.js‘,
output: {
filename: ‘bundle.js‘
},
module: {
loaders: [
{ test:/\.css$/, loader: ‘style-loader!css-loader‘}
]
},
plugin: [
new webpack.BannerPlugin(‘dujuncheng created‘)
]
}
1. 安装
/ dudu01 执行 npm init ,
npm init
会把该文件夹变成一个项目,会自动生成一个package.json 配置文件;
cnpm install webpack --save
为了把webpack 添加到项目依赖里面;
package.json 文件里面会多了一个字段:
"dependencies": {
"webpack": "^2.5.1"
}
2. webpack 会自动将文件进行打包
安装好了以后,我们新建两个文件:index.html, entry.js
// index.html
<div id=‘app‘></div>
<script src = ‘bundle.js‘>
//entry.js
document.getElementById(‘app‘).textContent = ‘hello‘
然后我们在控制台输入:
webpack entry.js bundle.js
3. webpack 会自动分析 依赖,
webpack 会自动分析 entry.js里面依赖了哪些文件,会自动一起打包到bundle.js 里面;
我们新建一个bundle.js 文件,里面写的是:
module.exports = ‘dujuncheng‘
在entry.js 里面引入:
var name = require(‘./name‘);
document.getElementById(‘app‘).textContent=‘hello‘+name
通过
webpack entry.js bundle.js
再次打包,我们就可以把entry.js依赖的name.js 一起打包进入bundle.js
4. loader
webpack 本身只能处理js ,如果想处理其他类型的文件,就需要用到 loader 进行转换;loader 本身是一个函数,接受源文件作为参数,返回转换后的结果;
如果我们想使用一个loader ,那么我们必须要手动安装;
cnpm install css-loader style-loader --save
在package.json里面就会多了loader:
"dependencies": {
"css-loader": "^0.28.1",
"style-loader": "^0.17.0",
"webpack": "^2.5.1"
}
我们新建webpack.config.js, 里面的内容是:
module.exports = {
entry: ‘./entry.js‘,
output: {
path: __dirname,
filename: ‘bundle.js‘
},
module: {
loaders:[
{ test:/\.css$/, loader: ‘style-loader!css-loader‘ }
]
}
}
多了一个module 对象,里面有一个数组 loaders, 数组的每一项都是对象,{test: /\.css$/, loader: ‘style-loader! css-loader‘}
这就是告诉 webpack, 只要是css , 就需要用这两个loader 进行处理;
我们新建一个style.css,一会要把它打包进 bundle.js
body {
background-color: red
}
//entry.js
require(‘./style.css‘);
document.getElementById(‘app‘).textContent = ‘dujuncheng‘ ;
我们把css 文件引入了js ,中间会自动用 css-loader , style-loader 进行处理;
// 因为我们配置了webpack.config.js 配置文件,所以我们只要 webpack 就可以打包了
webpack
5. source map
在没有用sourcemap的时候,我们在开发人员工具那里,看到了有 index.html 和 bundle.js
bundle. js 不用我们关心,因为是打包后的,我们需要关心的是 source-map
webpack --devtool source-map
项目中会多了一个 bundle.js.map 的文件,我们的浏览器窗口下:
source-map 方便了我们的调试,在name.js 文件里面,添加: debugger ,我们就可以在那个位置打一个断点;
如果我们不想在每一次的webpack 都带一个 devtool 我们可以在webpack.config.js 文件里面进行修改:
module.exports = {
entry: ‘./entry.js‘,
output: {
path: __dirname,
filename: ‘bundle.js‘
},
devtool: ‘source-map‘,
module: {
loaders: [
{
test: /\.css$/,
loader: ‘style-loader!css-loader‘
}
]
}
}
webpack 和 babel 进行配合
cnpm install babel-loader babel-core babel-preset-es2015 --save-dev
code splitting
两个极端的的情况,我们把所有的文件都打包到一个文件里面,或者我们的每个文件都要分别打包;这两个都不好;
怎么做?
1. 分离业务代码和第三方库 [ vender ]
2. 分离css 文件
3. 按需加载 [ import() ]
第三方库更新较慢,并且可以锁版本,利用浏览器的缓存来加载第三方的库;
按需加载,用户访问了某一个路由的时候,再去加载相应的组件;
首先,我们想可视化的看到,我们的文件中是哪些比较占体积:webpack-bundle-analyzer
npm install --save-dev webpack-bundle-analyzer
//webpack.config.js
var BundleAnalyzerPlugin = require(‘webpack-bundle-analyzer‘).BundleAnalyzerPlugin;
// ...
plugins: [new BundleAnalyzerPlugin()]
// ...
通过这个插件,我们就可以很直观的分析啦;
分离第三方的库:我们的思路是:把node_module 里面的用到的 js插件,都放到vender.js 里面
用webpack 自带的 commonChunkPlugin:
new webpack.optimize.CommonsChunkPlugin({
name: ‘vendor‘,
minChunks: ({ resource }) => (
resource && resource.indexOf(‘node_modules‘) >= 0 && resource.match(/\.js$/))
}),
按需加载
很简单,需要改两个地方:路由声明组件的那个地方,output的文件名;
1. 路由声明组件:
// import test1 from ‘@/components/test1‘
// import test2 from ‘@/components/test2‘
// import test3 from ‘@/components/test3‘
const test1 = () => import(
/* webpackChunkName: "Emoji" */
‘@/components/test1‘)
const test2 = () => import(
/* webpackChunkName: "Emoji" */
‘@/components/test2‘)
const test3 = () => import(
/* webpackChunkName: "Emoji" */
‘@/components/test3‘)
2. chunkFilename修改
filename: ‘[name].js‘,
chunkFilename: ‘[name].chunk.js‘,
如果你用了 Babel ,就需要装上这个插件:babel plugin syntax dynamic import 来解析 import() 语法。修改 .babelrc :
{
"plugins": ["syntax-dynamic-import"]
}