资讯专栏INFORMATION COLUMN

Javascript模块化及webpack基本介绍

figofuture / 657人阅读

摘要:可维护性根据定义,每个模块都是独立的。良好设计的模块会尽量与外部的代码撇清关系,以便于独立对其进行改进和维护。这标志模块化编程正式诞生。的模块系统,就是参照规范实现的。对象就代表模块本身。

javascript模块化及webpack基本介绍 JavaScript 模块化发展历程

什么是模块化 ?

为什么要做Javascript模块化?

JavaScript 模块化发展历程

什么是模块化 ?
模块化是一种处理复杂系统分解成为更好的可管理模块的方式,它可以把系统代码划分为一系列职责单一,高度解耦且可替换的模块,系统中某一部分的变化将如何影响其它部分就会变得显而易见,系统的可维护性更加简单易得。

一个模块就是实现特定功能的文件, 逻辑上相关的代码组织到同一个包内,包内是一个相对独立的王国,不用担心命名冲突什么的,那么外部使用的话直接引入对应的package即可.

就好像作家会把他的书分章节和段落;程序员会把他的代码分成模块。

就好像书籍的一章,模块仅仅是一坨代码而已。

好的代码模块分割的内容一定是很合理的,便于你增加减少或者修改功能,同时又不会影响整个系统。

为什么要做Javascript模块化?

早期前端只是为了实现简单的页面交互逻辑,随着Ajax技术的广泛应用,前端库的层出不穷,前端代码日益膨胀,JavaScript却没有为组织代码提供任何明显帮助,甚至没有类的概念,更不用说模块(module)了,这时候JavaScript极其简单的代码组织规范不足以驾驭如此庞大规模的代码.

模块化可以使你的代码低耦合,功能模块直接不相互影响。

可维护性:根据定义,每个模块都是独立的。良好设计的模块会尽量与外部的代码撇清关系,以便于独立对其进行改进和维护。维护一个独立的模块比起一团凌乱的代码来说要轻松很多。

命名空间:在JavaScript中,最高级别的函数外定义的变量都是全局变量(这意味着所有人都可以访问到它们)。也正因如此,当一些无关的代码碰巧使用到同名变量的时候,我们就会遇到“命名空间污染”的问题。

可复用性:现实来讲,在日常工作中我们经常会复制自己之前写过的代码到新项目中, 有了模块, 想复用的时候直接引用进来就行。

JavaScript 模块化发展历程
前端的先驱在刀耕火种的阶段开始,做了很多努力,在现有的运行环境中,实现"模块"的效果。
函数封装

模块就是实现特定功能的一组方法。在JavaScript中,函数是创建作用域的唯一方式, 所以把函数作为模块化的第一步是很自然的事情.

function foo(){
    //...
}

function bar(){
    //...
}

上面的,组成一个模块。使用的时候,直接调用就行了。

这种做法的缺点很明显:全局变量被污染,很容易命名冲突, 而且模块成员之间看不出直接关系。

对象写法

为了解决上面的缺点,可以把模块写成一个对象,所有的模块成员都放到这个对象里面。

var MYAPP = {
    count: 0,
    foo: function(){},
    bar: function(){}
}

MYAPP.foo();

上面的代码中,函数foobar, 都封装在MYAPP对象里。使用的时候,就是调用这个对象的属性。 但是,这样的写法会暴露所有模块成员,内部状态可以被外部改写.

立即执行函数(IIFE)写法

使用立即执行函数(Immediately-Invoked Function Expression,IIFE),可以达到不暴露私有成员的目的。

var Module = (function(){
    var _private = "safe now";
    var foo = function(){
        console.log(_private)
    }

    return {
        foo: foo
    }
})()

Module.foo();
Module._private; // undefined

这种方法的好处在于,你可以在函数内部使用局部变量,而不会意外覆盖同名全局变量,但仍然能够访问到全局变量, 在模块外部无法修改我们没有暴露出来的变量、函数.

引入依赖

将全局变量当成一个参数传入到匿名函数然后使用

var Module = (function($){
    var _$body = $("body");     // we can use jQuery now!
    var foo = function(){
        console.log(_$body);    // 特权方法
    }

    // Revelation Pattern
    return {
        foo: foo
    }
})(jQuery)

Module.foo();

jQuery的封装风格曾经被很多框架模仿,通过匿名函数包装代码,所依赖的外部变量传给这个函数,在函数内部可以使用这些依赖,然后在函数的最后把模块自身暴漏给window

