前言

在学习 Webpack 之前,我们需要了解一个概念:模块

何为模块?

如果你曾学过 Java , C# 之类的语言,一定会知道 Java 中的 import 或 C# 中的 using 吧?

比如:我想在 C# 中进行数据库操作,我只需要在代码头部加上 下面这两段代码即可。

using System.Data;
using System.Data.SqlClient;

这两段代码可以看成 两个与数据库操作相关的模块。
当我们需求是数据库,或者是读取 IO 等其他操作,我们便加载其他不同的模块。

很明显,这实现了编程中的一个非常重要的功能 按需加载

在前端中 模块又该如何定义呢?
按照我个人的理解:

  • 在 HTML 中 模块 便是一个组件

    <div class="layer">
    <div><%= name %></div>
    <% for(var i = 0; i < People.length;++i) { %>
    <%= People[i] %>
    <% } %>
    </div>
  • 在 CSS 中 模块 便是一个局部样式

    header{
    display:block;
    }
    header h1{
    font-size: 60px;
    }
  • 在 Javascript 中 模块 便是一个封装着方法或数据的脚本文件

    let People = { name: "Simon" } ;
    module.exports = People;

而我们又该怎样实现 在前端中加载模块呢?

下面是两个很常见的例子:

在 Less 中

@import "header";
@import "layout";
@import "footer";

在 Javascript

// CommonJS
const $ = require("jQuery"); //es6
let People = { name: "Simon" } ;
module.exports = People; import "./layer.less";
import tpl from "./layer.ejs";

如果你直接运行以上代码,浏览器并不会解析,这个时候,就要依靠 Webpack 了!

Webpack是什么

Webpack 是一款目前非常流行的前端模块打包工具,可以将项目中所加载的模块进行打包,以及将 一些浏览器不支持的语言进行转换。

Webpack 的打包原理是 先找到入口文件,递归探索出所有依赖的模块,最后 利用 Loader 进行不同文件类型的处理,打包成一个 Javascript 文件。

其中,Webpack 的两个最核心原理分别是:

  1. 一切皆模块
  2. 按需加载

当然 Webpack 的作用不止加载模块这么简单,前端的常用需求通常都可以实现:利用 Loader 转换 es6 、 Less 、 Typescript ,还可利用插件 开发多页面应用,等等诸多强大功能。

正文

下面,我将讲解 Webpack 的具体使用和配置。

安装

我一般在项目中使用 Webpack,都是先执行下面这四条命令进行 Webpack 的安装

  1. npm install -g webpack

    在全局安装 Webpack,第一次使用时 执行

  2. npm install --save-dev webpack

    将 Webpack 安装到你的项目

  3. npm init

    npm初始化,会询问你的项目信息,可以回车跳过

  4. npm install --save-dev webpack-dev-server

    在当前项目,安装 Webpack 服务器

安装完成后,便是建立配置文件了。

基本配置

在项目根目录下新建名为 webpack.config.js 的文件,

基本上 一个配置文件的大体结构就是下面这样:

modules.export={
entry:{
/* 入口文件 */
},
output:{
/* 出口文件 */
},
module:{
/* Loader */
rules:[{},{},{}]
},
plugins:[
/* 插件 */
],
devtool: ...
devServer: {...}
resolve:{...}
}

我们下面就先分析 modules.export 各个属性

入口

entry
代表是入口文件,Webpack 工作的开始。

Webpack 会递归的探索出 入口文件中所依赖的模块,并按照顺序 利用 Loader 进行处理。

官网给出了其 3 种数据类型:

  1. 字符串

    entry: "app.js";
  2. 数组

    数组中的每一项都会被打包,形成互不依赖的文件

    entry: ["app.js","main.js"];
  3. 对象

    对象中的每一个属性都会被打包,形成互不依赖的文件

    entry:{
    app: "./src/js/app.js",
    main: "./src/js/main.js"
    }

    一般入口文件中多是 import 或者 require 等模块导入命令。

出口

output
顾名思义,Webpack打包后文件的具体配置
常用的属性有 4 个

  1. path: ${__dirname }/dist

    打包后文件所在路径

  2. filename: "js/[name].js"

    打包后文件的名字,这里有 4 种常用的写法

    1. 自定义
    2. [name].js

      代表的便是入口的文件名

    3. [hash].js

      此次打包后的hash值

    4. [chunkhash]

      该块打包后的hash值

  3. publicPath: "http://cdn.com/"

    上线时的公共路径,主要应用于线上

  4. chunkFilename: 'js/[name].js'

    按需加载模块时输出的文件名称

Loader

Loader 是 Webpack 中最振奋人心的东西了!

将一切浏览器不支持的语言,处理成 浏览器可以支持。
针对各个文件类型,都有各种的 Loader 等你去挖掘。

