webpack快速掌握教程

转载http://yijiebuyi.com/blog/46fb97b11fb8f4055e0b04d1cecb1f69.htmljavascript

#为何用webpackcss

若是咱们 前端 javascript 能像 node.js 同样 require 去引用一个依赖包,那么前端的世界就不会像如今这么乱html

如今为何乱?前端


假设: a.js 依赖 b.js b.js 依赖 c.js c.js 依赖 d.jsjava


若是在咱们前端去引用这些依赖的时候,每每是这样的:node

<script src='a.js'></script>
<script src='b.js'></script>
<script src='c.js'></script>
<script src='d.js'></script>

上面的引用方式形成一个问题webpack

不乱你进入哪一个页面,这些js 都要去加载…形成没必要要的浪费es6

下面咱们来介绍 webpackweb

CommonJs与AMD

在一开始,咱们先讲一下它和以往咱们所用的模块管理工具备什么不同。在最开始的阶段,Js并无这些模块机制,各类Js处处飞,得不到有效妥善的管理。后来前端圈开始制定规范,最耳熟能详的是CommonJs和AMD。正则表达式

CommonJs是应用在NodeJs,是一种同步的模块机制。它的写法大体以下:

var firstModule = require("firstModule");

//your code...

module.export = anotherModule

AMD的应用场景则是浏览器,异步加载的模块机制。require.js的写法大体以下:

define(['firstModule'], function(module){
   
   //your code...
   return anotherModule
})

其实咱们单比较写法,就知道CommonJs是更为优秀的。它是一种同步的写法,对Human友好,并且代码也不会繁琐臃肿。但更重要的缘由是,随着npm成为主流的JavaScript组件发布平台,愈来愈多的前端项目也依赖于npm上的项目,或者自身就会发布到npm平台。因此咱们对如何可使用npm包中的模块是咱们的一大需求。因此browserify工具就出现了,它支持咱们直接使用require()的同步语法去加载npm模块。

固然咱们这里不得不说的是,ES2015(ES6)里也有了本身的模块机制,也就是说ES6的模块机制是官方规定的,咱们经过babel(一种6to5的编译器)可使用比较多的新特性了,包括咱们提到的模块机制,而它的写法大体以下:

import {someModule} from "someModule";

// your codes...

export anotherModule;

固然上面的写法只是最基本的,还有其余的不一样加载模块的写法,能够看一下阮一峰老师的ECMAScript 6 入门或者babel的相关文档Learn ES2015。

功能特性

browserify的出现很是棒,但webpack更胜一筹!

咱们来看看webpack支持哪些功能特性:

  • 支持CommonJs和AMD模块,意思也就是咱们基本能够无痛迁移旧项目。
  • 支持模块加载器和插件机制,可对模块灵活定制。特别是我最爱的babel-loader,有效支持ES6。
  • 能够经过配置,打包成多个文件。有效利用浏览器的缓存功能提高性能。
  • 将样式文件和图片等静态资源也可视为模块进行打包。配合loader加载器,能够支持sass,less等CSS预处理器。
  • 内置有source map,即便打包在一块儿依旧方便调试。
  • 看完上面这些,能够想象它就是一个前端工具,可让咱们进行各类模块加载,预处理后,再打包。以前咱们对这些的处理是放在grunt或gulp等前端自动化工具中。有了webpack,咱们无需借助自动化工具对模块进行各类处理,让咱们工具的任务分的更加清晰。

咱们看一下官方对webpack理解的图。 webpack.jpg

任何静态资源均可以视做模块,而后模块之间也能够相互依赖,经过webpack对模块进行处理后,能够打包成咱们想要的静态资源。

既然已经大体知道为何咱们要使用webpack了,咱们接下来就开始使用webpack吧!

#开始使用webpack

首先新建一个webpack101的项目,咱们将在webpack101这里开展咱们接下来的各项学习。

$ npm init // 用于初始化项目的package.json

//初始化文件目录:
webpack101
     src
         entry.js
         module1.js
     index.html
     package.json
     webpack.config.js

安装webpack

咱们经过npm来将webpack安装到全局

$ npm install webpack -g

webpack配置

webpack是须要进行配置的,咱们在使用webpack的时候,会默认webpack.config.js为咱们的配置文件。因此接下来,咱们新建这个js文件。

// webpack.config.js
var path = require("path");

module.exports = {
    entry: '../src/entry.js', //演示单入口文件
    output: {
        path: path.join(__dirname, 'out'),  //打包输出的路径
        filename: 'bundle.js',              //打包后的名字
        publicPath: "./out/"                //html引用路径,在这里是本地地址。
    }
};

编写入口文件

接下来就编写咱们的入口文件entry.js和第一个模块文件module1.js。咱们一切从简,里面只用来加载一个Js模块