如果需要添加扩展,则可以作为jQuery的插件,把它挂载到$上。
这种风格虽然灵活了些,但并未解决根本问题:所需依赖还是得外部提前提供、还是增加了全局变量。

模块化面临什么问题

从以上的尝试中,可以归纳出js模块化需要解决那些问题:

如何安全的包装一个模块的代码?(不污染模块外的任何代码)

如何唯一标识一个模块?

如何优雅的把模块的API暴漏出去?(不能增加全局变量)

如何方便的使用所依赖的模块?

围绕着这些问题,js模块化开始了一段艰苦而曲折的征途。

JavaScript 模块规范

上述的所有解决方案都有一个共同点:使用单个全局变量来把所有的代码包含在一个函数内,由此来创建私有的命名空间和闭包作用域。

你必须清楚地了解引入依赖文件的正确顺序。就拿Backbone.js来举个例子,想要使用Backbone就必须在你的页面里引入Backbone的源文件。

然而Backbone又依赖 Underscore.js,所以Backbone的引入必须在其之后。

而在工作中,这些依赖管理经常会成为让人头疼的问题。

另外一点,这些方法也有可能引起命名空间冲突。举个例子,要是你碰巧写了俩重名的模块怎么办?或者你同时需要一个模块的两个版本时该怎么办?

还有就是协同开发的时候, 大家编写模块的方式各不相同,你有你的写法,我有我的写法, 那就乱了套.

接下来介绍几种广受欢迎的解决方案

CommonJS

AMD

CMD

ES6模块

CommonJS

2009年,美国程序员Ryan Dahl创造了node.js项目,将javascript语言用于服务器端编程。

这标志Javascript模块化编程正式诞生。因为老实说,在浏览器环境下,没有模块也不是特别大的问题,毕竟网页程序的复杂性有限;但是在服务器端,一定要有模块,与操作系统和其他应用程序互动,否则根本没法编程。

node.js的模块系统,就是参照CommonJS规范实现的。

CommonJS定义的模块分为:

定义模块:

根据CommonJS规范,一个多带带的文件就是一个模块。每一个模块都是一个多带带的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性。

模块输出:

模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象。module对象就代表模块本身。

加载模块:

加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象。

// math.js
exports.add = function(a, b){
    return a + b;
}
// main.js
var math = require("math")      // ./math in node
console.log(math.add(1, 2));    // 3

这种实现模式有两点好处:

避免全局命名空间污染

明确代码之间的依赖关系

但是, 由于一个重大的局限,使得CommonJS规范不适用于浏览器环境。

看上面的main.js代码, 第二行的math.add(1, 2),在第一行require("math")之后运行,因此必须等math.js加载完成。也就是说,如果加载的依赖很多, 时间很长,整个应用就会停在那里等。

我们分析一下浏览器端的js和服务器端js都主要做了哪些事,有什么不同:

服务器端JS 浏览器端JS
相同的代码需要多次执行 代码需要从一个服务器端分发到多个客户端执行
CPU和内存资源是瓶颈 带宽是瓶颈
加载时从磁盘中加载 加载时需要通过网络加载

这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态。

因此,浏览器端的模块,不能采用"同步加载"(synchronous),只能采用"异步加载"(asynchronous)。这就是AMD规范诞生的背景。

AMD
AMD 即Asynchronous Module Definition,中文名是异步模块定义的意思。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
// main.js
  require(["moduleA", "moduleB", "moduleC"], function (moduleA, moduleB, moduleC){
    // some code here
  });

用全局函数define来定义模块,用法为:define(id?, dependencies?, factory);

id为模块标识,遵从CommonJS Module Identifiers规范

dependencies为依赖的模块数组,在factory中需传入形参与之一一对应

如果dependencies的值中有"require"、"exports""module",则与commonjs中的实现保持一致

如果dependencies省略不写,则默认为["require", "exports", "module"]factory中也会默认传入require,exports,module.

如果factory为函数,模块对外暴漏API的方法有三种:return任意类型的数据、exports.xxx=xxx、module.exports=xxx.

如果factory为对象,则该对象即为模块的返回值

大名鼎鼎的require.js就是AMD规范的实现.

