深入学习webpack(一)

  模块化的相关库和工具已经很多了,包括require.js、sea.js和一些工程化工具webpack、gulp、grant。那么我们该如何选择呢? 其实,我们只需要掌握了其中一种模块化的方案即可,因为这里最重要的是思想,而不是工具。在这些工具之中,webpack无疑是非常火的,并且在现在和未来也将大有可为,所以,这篇文章就好好的说说webpack!

  参考文章:webpack官方api文档

  https://doc.webpack-china.org/loaders/less-loader/

  webpack安装的loader方式。

  

  

什么是webpack?

  webpack是一款打包工具,其中的modules包括css、js、image等,通过webpack我们可以轻松的解决项目的依赖问题、模块化问题、后期的压缩测试等问题。

为什么使用webpack?

  好用啊!  相比于requirejs、gulp、grunt, webpack的优势都是非常明显的!

开始

本地安装webpack  

mkdir webpack-demo && cd webpack-demo
npm init -y
npm install --save-dev webpack
  • mkdir用于创建文件夹,&&标识当完成创建文件夹之后要做的指令。 cd 返回文件夹。

  • npm init -y 即创建package.json,通过-y,我们可以创建默认的信息。
  • --save-dev即将安装webpack记录在package.json中的dependicies中。
  • 注意:我们建议本地安装webpack,而不是全局安装webpack,因为全局的webpack将会限制你所使用的版本,在某些情况下回出错。比如,安装loader和plugins可能会依赖最新的webpack,这样,使用本地安装webpack就是最好的选择了。

获取webpack相关命令

./node_modules/.bin/webpack --help # Shows a list of valid cli commands
.\node_modules\.bin\webpack --help # For windows users
webpack --help # If you installed webpack globally
  • 即如果我们全局安装了webpack,直接webpack --help就可以获得相关的命令。
  • 如果我们是本地安装,就需要进入node_modules下的bin文件夹中执行 webpack --help 命令, 否则会出错。(注意Mac和Windows下的区别)

创建app文件夹并创建index.js

function component () {
var element = document.createElement('div'); /* lodash is required for the next line to work */
element.innerHTML = _.join(['Hello','webpack'], ' '); return element;
} document.body.appendChild(component());

这段代码即将一个创建的div插入到body中去。

注意: 这里的_并没有定义,我们在后面会引入lodash,才能支持使用_。

为执行index.js,在根目录下创建index.html

<html>
<head>
<title>webpack demo</title>
<script src="https://unpkg.com/lodash@4.16.6"></script>
</head>
<body>
<script src="app/index.js"></script>
</body>
</html>

OK! 到这里我们的这个项目就可以运行了,因为还没有做任何的配置,所以直接在浏览器中打开index.html可发现hello webpack。

总结一下可以发现,在两个js中,下面的js对上面的js的依赖的,lodash必须加载完成之后,index.js才能正常执行。但是,index.js对lodash的依赖又是隐式的,因为index.js并没有声明它需要lodash,而是直接认为_是全局中存在的,所以直接使用。

这样管理JavaScript存在下面的两个问题:

  1. 如果lodash不再存在后者两个js的顺序反了,那么这个应用将无法执行。
  2. 如果lodash存在但是没有被用到,即应用中不需要indexjs了,那么浏览器下载lodash就是多余的了。

为了解决上面两个问题,我们做出下面的改变。

为了将indexjs依赖的lodash和index打包在一起(形成明显的依赖关系),我们先安装lodash:

npm install --save lodash

在index.js中引入lodash

在index.js的最上方添加:

import _ from 'lodash';

注意: 这是引入lodash模块的_变量,使用import,这是一条语句,最后要添加分好。

index.html中只引入一个最后打包的文件

我们将index.html内容修改如下:

<html>
<head>
<title>webpack demo</title>
</head>
<body>
<script src="dist/bundle.js"></script>
</body>
</html>

即只保留了一个bundle.js,bundle.js是什么呢?实际上是最后我们通过webpack打包出来的文件,后面还会讲到。

到这里,我们就可以看到index.js是明确的依赖lodash的,并且将_绑定,这样,就不会造成全局污染了。

通过声明一个module(这里可以认为是index.js)所需要的依赖,webpack就可以利用这个信息来创建一个依赖图表,然后通过这个依赖图标将所需依赖按照正确的顺序打包到一个文件中。 对于没有用到的依赖将不会打包到文件中去。

现在,我们就可以来使用webpack运行项目了,并且把index.js当做入口文件,把bundle.js当做出口文件,且对于一个页面需要的所有代码都会被打包到这个出口文件中。

.\node_modules\.bin\webpack app/index.js dist/bundle.js

执行上述命令之后的结果如下:

C:\Users\Administrator\Desktop\webpack-demo>.\node_modules\.bin\webpack app/index.js dist/bundle.js
Hash: df00524299afa8ed4535
Version: webpack 2.5.
Time: 478ms
Asset Size Chunks Chunk Names
bundle.js kB [emitted] [big] main
[] ./~/.4.17.@lodash/lodash.js kB {} [built]
[] ./app/index.js bytes {} [built]
[] (webpack)/buildin/global.js bytes {} [built]
[] (webpack)/buildin/module.js bytes {} [built]