Loader 的工作方式 是从右向左执行,链式地按照顺序进行编译。
loader 链中的第一个返回值给下一个 loader,在最后一个 loader,返回所预期的结果。

loader 可以是同步或异步函数,也可使用 options 对象去接受配置参数。

基础结构

module:{
rules:[
{
test:/\.xxx$/,//以xxx结尾的文件
loader: "xxx-loader",
exclude: {排除的路径},
include: {包含的路径},
options: {Loader配置}
}
]
}

可以很清楚的看到,Loader 利用 test 的正则 找到各个类型文件,然后使用 loader 进行处理,便可转换成浏览器支持的文件。

其中我知道的 loader 的写法有两种:

  1. 每一个 loader 都是一个对象

    loaders:[
    {loader:"style-loader"},
    { loader: "css-loader?modules", options: { importLoaders: 1 } },
    {loader: "less-loader"}
    ]
  2. 使用 ! 号拼接的写法

    loader: "style-loader!css-loader?importLoaders=1!less-loader"

    下面介绍三个 前端必备的 Loader 方式

    css

  3. style-loader

    通过注入<style>标签将 CSS 添加到 DOM

    npm install style-loader --save-dev
  4. css-loader

    css-loader像import / require()一样解释@import和url()并解析它们。

    npm install css-loader --save-dev
  5. postcss-loader

    补充 不兼容的css属性 的浏览器前缀

    npm install post-loader --save-dev
  6. less-loader

    将Less 转换成 CSS

    npm install less --save-dev
    npm install less-loader --save-dev

javascript

babel

主要用于将 es6 转换成 es2015
npm install --save-dev babel-core babel-loader babel-preset-es2015

图片 & 字体

  1. file-loader

    用于压缩文件

    npm install --save-dev file-loader
  2. url-loader

    如果文件下于 规定限制,将会转换成 二进制编码

    npm install --save-dev url-loader

    ejs

    另外 我想介绍一下 自己常用的 ejs-loader

  3. 配置

    npm install --save-dev ejs-loader
    test:/\.ejs$/ , loader:"ejs-loader",
  4. 使用

<div class="layer">
<div><%= name %></div>
<% for(let i = 0; i < Array.length;++i) { %>
<%= Array[i] %>
<% } %>
</div>
//入口文件
import tpl from "./layer.ejs"; document.body.innerHTML = tpl({
name:"Simon",
arr:["Apple","Xiaomi"]
});

运行 生成后的页面 ,便会发现 ejs 组件已经被加进去了,
想象一下,我们在平时工作中是否可以把 一个轮播图,或者 排行榜 、评论 当成一个组件呢?

插件

plugins

在日常工作中,我们使用 Loader 处理不同类型的文件,当有某种其他方面的需求时,比如 抽离 CSS 、生成多页面 HTML ,plugins 便派上了用场。

插件的使用,一般都要先 require 出来,然后在 plugins 属性中 进行初始化

const htmlWebpackPlugin = require("html-webpack-plugin");
......
plugins: [ new htmlWebpackPlugin({/* options */}) ]

下面将介绍 一些工作中常用的插件

  1. clean-webpack-plugin

    主要用于 打包之前 先清空 打包目录下的文件,防止文件混乱。

    npm install --save-dev clean-webpack-plugin 
  2. html-webpack-plugin

    主要用于生成HTML,可以规定 模板HTML,也可以为 模板传入参数,压缩文件等

    npm install --save-dev html-webpack-plugin 

    这个插件可谓是 前端必备的,它的配置有很多
    ```jsx

new htmlWebpackPlugin({
//打包后的文件名
filename: "index.html",

//模板
template: "index.html",

//为true自动生成script标签添加到html中
//或者写 body/head 标签名
inject: false,//js的注入标签

//通过<%= htmlWebpackPlugin.options.title %>引用
title: "参数title",

//通过<%= htmlWebpackPlugin.options.date %> 引用
date: new Date()

//网站的图标
favicon: 'path/to/yourfile.ico'

//生成此次打包的hash
//如果文件名中有哈希,便代表有 合理的缓冲
hash: true,

//排除的块
excludeChunks: [''],

//选中的块 与入口文件相关
chunks: ['app','people'],

//压缩
minify:{
removeComments: true,collapseWhitespace: true,
minifyJS: true, minifyCSS: true,minifyURLs: true,
}

}),
那么问题来了,我们在模板文件中 又该怎样使用参数呢? 直接按照 ejs 的语法写入 html 文件即可!html

<%= htmlWeb
packPlugin.options.date %>

```

生成后的模板文件

<!DOCTYPE html>
<html lang="en">
Thu Dec 07 2017 10:01:58 GMT+0800 (中国标准时间)
</html>

