随着nodejs的发展,对于前端来说是一个福音,随之而来的前端开发们共享了非常多优秀的工具,前端的打包合并一直在前端基础构建中起了很重要的作用,
对于前端的开发模式以及线上的运行优化有这非常重要的影响. 一直用fis在做这方面的构建,为了够好的开发构建vue,那么webpack也应该好好熟悉一下.
一, webpack的安装
在命令行运行命令,这里说明一下 -g
是什么含义,就是安装到全局环境中,如果不加-g,那么它只会安装到你本地目录的node_modules文件夹下面,也就意味着,在其他文件中没办法用webpack
安装完成后,我们需要为项目生成一个package.json的文件,主要用于标记webpack的依赖.回头其他人开发项目时,可以直接 npm install就可以了.
1 2
| npm init npm install webpack --save-dev
|
npm init 先生成packge文件,
npm install webpack –save-dev 新建webpack并且保存到package.json文件中.
二, webpack的配置
每个项目下都必须配置有一个 webpack.config.js,类似于Gruntfile.js,其实是一个配置文件,webpack会读取文件中的配置来处理你要执行的那些配置.
三, 写一个简单的demo
创建test.js
1
| console.log('一个简单的demo');
|
创建index.html
1 2 3 4 5 6 7 8 9
| <html> <head> <meta charset="utf-8"> <title>webpack demo</title> </head> <body> <script type="text/javascript" src="testbuild.js" charset="utf-8"></script> </body> </html>
|
由于我们没写webpack.config.js,我们可以运行命令,生成testbuild.js文件
1
| webpack ./test.js testbuild.js
|
在浏览器中打开index.html文件
打开控制台,已经输入了我们想要的结果了.
在创建文件test1.js
1 2 3 4 5 6
| var test1 = { init: function(){ console.dir('我是来自于test1.js'); } } module.exports = test1;
|
修改test.js文件
1 2
| var test1 = require("./test1.js"); test1.init();
|
运行命令
1
| webpack ./test.js testbuild.js
|
查看index.html
我们来看一下webpack都干了什么,其实给我们加了一段代码,会生成一个module数组,并且把依赖的文件自动打包加载进来.也就是说原来我们通过seajs和requirejs在线加载的模块文件,已经全部打包到webpack中了.
有点就是不用在线上加载那么多modulejs了.通过webpack配置,我们可以按需打包.这个功能其实fis
也有.
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 73 74 75 76 77 78 79 80 81
| (function(modules) { var installedModules = {}; function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; var module = installedModules[moduleId] = { exports: {}, id: moduleId, loaded: false }; modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); module.loaded = true; return module.exports; } __webpack_require__.m = modules; __webpack_require__.c = installedModules; __webpack_require__.p = ""; return __webpack_require__(0); }) ([ function(module, exports, __webpack_require__) { var test1 = __webpack_require__(1); test1.init(); } , function(module, exports) { var test1 = { init: function() { console.dir('我是来自于test1.js'); } } module.exports = test1; } ]);
|
使用配置文件
1 2 3 4 5 6 7 8 9 10
| module.exports = { entry: "./test.js", output: { path: ./, filename: "testbuild.js" }, module: { loaders: [] } };
|
运行 webpack试试,也会出现我们出现的结果.
0) entry 和 output
1 2 3 4 5 6 7 8 9
| entry: { page1: "./test.js", page2: "./index.js", page3: "./index1.js" }, output: { path: './', filename: "[name].bundle.js" },
|
entry是只文件的入口,例如page1、page2也就相当于页面的入口文件
output 其中path是指输出的路径,filename只输出的文件名
1)插件项
plugins:
新建index.js
1 2
| var test1 = require("./test1.js"); test1.init();
|
例如我们把配置文件写为两个入口文件,和两个出口文件。
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
| module.exports = { entry: { page1: "./test.js", page2: "./index.js" }, output: { path: './', filename: "[name].bundle.js" }, module: { loaders: [{ test: /\.json$/, loader: "json" }, { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }, { test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' } ] } };
|
运行
此时我们发现生成两个page1.bundle.js以及page2.bundle.js
但是我们发现他们两个文件一模一样,对我们来说,他们两个有公用的部分,我们可以提取出来,这样我们就不用再前端加载相同的代码了。
接着我们在webpack.config.js中添加
1 2 3 4
| var webpack = require('webpack'); var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js'); plugins: [commonsPlugin]
|
完整的文件为
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
| var webpack = require('webpack'); var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js'); module.exports = { plugins: [commonsPlugin], entry: { page1: "./test.js", page2: "./index.js" }, output: { path: './', filename: "[name].bundle.js" }, module: { loaders: [{ test: /\.json$/, loader: "json" }, { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }, { test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' } ] } };
|
运行webpack之后,我们发现多了一个common.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 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
| (function(modules) { var parentJsonpFunction = window["webpackJsonp"]; window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) { var moduleId, chunkId, i = 0, callbacks = []; for(;i < chunkIds.length; i++) { chunkId = chunkIds[i]; if(installedChunks[chunkId]) callbacks.push.apply(callbacks, installedChunks[chunkId]); installedChunks[chunkId] = 0; } for(moduleId in moreModules) { modules[moduleId] = moreModules[moduleId]; } if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules); while(callbacks.length) callbacks.shift().call(null, __webpack_require__); if(moreModules[0]) { installedModules[0] = 0; return __webpack_require__(0); } }; var installedModules = {}; var installedChunks = { 2:0 }; function __webpack_require__(moduleId) { if(installedModules[moduleId]) return installedModules[moduleId].exports; var module = installedModules[moduleId] = { exports: {}, id: moduleId, loaded: false }; modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); module.loaded = true; return module.exports; } __webpack_require__.e = function requireEnsure(chunkId, callback) { if(installedChunks[chunkId] === 0) return callback.call(null, __webpack_require__); if(installedChunks[chunkId] !== undefined) { installedChunks[chunkId].push(callback); } else { installedChunks[chunkId] = [callback]; var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.type = 'text/javascript'; script.charset = 'utf-8'; script.async = true; script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"page1","1":"page2"}[chunkId]||chunkId) + ".bundle.js"; head.appendChild(script); } }; __webpack_require__.m = modules; __webpack_require__.c = installedModules; __webpack_require__.p = ""; }) ([ , function(module, exports) { var test1 = { init: function() { console.dir('我是来自于test1.js'); } } module.exports = test1; } ]);
|
page1.bundle.js
1 2 3 4 5 6 7 8 9 10
| webpackJsonp([0],[ function(module, exports, __webpack_require__) { var test1 = __webpack_require__(1); test1.init(); } ]);
|
page2.bundle.js
1 2 3 4 5 6 7 8 9
| webpackJsonp([1],[ function(module, exports, __webpack_require__) { var test1 = __webpack_require__(1); test1.init(); } ]);
|
我们发现公用的一部分代码被提取出来了。赞一个。
加入我们在加入两个文件:
test2.js index1.js
index1.js作为入口文件,引用test2.js里的方法
接着运行webpack
这是会后page3.bundle.js 只包含了test2.js里的代码
问题?? 1、在这里提出一个问题?就是现在对于我来说写代码还是比较麻烦的,因为我希望的时候这个入口文件不是由我来配置,而是自动遍历html中的入口文件。这是我觉得比较合理的地方。我觉得可以用插件来时实现,或者已经有了这样的插件
2)Loaders
loaders是非常重要的一块配置,它将告诉我们每一种文件需要使用什么加载器来加载处理。
例如最近比较火爆的vue.js为结尾的.vue文件。
需要单独安装到本地,并且配置到配置文件里
1、json-loader 处理json文件
安装
1
| sudo npm install -g --save-dev json-loader
|
用法
1 2
| var json = require("json!./file.json"); console.dir(json);
|
可以直接引用json文件中的对象包装成一个对象
2、Babel-Loader
label的应用,语言的转换
安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react `` 安装完成后,配置webpack.config.js ``` javascript { test: /\.js$/, exclude: /node_modules/, loader: 'babel',//在webpack的module部分的loaders里进行配置即可 query: { presets: ['es2015','react'] } }
|
新建Person.js,用es6语法书写代码
1 2 3 4 5 6 7 8 9 10 11
| class Person{ constructor(name, age){ this.name = name; this.age = age; } say(){ return `我是${this.name},我今年${this.age}岁了。`; } } export default Person;
|
在index.js中添加
1 2 3 4
| import Person from './Person.js'; let p = new Person('张三', 20); document.write(p.say());
|
编译后生成的文件
page2.bundle.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 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
| webpackJsonp([1, 3], [ function(module, exports, __webpack_require__) {
"use strict"; var _Person = __webpack_require__(2); var _Person2 = _interopRequireDefault(_Person); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var test1 = __webpack_require__(1); test1.init(); var json = __webpack_require__(3); console.dir(json); var p = new _Person2.default('张三', 20); document.write(p.say()); }, function(module, exports) {
'use strict'; var test1 = { init: function init() { console.dir('我是来自于test1.js'); } }; module.exports = test1; }, function(module, exports) {
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function() { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function(Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Person = function() { function Person(name, age) { _classCallCheck(this, Person); this.name = name; this.age = age; } _createClass(Person, [{ key: "say", value: function say() { return "我是" + this.name + ",我今年" + this.age + "岁了。"; } }]); return Person; }(); exports.default = Person; }, function(module, exports) { module.exports = { "name": "test" }; } ]);
|
可以看到 Person类被转换成了es5的写法。赞一个,不过同学们要小心了,es5现在目前支持的浏览器也只能到ie9,并且ie9不支持严格模式,需要支持ie8的同学注意了,es5只有某几个属性支持。ie6/7的同学们就更惨了。。。。
3) css
安装
1
| npm install --save-dev css-loader style-loader sass-loader less-loader less postcss-loader
|
其中包括了sass和less,我们测试less
看看配置文件
1 2 3 4 5 6 7 8
| { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }, { test: /\.css$/, loader: 'style-loader!css-loader' }
|
创建file.less文件
1 2 3 4
| @bg: black; body{ background: @bg; }
|
index.js中加入
1
| require("!style!css!less!./file.less");
|
运行webpack后,css已经被打包进入到js中,看图
问题?? 提出一个问题,如果是文件形式的,同样也有less路径的填写问题?
4) url-loader
安装url-loader
1
| npm install --save-dev url-loader file-loader
|
配置文件
1 2 3 4
| { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' },
|
在index.js中添加代码
1 2
| var img = require('./23.png'); console.dir(img);
|
在file.less中添加
1
| background: url(23.png) no-repeat;
|
运行webpack
可以看到
23.png转换成了1614a0070c3a3656c434ebca4d5f4000.png
问题?? 就是html中的图片怎么处理?
3、resolve
root告诉我们module从哪里查找
extensions 自动扩展文件后缀名,也就是说可以省略地址
alias 别名,可以代替js的路径
1 2 3 4 5 6 7 8 9 10
| resolve: { root: '~/test/src', extensions: ['', '.js', '.json', '.scss'], alias: { test : 'js/test1.js', } }
|
webpack 命令
1 2 3 4 5 6 7 8
| $ webpack --config XXX.js //使用另一份配置文件(比如webpack.config2.js)来打包 $ webpack --watch //监听变动并自动打包 $ webpack -p //压缩混淆脚本,这个非常非常重要! $ webpack -d //生成map映射文件,告知哪些模块被最终打包到哪里了
|
执行也可以加参数,例如加
$ webpack –display-error-details 可以抛出更详细的错误。