// entry.js
require("./module1"); // 使用CommonJs来加载模块

下一个文件

// module1.js
console.log("Hello Webpack!");

启动webpack

一切准备好后,咱们仅须要在项目根目录下,用命令行webpack执行一下便可

// webpack 命令行的几种基本命令

$ webpack // 最基本的启动webpack方法
$ webpack -w // 提供watch方法,实时进行打包更新
$ webpack -p // 对打包后的文件进行压缩,提供production
$ webpack -d // 提供source map,方便调试。

webpack成功运行后,咱们就能够看到根目录出现了out文件夹,里面有咱们打包生成的bundle.js。咱们最后经过在index.html里对这个文件引入就能够了。咱们能够在控制台看到咱们想要的结果,Hello Webpack !

多模块依赖

刚才的例子,咱们仅仅是跑通了webpack经过entry.js入口文件进行打包的例子。下面咱们就来看一下它是否真的支持CommonJs和AMD两种模块机制呢?下面咱们新建多几个js文件吧!

// 修改module1.js
require(["./module3"], function(){
    console.log("Hello Webpack!");
});

下一个文件

// module2.js,使用的是CommonJs机制导出包
module.exports = function(a, b){
    return a + b;
}

下一个文件

// module3.js,使用AMD模块机制
define(['./module2.js'], function(sum){
    return console.log("1 + 2 = " + sum(1, 2));
})

其实像上面这样混用两种不一样机制很是很差,这里仅仅是展现用的,在开发新项目时仍是推荐CommonJs或ES2015的Module。固然我我的更倾向于ES2015的模块机制的~

loader加载器

到了我最喜欢也是最激动人心的功能了!咱们先想一想应用场景,前端社区有许多预处理器供咱们使用。咱们可使用这些预处理器作一些强大的事情,你们都听过的就是CoffeeScript和Sass了。咱们之前要编译这些预处理器,就是用gulp进行编译。可是咱们对这些文件处理其实也挺繁琐的,webpack能够一次性解决!

在这里咱们用Sass和babel编译ES2015为例子,看一下loader是如何使用的

安装loader

咱们第一步就是先要安装好各个必须的loader,咱们直接看看须要经过npm安装什么

$ npm install style-loader css-loader url-loader babel-loader sass-loader file-loader --save-dev

配置loader

安装完各个loader后,咱们就须要配置一下咱们的webpack.config.js,载入咱们的loader

// webpack.config.js
module.exports = {
    entry: path.join(__dirname, 'src/entry.js'),
    output: {
        path: path.join(__dirname, 'out'),
        publicPath: "./out/",
        filename: 'bundle.js'
    },
    // 新添加的module属性
    module: {
        loaders: [
            {test: /\.js$/, loader: "babel"},
            {test: /\.css$/, loader: "style!css"},
            {test: /\.(jpgpng)$/, loader: "url?limit=8192"},
            {test: /\.scss$/, loader: "style!css!sass"}
        ]
    }
};

咱们主要看看module的loaders。loaders是一个数组,里面的每个对象都用正则表达式,对应着一种配对方案。好比匹配到js后缀名就用babel-loader,匹配到scss后缀名的就先用sass,再用css,最后用style处理,不一样的处理器经过!分隔并串联起来。这里的loader是能够省略掉-loader这样的,也就是本来应该写成style-loader!css-loader!sass-loader,固然咱们必须惜字如金,因此都去掉后面的东东。

咱们仅仅是配置一下,已是能够直接用ES2015和SASS去写咱们的前端代码了。在此以前,咱们对src文件夹里再细分红js,css,image三个文件夹,处理好分层。话很少说,赶忙试试。

稍微复杂的webpack项目

bebel-loader

// js/es6-module.js
class People{
    constructor(name){
        this.name = name;
    }
    sayhi(){
        console.log(`hi ${this.name} !`);
    }
}
exports.module = People;

写好模块后,咱们直接在entry.js入口文件中引入该模块。

// entry.js

// javascript
require('./js/module1');
let People = require('./js/es6-module');
let p = new People("Yika");
p.sayHi();

// css
require('./css/main.scss');

哈,不能再爽!这下子咱们可使用不少优秀的ES6特性去构建大型的web了。

sass-loader

你们或许注意到了下方的css的require,那就是用来加载Sass样式的。咱们经过启动style-loader会将css代码转化到 style 标签内,咱们看一下里面的内容

// css/main.scss
html, body{
    background: #dfdfdf;
}

最后咱们打开index.html观察咱们全部的结果,首先背景已是淡灰色的,而且控制台也有咱们想要的内容。咱们经过查看DOM结构,能够发现head标签里多出了style标签,里面正是咱们想要定制的样式

关于对图片的打包