另外,如果想生成 多页面应用,只需 将上面的配置,多复制几遍即可。

new htmlWebpackPlugin({ filename: "index1.html", }
new htmlWebpackPlugin({ filename: "index2.html", }
new htmlWebpackPlugin({ filename: "index3.html", }
  1. UglifyJsPlugin

    主要用于压缩 Javascript 文件

    npm i -D uglifyjs-webpack-plugin
  2. webpack.ProvidePlugin

    自动加载模块,全局使用变量,下面借助 官网的DEMO

    new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery'
    })
    // in a module
    $('#item'); // <= 起作用
    jQuery('#item'); // <= 起作用
    // $ 自动被设置为 "jquery" 输出的内容
  3. open-browser-webpack-plugin

    打开服务器后 会自动打开浏览器端口,用起来 很方便

  4. HotModuleReplacementPlugin

    热更新插件

常用命令

  • webpack

    最基本的启动webpack命令

  • webpack -w

    监控代码变化,实时进行打包更新

  • webpack -p

    对打包后的文件进行压缩,利用线上发布

  • webpack -d

    提供SourceMaps,方便调试代码

  • webpack --colors

    输出结果带彩色,可以更详细的查看信息

  • webpack --profile

    输出性能数据,可以看到每一步的耗时

devtool

不知道你现在时候有没有一个想法? webpack 打包后的文件就一定正确无误吗? 如果发生错误的话,该怎么办呢?

devtool 属性 便提供了生成 sourcemap 的功能,具体有下面这些选项。

  1. source-map

    此选项具有最完备的source map,但会减慢打包的速度;

  2. cheap-module-source-map

    生成一个不带列映射的map

  3. eval-source-map

    使用eval打包源文件模块,生成一个完整的source map。

  4. cheap-module-eval-source-map

    这是最快生成source map的方法,生成后的Source Map 会和打包后的 JavaScript 文件同行显示,但没有列映射,所以慎用

devServer

  1. contentBase: "./dist",

    本地服务器所加载的页面所在的目录

  2. historyApiFallback: true,

    再找不到文件的时候默认指向index.html

  3. inline: true,

    当源文件改变时会自动刷新页面

  4. hot: true,

    热加载开启

  5. port:8080

    设置默认监听端口

resolve

  1. extensions: [".js", ".html", ".css", ".txt","less","ejs","json"],

    自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名

  2. alias: { Temp: path.resolve(__dirname, "src/templates/") }

    模块别名定义,直接 require('AppStore') 即可,方便后续直接引用别名

其他功能

path

常用于字符串拼接路径。

const path = require("path");

有两个 API

  1. path.resolve()

将相对路径转换成绝对路径

const aPath = path.resolve("__dirname","js","main.js");
// aPath = 当前目录下的 js 文件夹的 main.js 文件的路径
  1. path.join()

对路径进行拼接

const rPath = path.join("source","js","main.js");
// aPath = //source/js/main.js
  1. __dirname
    Node.js 中的全局变量,代表的是 项目的当前路径。常与 path 结合使用。

热更新

上面我们已经提过了 webpack -w 命令,它可以实时的监控 代码的改变,从而自动进行打包,但是 有个缺点 在于它不能及时的刷新界面。

在我们 开启服务器后,是无法使用 此命令的,这个时候,如果你还想进行 自动打包,又想自动刷新界面,热更新 便是不二之选,另外 Webpack 只会热更新 发生改变的模块,不会重新加载整个页面,便可加快开发速度。

开启步骤:

  1. 修改 devServer属性

    devServer: {
    hot: true,//热加载开启
    inline: true,//文件改变时会自动刷新页面
    }
  2. 增加热更新插件
    ```jsx
    const webpack = require("webpack");
    //Other property
    plugins: [
    new webpack.HotModuleReplacementPlugin()]

```
另外,只有修改 依赖的项目,才会进行实时更新。

结束语

现在是一个 Web 技术蓬发的时代,一定要把握住时代潮流。

在写这篇文章前,我已经花了一整天的时间,把工作所需要 几乎所有的 Loader , plugins 收集了一遍,专门写了个源文件。但因为我的源文件太大 必须可显示,可隐藏,不然影响阅读 ,可博客园的 Markdown 不支持自定义样式 ,所以我贴在了我的博客,希望它能对你有帮助。

另外,再送你个福利,如果你是个人博客爱好者,我最近新开发了一款美观开源的主题,等待你的使用。

Webpack按需加载一切皆模块的更多相关文章

  1. Extjs4.1.x使用Application动态按需加载MVC各模块

    我们知道Extjs4之后提出了MVC模块开发,将以前肥厚的js文件拆分成小的js模块[model\view\controller\store\form\data等],通过controller拼接黏合, ...

  2. 记一次按需加载和npm模块发布实践

    按需加载 在使用 lodash 的时候我们可以使用这样的代码 //一 import {omit} from "lodash"; //二 import l from "lo ...

  3. Angular (SPA) WebPack模块化打包、按需加载解决方案完整实现

    文艺小说-?2F,言情小说-?3F,武侠小说-?9F long long ago time-1-1:A 使用工具,long long A ago time-1-2:A 使用分类工具,long long ...

  4. react-router配合webpack实现按需加载

    很久没有写博客了.一直感觉没有什么要写的,但是这个东西确实有必要的.使用react开发,不可能一直打包到一个文件.小项目肯定没有问题,但是变大一旦到几兆,这个问题就很严重.现在又Commonjs,AM ...

  5. webpack 代码拆分,按需加载

    转自:https://segmentfault.com/a/1190000007649417?utm_source=weekly&utm_medium=email&utm_campai ...

  6. webpack中利用require.ensure()实现按需加载

    webpack中的require.ensure()可以实现按需加载资源包括js,css等,它会给里面require的文件单独打包,不和主文件打包在一起,webpack会自动配置名字,如0.js,1.j ...

  7. 【webpack整理】一、安装、配置、按需加载

    如果你: 是前端热爱者 :) 有JavaScript/nodejs基础 会使用一些常用命令行,mkdir,cd,etc. 会使用npm 想对webpack有更深的认识,或许此时你恰好遇到关于webpa ...

  8. webpack中实现按需加载

    webpack中的require.ensure()可以实现按需加载资源包括js,css等,它会给里面require的文件单独打包,不和主文件打包在一起,webpack会自动配置名字,如0.js,1.j ...

  9. 深入浅出的webpack4构建工具---webpack+vue+router 按需加载页面(十五)

    1. 为什么需要按需加载? 对于vue单页应用来讲,我们常见的做法把页面上所有的代码都打包到一个bundle.js文件内,但是随着项目越来越大,文件越来越多的情况下,那么bundle.js文件也会越来 ...