然后在浏览器中打开index.html我们就可以看到成功的打包结果了,并且在根目录下产生了一个dist文件,其中包含了bundle.js。说明:dist是distribution,即分发的意思。

存在的问题: 原本就几十行的代码通过webpack的打包之后达到了惊人的17000多行,大小达到了500余k,这是不是会影响性能呢?

解释:并非如此,因为lodash就有17000行了。

这是bundle.js在开头添加的70行代码:

/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = );
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

这是bundle.js在末尾添加的50行代码:

/* 2 */
/***/ (function(module, exports) { var g; // This works in non-strict mode
g = (function() {
return this;
})(); try {
// This works if eval is allowed (see CSP)
g = g || Function("return this")() || (,eval)("this");
} catch(e) {
// This works if the window reference is available
if(typeof window === "object")
g = window;
} // g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...} module.exports = g; /***/ }),
/* 3 */
/***/ (function(module, exports) { module.exports = function(module) {
if(!module.webpackPolyfill) {
module.deprecate = function() {};
module.paths = [];
// module.parent = undefined by default
if(!module.children) module.children = [];
Object.defineProperty(module, "loaded", {
enumerable: true,
get: function() {
return module.l;
}
});
Object.defineProperty(module, "id", {
enumerable: true,
get: function() {
return module.i;
}
});
module.webpackPolyfill = ;
}
return module;
}; /***/ })
/******/ ]);

后面会介绍他们的作用。

不难看出,这样做的好处是显而易见的,对于项目的依赖关系非常明显,不会出现浏览器下载多余的js文件情况、明确了每个项目的依赖关系,并且合并了两个js文件,在付出了一个120行代码的情况下减少了一个http请求,也许得不偿失,但是项目比较大时,所做的优化就会非常可观了。

使用ES2015modules

  在index.js中我们使用了import来引入lodash模块,但是这个import是es6的语法,在如今的浏览器中大多都是不支持的,所以webpack会将之转化为es5,在bundle.js中多出来的代码就是做这个工作的。

  值得注意的时:webpack不会修改你的除了import和export部分之外的代码。 如果你使用了ES2015的新特性,那么最好使用babel来转译为ES5的代码以获得更好的支持。

  下面的代码就是index.js的代码,可以看到webpack对之进行了封装,并没有替换我们的核心代码:

/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash__ = __webpack_require__();
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash__); function component () {
var element = document.createElement('div'); /* lodash is required for the next line to work */
element.innerHTML = __WEBPACK_IMPORTED_MODULE_0_lodash___default.a.join(['Hello','webpack'], ' '); return element;
} document.body.appendChild(component()); /***/ }),

对webpack进行配置

  对于这么一个简单的项目,我们在运行的时候就要写成:.\node_modules\.bin\webpack app/index.js dist/bundle.js。 那么对于更为复杂的项目,不难想象,我们是非常难管理的。

  所以为了解决这个问题,我们可以使用一个webpack可以参考的配置文件来自动打包你得模块文件。在你创建了 webpack.config.js 文件之后,你就可以使用下面的简单配置来代替复杂的命令行操作了。

  在根目录下添加如下的webpack.config.js文件:

var path = require('path');

module.exports = {
entry: './app/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist');
}
};

  说明:第一,path是node内置的,并且require也是node的用法,因为我们使用webpack是建立在使用node的基础上的。 第二,path.join()和path.resolve()是不同的,具体可见Stack Overflow

  至此,我们可以按照下面的方式来运行这个项目:

./node_modules/.bin/webpack --config webpack.config.js

  这和我们之前的运行结果是一样的。其中,--config用于说明使用根目录下的配置文件,而这个配置文件就是 webpack.config.js。

  

  另外,如果你使用的就是webpack.config.js(就是这个确定的文件名),并且也在根目录下,那么直接使用下面的命令就可以运行。

webpack

 

  但是,如果你使用的文件名是 webpack.test.js,那么使用webpack就会报错,提示在根目录下不存在 webpack.config.js 这个配置文件,所以我们就必须使用下面的这个命令:

./node_modules/.bin/webpack --config webpack.test.js

  这同样可以达到目的。

  

  配置文件的灵活性非常高,它允许我们增加loader规则、plugins、resolve选项以及其他很多对bundles的控制。

通过npm使用webpack

  上面所给的运行webpack的方式都比较复杂,我们可以通过在package.json中这样设置来简化操作:

{
...
"scripts": {
"build": "webpack"
},
...
}

  这是package.json中的script选项,阮一峰的一篇文章中对此做了详细的解释,大家可以搜索看看。

  通过这样的设置,我们就可以使用下面的命令运行webpack了。

npm run build

  

  同样的,如果我们把webpack.config.js修改为webpack.test.js,我们可以在package.json中修该build为“./node_modules/.bin/webpack --config webpack.test.js”,最后通过 npm run build也可以成功运行。

  

  注: 未经允许,不得转载。