咱们以前也说,webpack对与静态资源来讲,也是看做模块来加载的。CSS咱们是已经看过了,那图片是怎么做为模块打包加载进来呢?这里咱们能够想到,图片咱们是用url-loader加载的。咱们在css文件里的url属性,其实就是一种封装处理过require操做。固然咱们还有一种方式就是直接对元素的src属性进行require赋值


div.img{
    background: url(../image/xxx.jpg)
}

//或者
var img = document.createElement("img");
img.src = require("../image/xxx.jpg");
document.body.appendChild(img);

上述两种方法都会对符合要求的图片进行处理。而要求就是在url-loader后面经过query参数的方式实现的,这里就是说只有不大于8kb的图片才会打包处理成Base64的图片。关于query,请看文档:Query parameters

{test: /\.(jpgpng)$/, loader: "url?limit=8192"}

打包成多个资源文件

咱们在开发多页面的站点的时候,仍是须要但愿能有多个资源文件的。这样咱们就能够有效利用缓存提高性能,作到文件按需加载。如何写入口文件,这里就再也不赘述了,咱们直接看如何对webpack.config.js进行修改

// webpack.config.js

entry: {
    page1: "entry.js",
    page2: "entry2.js"
},
output: {
    path: path.join(__dirname, 'out'),
    publicPath: "./out/",
    filename: '[name].js'
}

这里重点关注两个地方,entry属性能够是一个对象,而对象名也就是key会做为下面output的filename属性的[name]。固然entry也能够是一个数组,更多用法均可以去webpack的官方文档进行查看。

固然webpack也考虑到公共模块的利用,咱们利用插件就能够智能提取公共部分,以提供咱们浏览器的缓存复用。咱们只须要在webpack.config.js添加下面的代码便可

// 修改添加,webpack.config.js
var webpack = require('webpack');
module.exports = {
    // ....省略各类代码
        plugins: [
            new webpack.optimize.CommonsChunkPlugin('common.js')
        ]
}

咱们作个小测试,让第二个入口文件也加载咱们以前的es6-module.js。而后咱们用webpack进行打包,就发现生成的common.js里是有相应代码的。咱们须要手动在html上去加载common.js,而且是必需要最早加载

独立出css样式

若是咱们但愿样式经过 link 引入,而不是放在 style 标签内呢,即便这样作会多一个请求。这个时候咱们就要配合插件一块儿使用啦,咱们一块儿来看看

$ npm install extract-text-webpack-plugin --save-dev

安装完插件就要配置webpack.config.js了。咱们添加如下代码

var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
    // ...省略各类代码
    module: {
        loaders: [
            {test: /\.js$/, loader: "babel"},
            {test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader")},
            {test: /\.(jpgpngsvg)$/, loader: "url?limit=8192"},
            {test: /\.scss$/, loader: "style!css!sass"}
        ]
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin('common.js'),
        new ExtractTextPlugin("[name].css")
    ]
}

为了区分开用<link>连接和用 style ,咱们这里以CSS后缀结尾的模块用插件。咱们重点关注一下使用了ExtractTextPlugin的模块,在ExtractTextPlugin的extract方法有两个参数,第一个参数是通过编译后经过style-loader单独提取出文件来,而第二个参数就是用来编译代码的loader

固然,插件也支持全部独立样式打包成一个css文件。增长多一个参数便可

new ExtractTextPlugin("style.css", {allChunks: true})

至于怎样加载样式是最佳实践,这个就要本身平时多思考了。多站点多样式的时候,是作到一次性打包加载呢,仍是按需加载呢?我这里就建议一项,主页尽可能作到最精简,毕竟决定用户存留时间

总结

前端社区不断发展,愈来愈趋向于组件化的发展。经过webpack,咱们就能体验到one component one module的开发感受。固然如何更好的使用webpack仍是要经过不断的思考总结,才能找到最优的方案web

 


 

模块化 JavaScript

若是我想用 ES6 的方式引入某个 es6 模块,好比:

import $ from 'whatever';
怎么办?浏览器目前还不提供原生支持,webpack 原生也仅支持 CommonJS 的那种写法,但借助 babel-loader ,咱们能够加载 es6 模块:

安装 babel-loader

npm install babel-loader babel-core babel-preset-es2015 --save-dev
配置 webpack.config.js

在 module.exports 值中添加 module:

module.exports = {
entry: {
app: ['./main.js']
},
output: {
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.js$/,
loaders: ['babel?presets[]=es2015'],
exclude: /node_modules/
}]
}
}
这样咱们就能够在咱们的 js 文件中使用 ES6 语法,babel-loader 负责翻译。

上面的方法,是在 webpack.config.js 文件中给某一类型文件定义加载器,咱们还能够在代码中直接指定:

import $ from 'babel!whatever'
固然,前一种方法会更优雅。

 

更多资料: 易懂的 webpack 使用教程  https://juejin.im/entry/574fe7c579bc440052f6d805