require.js要求,每个模块是一个多带带的js文件。这样的话,如果加载多个模块,就会发出多次HTTP请求,会影响网页的加载速度。因此,require.js提供了一个优化工具(Optimizerr.js,当模块部署完毕以后,可以用这个工具将多个模块合并在一个文件中,实现前端文件的压缩与合并, 减少HTTP请求数。

我们来看一个require.js的例子

//a.js
define(function(){
     console.log("a.js执行");
     return {
          hello: function(){
               console.log("hello, a.js");
          }
     }
});
//b.js
define(function(){
     console.log("b.js执行");
     return {
          hello: function(){
               console.log("hello, b.js");
          }
     }
});
//main.js
require.config({
  paths: {
      "jquery": "../js/jquery.min"
  },
});

require(["jquery","a", "b"], function($, a, b){
  console.log("main.js执行");
  a.hello();
  $("#btn").click(function(){
       b.hello();
  });
})

上面的main.js被执行的时候,会有如下的输出:
a.js执行
b.js执行
main.js执行
hello, a.js

在点击按钮后,会输出:
hello, b.js

但是如果细细来看,b.js被预先加载并且预先执行了,(第二行输出),b.hello这个方法是在点击了按钮之后才会执行,如果用户压根就没点,那么b.js中的代码应不应该执行呢?

这其实也是AMD/RequireJs被吐槽的一点,由于浏览器的环境特点,被依赖的模块肯定要预先下载的。问题在于,是否需要预先执行?如果一个模块依赖了十个其他模块,那么在本模块的代码执行之前,要先把其他十个模块的代码都执行一遍,不管这些模块是不是马上会被用到。这个性能消耗是不容忽视的。

另一点被吐槽的是,在定义模块的时候,要把所有依赖模块都罗列一遍,而且还要在factory中作为形参传进去,要写两遍很大一串模块名称,像这样:

define(["a", "b", "c", "d", "e", "f", "g"], function(a, b, c, d, e, f, g){  ..... })
CMD
CMD 即Common Module Definition, CMD是sea.js的作者在推广sea.js时提出的一种规范.

CMD 规范中,一个模块就是一个文件。代码的书写格式如下:

define(function(require, exports, module) {
    // 模块代码
    // 使用require获取依赖模块的接口
    // 使用exports或者module或者return来暴露该模块的对外接口
})

也是用全局的define函数定义模块, 无需罗列依赖数组,在factory函数中需传入形参require,exports,module.

require 用来加载一个 js 文件模块,require 用来获取指定模块的接口对象 module.exports

//a.js
define(function(require, exports, module){
     console.log("a.js执行");
     return {
          hello: function(){
               console.log("hello, a.js");
          }
     }
});
//b.js
define(function(require, exports, module){
     console.log("b.js执行");
     return {
          hello: function(){
               console.log("hello, b.js");
          }
     }
});
//main.js
define(function(require, exports, module){
     console.log("main.js执行");

     var a = require("a");
     a.hello();    

     $("#b").click(function(){
          var b = require("b");
          b.hello();
     });
    
});

上面的main.js执行会输出如下:
main.js执行
a.js执行
hello, a.js

a.js和b.js都会预先下载,但是b.js中的代码却没有执行,因为还没有点击按钮。当点击按钮的时候,会输出如下:
b.js执行
hello, b.js

Sea.js加载依赖的方式

加载期:即在执行一个模块之前,将其直接或间接依赖的模块从服务器端同步到浏览器端;

执行期:在确认该模块直接或间接依赖的模块都加载完毕之后,执行该模块。

AMD vs CMD

AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块,

CMD推崇就近依赖,只有在用到某个模块的时候再去require,

AMD和CMD最大的区别是对依赖模块的执行时机处理不同

同样都是异步加载模块,AMD在加载模块完成后就会执行改模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑.

CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的。

这也是很多人说AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行的原因。

ES6模块
上述的这几种方法都不是JS原生支持的, 在ECMAScript 6 (ES6)中,引入了模块功能, ES6 的模块功能汲取了CommonJS 和 AMD 的优点,拥有简洁的语法并支持异步加载,并且还有其他诸多更好的支持。

简单来说,ES6 模块的设计思想就是:一个 JS 文件就代表一个 JS 模块。在模块中你可以使用 import 和 export 关键字来导入或导出模块中的东西。

ES6 模块主要具备以下几个基本特点:

自动开启严格模式,即使你没有写 use strict

每个模块都有自己的上下文,每一个模块内声明的变量都是局部变量,不会污染全局作用域

模块中可以导入和导出各种类型的变量,如函数,对象,字符串,数字,布尔值,类等

每一个模块只加载一次,每一个 JS 只执行一次, 如果下次再去加载同目录下同文件,直接从内存中读取。

补充: Typescript 识别模块的模式
一般来讲,组织声明文件的方式取决于库是如何被使用的。 在JavaScript中一个库有很多使用方式,这就需要你书写声明文件去匹配它们.

通过库的使用方法及其源码来识别库的类型。

全局库

全局库是指能在全局命名空间下访问的,许多库都是简单的暴露出一个或多个全局变量。 比如jQuery.

当你查看全局库的源代码时,你通常会看到:

顶级的var语句或function声明

一个或多个赋值语句到window.someName

模块化库

一些库只能工作在模块加载器的环境下。 比如,像 express只能在Node.js 里工作所以必须使用CommonJSrequire函数加载。

模块库至少会包含下列具有代表性的条目之一:

无条件的调用requiredefine

import * as a from "b"; or export c;这样的声明

赋值给exportsmodule.exports

UMD (Universal Module Definition)

UMD创造了一种同时使用两种规范的方法,并且也支持全局变量定义。所以UMD的模块可以同时在客户端和服务端使用。

本质上,UMD 是一套用来识别当前环境支持的模块风格的 if/else 语句。下面是一个解释其功能的例子:
(function (root, factory) {
 if (typeof define === "function" && define.amd) {
     define(["libName"], factory);
 } else if (typeof module === "object" && module.exports) {
     module.exports = factory(require("libName"));
 } else {
     root.returnExports = factory(root.libName);
 }
  }(this, function (b) {})
前端自动化构建工具

Grunt

Gulp

Webpack

Browserify

......

简单的说,Grunt / Gulp 和 browserify / webpack 不是一回事。

Gulp / Grunt Gulp / Grunt 是一种工具,能够优化前端工作流程。比如自动刷新页面、combo、压缩css、js、编译less等等。简单来说,就是使用Gulp/Grunt,然后配置你需要的插件,就可以把以前需要手工做的事情让它帮你做了。

说到 browserify / webpack ,那还要说到 seajs / requirejs 。这四个都是JS模块化的方案。其中seajs / require 是一种类型,browserify / webpack 是另一种类型。seajs / require : 是一种在线"编译" 模块的方案,相当于在页面上加载一个 CMD/AMD 解释器。这样浏览器就认识了 define、exports、module 这些东西。也就实现了模块化。

browserify / webpack : 是一个预编译模块的方案,相比于上面 ,这个方案更加智能, 首先,它是预编译的,不需要在浏览器中加载解释器。另外,你在本地直接写JS,不管是 AMD / CMD / ES6 风格的模块化,它都能认识,并且编译成浏览器认识的JS。这样就知道,Gulp是一个工具,而webpack等等是模块化方案。Gulp也可以配置seajs、requirejs甚至webpack的插件。

Grunt

每次运行grunt 时,他就利用node提供的require()系统查找本地安装的 Grunt

如果找到一份本地安装的 Gruntgrunt-CLI就将其加载,并传递Gruntfile中的配置信息,然后执行你所指定的任务。

安装grunt-cli

npm install -g grunt-cli

配置gruntfile.js文件

module.exports = function(grunt) {
  // 项目配置.
  grunt.initConfig({
    // 定义Grunt任务
  });

  // 加载能够提供"uglify"任务的插件。
  grunt.loadNpmTasks("grunt插件"); 

  // Default task(s).
  grunt.registerTask("default", ["任务名"]); 
}
gulp

gulp是基于Nodejs的自动化任务运行器,它能自动化地完成javascript/sass/less/html/image/css 等文件的的测试、检查、合并、压缩、格式化、浏览器自动刷新、部署文件生成,并监听文件在改动后重复指定的这些步骤。

使用Gulp的优势就是利用流的方式进行文件的处理,使用管道(pipe)思想,前一级的输出,直接变成后一级的输入,通过管道将多个任务和操作连接起来,因此只有一次I/O的过程,流程更清晰,更纯粹。Gulp去除了中间文件,只将最后的输出写入磁盘,整个过程因此变得更快。

使用Gulp,可以避免浏览器缓存机制,性能优化(文件合并,减少http请求;文件压缩)以及效率提升(自动添加CSS3前缀;代码分析检查)

browserify

Browserify 是一个模块打包器,它遍历代码的依赖树,将依赖树中的所有模块打包成一个文件。有了 Browserify,我们就可以在浏览器应用程序中使用 CommonJS 模块。

browserify模块化的用法和node是一样的,所以npm上那些原本仅仅用于node环境的包,在浏览器环境里也一样能用.

webpack官网有对二者的使用方法进行对比,可以看一下:[webpack for browserify users
](http://webpack.github.io/docs...

browserify main.js -o bundle.js

Compare Webpack vs Browserify vs RequireJS

webpack

官网对webpack的定义是MODULE BUNDLER(模块打包器),他的目的就是把有依赖关系的各种文件打包成一系列的静态资源。 请看下图

Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:main.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。

webpack核心概念 1. 入口(entry):

webpack将创建所有应用程序的依赖关系图表(dependency graph)。

entry配置项告诉Webpack应用的根模块或起始点在哪里,
入口起点告诉 webpack 从哪里开始,并遵循着依赖关系图表知道要打包什么。可以将应用程序的入口起点认为是根上下文或 app 第一个启动文件。它的值可以是字符串、数组或对象.

//webpack.config.js
const config = {
 entry: {
   app: "./src/app.js",
   vendors: "./src/vendors.js"
 }
};
2. 出口(output)

将所有的资源(assets)合并在一起后,我们还需要告诉 webpack 在哪里打包我们的应用程序。output 选项控制 webpack 如何向硬盘写入编译文件。注意,即使可以存在多个入口起点,但只指定一个输出配置。

output: {
    path: helpers.root("dist/nonghe"),
    publicPath: "/",
    filename: "js/[name].[chunkhash].bundle.js",
    chunkFilename: "js/[name].[chunkhash].bundle.js"
 }
3. 加载器(loader)
在webpack的世界里, 一切皆模块, 通过 loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS 等。而且 webpack 只理解 JavaScript。

对比 Node.js 模块,webpack 模块能够以各种方式表达它们的依赖关系:

ES2015 import 语句

CommonJS require() 语句

AMD define 和 require 语句

css/sass/less 文件中的 @import 语句。

样式(url(...))或 HTML 文件()中的图片链接

webpack compiler在碰到上面那些语句的时候, 通过与其相对应的loader将这些文件进行转换,而转换后的文件会被添加到依赖图表中。

module: {
        loaders: [{
            test: /.scss$/,
            loaders: "style!css!sass"
        }, {
            test: /.(png|jpg|svg)$/,
            loader: "url?limit=20480" //20k
        }]
    }}
4. 插件(plugin)

plugin 插件,用于扩展webpack的功能,在webpack构建生命周期的节点上加入扩展hookwebpack加入功能。

LoadersPlugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(js,ts, Scss,Less..),一次处理一个,通常作用于包生成之前或生成的过程中。

插件并不直接操作单个文件,它直接对整个构建过程其作用。

几款常用的插件

HtmlWebpackPlugin : 这个插件的作用是依据一个简单的html模板,生成一个自动引用打包后的JS文件的新index.html

Hot Module Replacement: 它允许你在修改组件代码后,自动刷新实时预览修改后的效果。

CommonsChunkPlugin: 对于有多个入口文件的, 可以抽取公共的模块,最终合成的文件能够在最开始的时候加载一次,便存起来到缓存中供后续使用。

DefinePlugin: 允许你创建一个在编译时可以配置的全局常量。这可能会对开发模式和发布模式的构建允许不同的行为非常有用。

ExtractTextWebpackPlugin: 它会将打包在js代码中的样式文件抽离出来, 放到一个多带带的 css 包文件 (styles.css)当中, 这样js代码就可以和css并行加载.

UglifyjsWebpackPlugin: 这个插件使用 UglifyJS 去压缩你的JavaScript代码。

webpack构建流程

从启动webpack构建到输出结果经历了一系列过程,它们是:

解析webpack配置参数,合并从shell传入和webpack.config.js文件里配置的参数,生产最后的配置结果。

注册所有配置的插件,让插件监听webpack构建生命周期的事件节点,以做出对应的反应。

从配置的entry入口文件开始解析文件构建依赖图谱,找出每个文件所依赖的文件,递归下去。

在解析文件递归的过程中根据文件类型和loader配置找出合适的loader用来对文件进行转换。

递归完后得到每个文件的最终结果,根据entry配置生成代码块chunk

输出所有chunk到文件系统。

代码拆分(Code Splitting)

代码拆分是 webpack 中最引人注目的特性之一。你可以把代码分离到不同的 bundle 中,然后就可以去按需加载这些文件.

分离资源,实现缓存资源

分离第三方库(vendor) CommonsChunkPlugin

分离 CSS

传统的模块打包工具(module bundlers)最终将所有的模块编译生成一个庞大的bundle.js文件。因此Webpack使用许多特性来分割代码然后生成多个“bundle”文件,而且异步加载部分代码以实现按需加载

使用 require.ensure() 按需分离代码

require.ensure(dependencies: String[], callback: function(require), chunkName: String)

模块热替换(Hot Module Replacement)

模块热替换功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载页面。这使得你可以在独立模块变更后,无需刷新整个页面,就可以更新这些模块.

webpack-dev-server 支持热模式,在试图重新加载整个页面之前,热模式会尝试使用 HMR 来更新。

webpack-dev-server 主要是启动了一个使用 express 的 Http服务器 。它的作用 主要是用来伺服资源文件 。此外这个 Http服务器 和 client 使用了 websocket 通讯协议,原始文件作出改动后, webpack-dev-server 会实时的编译,但是最后的编译的文件并没有输出到目标文件夹, 实时编译后的文件都保存到了内存当中。

"server": "webpack-dev-server --inline --progress --hot",

webpack-dev-server 支持2种自动刷新的方式:

Iframe mode

Iframe mode 是在网页中嵌入了一个 iframe ,将我们自己的应用注入到这个 iframe 当中去,因此每次你修改的文件后,都是这个 iframe 进行了 reload 。

inline mode

而 Inline-mode ,是 webpack-dev-server 会在你的 webpack.config.js 的入口配置文件中再添加一个入口,

module.exports = {
        entry: {
            app: [
                "webpack-dev-server/client?http://localhost:8080/",
                "./src/js/index.js"
            ]
        },
        output: {
            path: "./dist/js",
            filename: "bundle.js"
        }
    }

这样就完成了将 inlinedJS 打包进 bundle.js 里的功能,同时 inlinedJS 里面也包含了 socket.ioclient 代码,可以和 webpack-dev-server 进行 websocket 通讯。

其他配置选项

--hot 开启 Hot Module Replacement功能

--quiet 控制台中不输出打包的信息

--compress 开启gzip压缩

--progress 显示打包的进度

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90329.html

相关文章

  • webpack+babel+react练习流程记录

    摘要:简介来构建用户界面的库,不是框架关注于层虚拟单向数据流这些概念如何使用下载文件也可以使用,需要用到的模块介绍是编写组件的一种语法规范,可以看为是的扩展,它支持将和混写在一起,最后使用编译为常规的,方便浏览器解析编写第一个例子使用编写组件 react简介 来构建用户界面的库,不是框架 关注于view层 虚拟DOM 单向数据流 JSX这些概念 如何使用react 下载文件 rea...

    DDreach 评论0 收藏0
  • webpack系列之loader的基本使用

    摘要:由于本篇我们只讲的基本使用,故这里不再深入讲解,有兴趣的可以点击这里学习。使用的方式有三种使用方式,如下配置推荐在文件中指定。下一篇会给大家介绍系列之及简单的使用 欢迎大家访问我的github blog查看更多文章 webpack系列之loader及简单的使用 一. loader有什么用 webpack本身只能打包Javascript文件,对于其他资源例如 css,图片,或者其他的语...

    xiaoxiaozi 评论0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件开发前端掘金作者原文地址译者插件是为应用添加全局功能的一种强大而且简单的方式。提供了与使用掌控异步前端掘金教你使用在行代码内优雅的实现文件分片断点续传。 Vue.js 插件开发 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins译者:jeneser Vue.js插件是为应用添加全局功能的一种强大而且简单的方式。插....

    izhuhaodev 评论0 收藏0
  • webpack走在前端技术的前沿(深入浅出)

    摘要:我们也可以不用在命令行里面输入,因为我们可能以后会查询更多东西,因此我们可以,在的里面加入这里的和只是为了输出进度条和,没有实际意义,然后在命令行输入就可以默认使用进行打包了。更具体的就请查看一下官方文档了,毕竟篇幅不能太长。 Webpack 网上有很多webpack的介绍,也有不少的视频,但是不少人看到应该还是不是很了解webpack里面到底是讲什么,而且报错了之后也是不知所措 那么...

    jayce 评论0 收藏0
  • webpack走在前端技术的前沿(深入浅出)

    摘要:我们也可以不用在命令行里面输入,因为我们可能以后会查询更多东西,因此我们可以,在的里面加入这里的和只是为了输出进度条和,没有实际意义,然后在命令行输入就可以默认使用进行打包了。更具体的就请查看一下官方文档了,毕竟篇幅不能太长。 Webpack 网上有很多webpack的介绍,也有不少的视频,但是不少人看到应该还是不是很了解webpack里面到底是讲什么,而且报错了之后也是不知所措 那么...

    _ang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<