深入学习webpack(一)的更多相关文章

  1. [译]开始学习webpack

    写在前面: 文章翻译自petehunt大神的petehunt/webpack-howto,作为学习webpack的开始.fork了一份,翻译后的在这里https://github.com/zjzhom ...

  2. webpack4 学习 --- webpack和webpack-dev-server

    以前了解过webpack2, 所以对webpack 不是很陌生,就直接入主题吧.新建一个文件夹,就叫它webpack-tut吧.然后在文件中新建一个src 文件夹,存放我们的源文件,再在src 文件夹 ...

  3. 如何学习 Webpack

    webpack-howto Tip: 本文是 webpack-howto 的原文,我觉得这篇文章写得非常好,确实算是目前学习 webpack 入门的必读文章.直接收录之. 本教程的目标 这是一本教你如 ...

  4. 深入学习webpack(二)

    深入学习webpack(二) 在深入学习webpack(一)中,我通过一个例子介绍了webpack的基本使用方法,下面将更为系统的学习webpack的基本概念,对于一门技术的掌握我认为系统化还是很重要 ...

  5. 跟我一起学习webpack使用配置文件(二)

    接着跟我一起学习webpack(一)中的项目来,我们接下来使用配置文件 使用npx webpack -h 我们可以查看webpack的配置参数 从我们在package.json中添加的命令来看,当项目 ...

  6. 学习webpack基础笔记01

    学习webpack基础笔记 1.webpack搭建环境最重要的就是如何使用loader和plugins,使用yarn/npm安装插件.预处理器,正确的配置好去使用 2.从0配置webpack - 1. ...

  7. vue第二单元(webpack的配置-学习webpack的常用配置)

    第二单元(webpack的配置-学习webpack的常用配置) #课程目标 掌握webpack的常用配置 掌握如何根据实际的需求修改webpack的对应配置 了解webpack-dev-server的 ...

  8. 零基础学习webpack打包管理

    这些天在项目之余的时间学习了webpack打包项目的东西,非常荣幸的找到一些大神的文章来学习,死劲嚼了几天,终于略知一二.在以后的工作上还需继续学习,下面我将分享我这几天学到的一点东西,希望能让我一个 ...

  9. Webpack学习-Webpack初识

    一.前言 webpack 到底是个什么东西呢,看了一大堆的文档,没一个能看懂的,因为上来就是给个module.exports 然后列一大堆配置,这个干啥,那个干啥,没一点用.但凡要用一个东西,一个东西 ...

随机推荐

  1. 5.Redis常用命令:Hash

    我们可以将Redis中的Hashes类型看成具有String Key和String Value的map容器.所以该类型非常适合于存储值对象的信息.如Username.Password和Age等.如果H ...

  2. WSDL/WebService/SOAP/REST/AXIS/CXF 开放式服务

    WebService是一种数据交换标准.通过WebService标准,你可以把项目中的方法作为接口提供给其他项目使用. 有时候我们习惯性地将具体提供服务的某个方法称为WebService.比如图书系统 ...

  3. K近邻 Python实现 机器学习实战(Machine Learning in Action)

    算法原理 K近邻是机器学习中常见的分类方法之间,也是相对最简单的一种分类方法,属于监督学习范畴.其实K近邻并没有显式的学习过程,它的学习过程就是测试过程.K近邻思想很简单:先给你一个训练数据集D,包括 ...

  4. 进入html+css世界的正确姿势

    今天,我带大家一起走进html+css的世界. HTML其实是HyperText Markup Language的缩写, 超文本标记语言.他是用于告诉浏览器这是一个网页, 也就是说告诉浏览器我是一个H ...

  5. 1029. Median

    Given an increasing sequence S of N integers, the median is the number at the middle position. For e ...

  6. 使用Python-iGraph绘制贴吧/微博好友关系图

    想通过图形化的方式显示社交网络特定用户的好友关系,上网找了一下这方面的图形库有networkx.graphviz等,找了好久我选择了iGraph这个图形库. igraph在Windows下的安装稍微有 ...

  7. .NET Framework 4.7 安装

    我们打开.NET Framework下载界面: https://www.microsoft.com/net/download/framework 这时你会发现,我们能下载的.NET Framework ...

  8. MidpointRounding 枚举值简要说明

    1. MidpointRounding.AwayFromZero 当小数点后取舍时5 时会取绝对值大的如 4.5 会取5 及正常的4舍5入. -- 官方解释翻译解释取绝对值小值感觉反译错了. 2.Mi ...

  9. STM32之呼吸灯实验

    首先,我想引用一下在一片博文里 看到 的一段话,写的很详细, 首先来说,你要使用PWM模式你得先选择用那个定时器来输出PWM吧!除了TIM6.TIM7这两个普通的定时器无法输出PWM外,其余的定时器都 ...

  10. JS中的循环嵌套 BOM函数

    [嵌套循环特点]                           外层循环转一次,内层循环转一圈              外层循环控制行数,内层循环控制每行元素个数             [做 ...