随机推荐

  1. Java中public、private、protect对数据成员或成员函数的访问限制

    Java类中对数据成员.成员函数的访问限制修饰有:public.protect.private.friendly(包访问限制) public修饰的数据成员或成员函数是对所有用户开放的,所有用户可以直接 ...

  2. 【BZOJ1297】[SCOI2009]迷路(矩阵快速幂)

    [BZOJ1297][SCOI2009]迷路(矩阵快速幂) 题面 BZOJ 洛谷 题解 因为边权最大为\(9\),所以记录往前记录\(9\)个单位时间前的.到达每个点的方案数就好了,那么矩阵大小就是\ ...

  3. 【BZOJ1967】[AHOI2005]穿越磁场(最短路)

    [BZOJ1967][AHOI2005]穿越磁场(最短路) 题面 BZOJ 洛谷 题解 一个显然的思路是这样的,我们的正方形的边长把整个平面割成了若干块,显然每个联通块都可以看着做一个点,那么接下来只 ...

  4. LANMP环境编译参数查看方法

    nginx编译参数查看:/usr/local/nginx/sbin/nginx -V apache编译参数查看:cat /usr/local/apache2/build/config.nice mys ...

  5. 前端学习 -- Css -- 文档流

    文档流 文档流处在网页的最底层,它表示的是一个页面中的位置, 我们所创建的元素默认都处在文档流中 元素在文档流中的特点 块元素 块元素在文档流中会独占一行,块元素会自上向下排列. 块元素在文档流中默认 ...

  6. DataTables合并单元格(rowspan)的实现思路(多分组分类的情况)

    直接上代码,原理之前的随笔已经讲过了.http://www.cnblogs.com/hdwang/p/7115835.html 1.先看看效果 2.html代码,含js代码 2.1 common.js ...

  7. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

  8. bzoj千题计划181:bzoj1878: [SDOI2009]HH的项链

    http://www.lydsy.com/JudgeOnline/problem.php?id=1878 之前用莫队做的,现在用树状数组 把每种数的第一个出现位置在树状数组中+1 nxt[i] 记录i ...

  9. MongoDB 之 $关键字 及 $修改器 $set $inc $push $pull $pop MongoDB - 4

    我们在之前的 MongoDB 之 手把手教你增删改查 MongoDB - 2 中提到过 $set 这个系统关键字,用来修改值的对吧 但是MongoDB中类似这样的关键字有很多, $lt $gt $lt ...

  10. MongoDB 之 手把手教你增删改查 MongoDB - 2

    我们在  MongoDB 之 你得知道MongoDB是个什么鬼 MongoDB - 1  中学习了如果安装部署一个 MongoDB 如果没看到我的金玉良言的话,就重新打开一次客户端和服务端吧 本章我们 ...