Webpack使用基础介绍
参考文章:
https://www.cnblogs.com/eyunhua/tag/webpack/
http://wiki.jikexueyuan.com/project/webpack-handbook/
https://www.cnblogs.com/zuozuo-blog/category/966596.html
0.前言
模块系统的演进
1.<script>标签
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>
这是最原始的 JavaScript 文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在 window 对象中,不同模块的接口调用都是一个作用域中,一些复杂的框架,会使用命名空间的概念来组织这些模块的接口,典型的例子如 YUI 库。
这种原始的加载方式暴露了一些显而易见的弊端:
- 全局作用域下容易造成变量冲突
- 文件只能按照
<script>
的书写顺序进行加载 - 开发人员必须主观解决模块和代码库的依赖关系
- 在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪
2.CommonJS
服务器端的 Node.js 遵循 CommonJS规范,该规范的核心思想是允许模块通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或 module.exports 来导出需要暴露的接口。
require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;
优点:
- 服务端模块便于重用
- NPM中已经由将近20万个可以使用模块包
- 简单并容易使用
缺点:
- 同步的模块加载方式不适合在浏览器环境中,同步意味者阻塞加载,浏览器资源是异步加载的
- 不能非阻塞的并行加载多个模块
实现:
- 服务器端的 Node.js
- Browserify,浏览器端的 CommonJS 实现,可以使用 NPM 的模块,但是编译打包后的文件体积可能很大
- modules-webmake,类似Browserify,还不如 Browserify 灵活
- wreq,Browserify 的前身
3.AMD
Asynchronous Module Definition 规范其实只有一个主要接口 define(id?, dependencies?, factory),它要在声明模块的时候指定所有的依赖 dependencies,并且还要当做形参传到 factory 中,对于依赖的模块提前执行,依赖前置。
define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });
优点:
适合在浏览器环境中异步加载模块
可以并行加载多个模块
缺点:
提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不顺畅
不符合通用的模块化思维方式,是一种妥协的实现
实现:
RequireJS
curl
4.CMD
Common Module Definition 规范和 AMD 很相似,尽量保持简单,并与 CommonJS 和 Node.js 的 Modules 规范保持了很大的兼容性。
define(function(require, exports, module) {
var $ = require('jquery');
var Spinning = require('./spinning');
exports.doSomething = ...
module.exports = ...
})
优点:
依赖就近,延迟执行
可以很容易在 Node.js 中运行
缺点:
依赖 SPM 打包,模块的加载逻辑偏重
实现:
Sea.js
coolie
5.UMD
Universal Module Definition 规范类似于兼容 CommonJS 和 AMD 的语法糖,是模块定义的跨平台解决方案。
6.ES6模块
EcmaScript6 标准增加了 JavaScript 语言层面的模块体系定义。ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。
import "jquery";
export function doStuff() {}
module "localModule" {}
优点:
容易进行静态分析
面向未来的 EcmaScript 标准
缺点:
原生浏览器端还没有实现该标准
全新的命令字,新版的 Node.js才支持
实现:
Babel
期待的模块系统
可以兼容多种模块风格,尽量可以利用已有的代码,不仅仅只是 JavaScript 模块化,还有 CSS、图片、字体等资源也需要模块化。
模块的加载和传输,我们首先能想到两种极端的方式,一种是每个模块文件都单独请求,另一种是把所有模块打包成一个文件然后只请求一次。显而易见,每个模块都发起单独的请求造成了请求次数过多,导致应用启动速度慢;一次请求加载所有模块导致流量浪费、初始化过程慢。这两种方式都不是好的解决方案,它们过于简单粗暴。
分块传输:按需进行懒加载,在实际用到某些模块的时候再增量更新,才是较为合理的模块加载方案。要实现模块的按需加载,就需要一个对整个代码库中的模块进行静态分析、编译打包的过程。
所有资源都是模块
在上面的分析过程中,我们提到的模块仅仅是指JavaScript模块文件。然而,在前端开发过程中还涉及到样式、图片、字体、HTML 模板等等众多的资源。这些资源还会以各种方言的形式存在,比如 coffeescript、 less、 sass、众多的模板库、多语言系统(i18n)等等。
如果他们都可以视作模块,并且都可以通过require的方式来加载,将带来优雅的开发体验,比如:
require("./style.css");
require("./style.less");
require("./template.jade");
require("./image.png");
那么如何做到让 require 能加载各种资源呢?
静态分析
在编译的时候,要对整个代码进行静态分析,分析出各个模块的类型和它们依赖关系,然后将不同类型的模块提交给适配的加载器来处理。比如一个用 LESS 写的样式模块,可以先用 LESS 加载器将它转成一个CSS 模块,在通过 CSS 模块把他插入到页面的
总结:分块加载或者按需加载,就是需要将JavaScript、样式、图片、字体、HTML模板等等视作模块,因此我们我们就需要对整个代码进行静态分析,分析出各个模块的类型和它们的依赖关系,然后将不同类型的模块提交给适配的加载器来处理,Webpack就是在这样的需求者中应运而生的。
什么是Webpack?
Webpack 是一个模块打包器。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。
为什么重复造轮子
市面上已经存在的模块管理和打包工具并不适合大型的项目,尤其单页面 Web 应用程序。最紧迫的原因是如何在一个大规模的代码库中,维护各种模块资源的分割和存放,维护它们之间的依赖关系,并且无缝的将它们整合到一起生成适合浏览器端请求加载的静态资源。
这些已有的模块化工具并不能很好的完成如下的目标:
- 将依赖树拆分成按需加载的块
- 初始化加载的耗时尽量少
- 各种静态资源都可以视作模块
- 将第三方库整合成模块的能力
- 可以自定义打包逻辑的能力
- 适合大项目,无论是单页还是多页的 Web 应用
Webpack的特定
1.代码拆分
Webpack 有两种组织模块依赖的方式,同步和异步。异步依赖作为分割点,形成一个新的块。在优化了依赖树后,每一个异步区块都作为一个文件被打包。
2.Loader
Webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成 JavaScript 模块。这样,任何资源都可以成为 Webpack 可以处理的模块。
3.智能解析
Webpack 有一个智能解析器,几乎可以处理任何第三方库,无论它们的模块形式是 CommonJS、 AMD 还是普通的 JS 文件。甚至在加载依赖的时候,允许使用动态表达式 require("./templates/" + name + ".jade")
。
4.插件系统
Webpack 还有一个功能丰富的插件系统。大多数内容功能都是基于这个插件系统运行的,还可以开发和使用开源的 Webpack 插件,来满足各式各样的需求。
5.快速运行
Webpack 使用异步 I/O 和多级缓存提高运行效率,这使得 Webpack 能够以令人难以置信的速度快速增量编译。
1.webpack安装、创建项目
1.安装nodejs
node自带npm。
node -v
检查node版本。
npm -v
检查npm版本。
2.npm安装webpack
npm install webpack -g
webpack -v
查看webpack的版本号。
3.进入项目目录,输入npm init,生成package.json文件
4.输入命令npm install webpack —save-dev 为项目添加webpack依赖
5.webpack使用示例
webpack hello.js hello.bundle.js
运行命令:webpack hello.js hello.bundle.js,将hello.js编译并打包到hello.bundle.js
Webpack 会分析入口文件,解析包含依赖关系的各个文件。这些文件(模块)都打包到 bundle.js 。Webpack 会给每个模块分配一个唯一的 id 并通过这个 id 索引和访问模块.
2.loader的使用
Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。
Loader 可以理解为是模块和资源的转换器,它本身是一个函数,接受源文件作为参数,返回转换的结果。这样,我们就可以通过 require 来加载任何类型的模块或文件,比如 CoffeeScript、 JSX、 LESS 或图片。
Loader 可以在 require() 引用模块的时候添加,也可以在 webpack 全局配置中进行绑定,还可以通过命令行的方式使用。
示例
1.输入命令:npm install css-loader style-loader —save-dev,来安装css的loader转换器和style的loader转换器
2.在 require() 引用模块的时候添加loader转换,require('style-loader!css-loader!./style.css');
3.输入命令:webpack hello.js hello.bundle.js,进行编译hello.js
发现style.css中的样式被使用style标签插入到了head里面,这是由style-loader实现的,style-loader是将webpack识别完的css文件中的内容,在编译完运行文件的时候,将这些css用style标签包起来嵌在head内.
css-loader是允许webpack识别.css的文件.
在命令行中添加loader
在命令行中输入命令:webpack hello.js hello.bundle.js —module-bind ‘css=style-loader!css-loader’(git bash中执行相当于linux,如在windows下的cmd估计要将单引号换成双引号)。
3.webpack.config.js配置文件使用
loader的三种用法:
- require()
- 在命令行中配置
- 在配置文件webpack.config.js中通过module.loaders进行配置
Webpack 在执行的时候,除了在命令行传入参数,还可以通过指定的配置文件来执行。默认情况下,会搜索当前目录的 webpack.config.js 文件,这个文件是一个 node.js 模块,返回一个 json 格式的配置信息对象,或者通过 —config 选项来指定配置文件。
module.exports = {
entry:'./src/script/hello.js',
output:{
path:'./dist/js',
filename:'hello.boudle.js'
}
}
输入命令:webpack
,即可按照webpack.config.js中的配置项进行编译.
如果将webpack.config.js重命名为webpack.dev.config.js,则直接执行默认的webpack命令则会找不到相应的配置文件,需要借助于webpack的–config选项来指定配置文件
命令:webpack --config webpack.dev.config.js
如果要查看编译的进度,打包的模块之类的,可以在package.json中的scripts标签内通过webpack的属性值来指定
{
"script":{
"webpack":"webpack --config webpack.dev.config.js --progress --display-modules --display-reasons --colors "
}
}
输入命令:npm run webpack
,来编译打包。
4.自动化生成项目中的html页面
1.安装html-webpack-plugin插件,输入命令:npm install html-webpack-plugin --save-dev
2.在webpack.config.js文件中,引入html-webpack-plugin插件
var htmlWebpackPlugin = require('html-webpack-plugin'); //引入html-webpack-plugin插件
module.exports = {
entry:{
hello:'./src/script/hello.js',
world:'./src/script/world.js'
},
output:{
path:'./dist/js',
filename:'[name]-[hash].js'
},
plugins:[
new htmlWebpackPlugin({
template:'src/index.html', //模板.
filename:'index-[hash].html', //编译后的文件名
inject:'head' //想把脚本文件放在那个标签内,head或者body
})
]
}
3.输入命令:npm run webpack,编译打包
进一步详细介绍请看上面链接
还没有评论,来说两句吧...