zoukankan      html  css  js  c++  java
  • Webpack按需加载一切皆模块

    前言

    在学习 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 不支持自定义样式 ,所以我贴在了我的博客,希望它能对你有帮助。

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

  • 相关阅读:
    MySQL效能监控工具mysqlreport安装和中文说明
    mysql的配置文件my.cnf
    MySQL的高可用设计方案的记录
    jQuery 求页面加载等待特效
    如果客户端禁用cookie,session还能使用吗?
    heartbeat重要文件的配置参数说明
    MySQL的索引类型和左前缀索引
    比较一下Linux下的Epoll模型和select模型的区别
    网络防火墙和NAT地址转换
    Postfix+dovecot搭建简单邮箱服务器
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/8033738.html
Copyright © 2011-2022 走看看