zoukankan      html  css  js  c++  java
  • 通过核心概念了解webpack工作机制

    webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
    需要先理解四个核心概念:

    • 入口(entry)
    • 输出(output)
    • loader
    • 插件(plugins)

    入口(entry)

    入口指 webpack 构建其内部依赖图开始的模块。进入入口后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
    在 webpack 配置中有多种方式定义 entry 属性。
    用法:

    const config = {
    entry: {
    app: './src/app.js',
    vendors: './src/vendors.js'
    }
    };


    单个入口可简写成如下:

    const config = {
    entry: './path/to/my/entry/file.js'
    };

    以下是两种实际用例:
    1.分离应用程序和第三方库入口,vue-cli中是这样做的:

    const config = {
    entry: {
    app: './src/app.js',
    vendors: './src/vendors.js'
    }
    };

    webpack 从 app.js 和 vendors.js 开始创建依赖图。这些依赖图是彼此完全分离、互相独立的。这种方式比较常见于,只有一个入口起点(不包括 vendor)的单页应用程序(single page application)中。

    2.多页面应用程序

    const config = {
    entry: {
    pageOne: './src/pageOne/index.js',
    pageTwo: './src/pageTwo/index.js',
    pageThree: './src/pageThree/index.js'
    }
    };

    在多页应用中,页面跳转时服务器将为你获取一个新的 HTML 文档。页面重新加载新文档,并且资源被重新下载。由于入口起点增多,多页应用能够复用入口起点之间的大量代码/模块.

    输出(Output)

    该属性设置 webpack 在输出它所创建的 bundles的路径以及命名。
    注意: 即使可以存在多个入口起点,但只指定一个输出配置。

    用法:
    在 webpack 中配置 output 属性的最低要求是,将它的值设置为一个对象,包括以下两点:

    filename 用于输出文件的文件名。
    目标输出目录 path 的绝对路径。

    const config = {
    output: {
    filename: 'bundle.js',
    path: '/home/proj/public/assets'
    }
    };

    module.exports = config;
    此配置将一个单独的 bundle.js 文件输出到 /home/proj/public/assets 目录中。

    多个入口时:
    如果配置创建了多个单独的 "chunk"(例如,使用多个入口起点或使用像 CommonsChunkPlugin 这样的插件),则应该使用占位符(substitutions)来确保每个文件具有唯一的名称。

    {
    entry: {
    app: './src/app.js',
    search: './src/search.js'
    },
    output: {
    filename: '[name].js',
    path: __dirname + '/dist'
    }
    }

    复杂示例:
    以下是使用 CDN 和资源 hash 的复杂示例

    output: {
    path: "/home/proj/cdn/assets/[hash]",
    publicPath: "http://cdn.example.com/assets/[hash]/"
    }

    在编译时不知道最终输出文件的 publicPath 的情况下,publicPath 可以留空,并且在入口起点文件运行时动态设置。如果你在编译时不知道 publicPath,你可以先忽略它,并且在入口起点设置 __webpack_public_path__。

    __webpack_public_path__ = myRuntimePublicPath

    // 剩余的应用程序入口

    loader

    用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!

    示例:
    使用loader加载 CSS 文件 和 将 TypeScript 转为 JavaScript。
    首先安装对应的loader

    npm install --save-dev css-loader
    npm install --save-dev ts-loader

    然后指示 webpack 对每个 .css 使用 css-loader,以及对所有 .ts 文件使用 ts-loader:

    module.exports = {
    module: {
    rules: [
    { test: /.css$/, use: 'css-loader' },
    { test: /.ts$/, use: 'ts-loader' }
    ]
    }
    };


    以上配置,对一个 module 对象定义了 rules 属性,里面包含两个必须属性:test 和 use。
    test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
    use 属性,表示进行转换时,应该使用哪个 loader。
    上面的配置代表, 当webpack编译器解析时, 遇到 require()/import 语句有'.css'路径时,在打包之前先用 css-loader 转换一下;遇到 require()/import 语句有'.ts'路径时,在打包之前先用 ts-loader 转换一下

    使用Loader的三种方式:

    1.配置: 在 webpack.config.js 文件中指定 loader。

    module.rules 允许你在 webpack 配置中指定多个 loader。 这是展示 loader 的一种简明方式,并且有助于使代码变得简洁。同时让你对各个 loader 有个全局概览:

    module: {
      rules: [
        {
          test: /.css$/,
          use: [
            { loader: 'style-loader' },
            {
              loader: 'css-loader',
              options: {
                modules: true
              }
            }
          ]
        }
      ]
    }

    2.内联: 在 import 语句或任何等效于 "import" 的方式中指定 loader。

    使用 ! 将资源中的 loader 分开。分开的每个部分都相对于当前目录解析。

    import Styles from 'style-loader!css-loader?modules!./styles.css';


    通过前置所有规则及使用 !,可以对应覆盖到配置中的任意 loader。选项可以传递查询参数,例如 ?key=value&foo=bar,或者一个 JSON 对象,例如 ?{"key":"value","foo":"bar"}。

    3.通过 CLI 使用 loader:

    webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

    loader 通过(loader)预处理函数,为 JavaScript 生态系统提供了更多能力。 用户现在可以更加灵活地引入细粒度逻辑,例如压缩、打包、语言翻译等loader 遵循标准的模块解析。多数情况下,loader 将从模块路径(通常将模块路径认为是 npm install, node_modules)解析。loader 模块需要导出为一个函数,并且使用 Node.js 兼容的 JavaScript 编写。通常使用 npm 进行管理,但是也可以将自定义 loader 作为应用程序中的文件。按照约定,loader 通常被命名为 xxx-loader(例如 json-loader)。

    用法:
    由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例。
    根据你的 webpack 用法,这里有多种方式使用插件。

    const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
    const webpack = require('webpack'); //访问内置的插件
    const path = require('path');
    
    const config = {
      entry: './path/to/my/entry/file.js',
      output: {
        filename: 'my-first-webpack.bundle.js',
        path: path.resolve(__dirname, 'dist')
      },
      module: {
        loaders: [
          {
            test: /.(js|jsx)$/,
            use: 'babel-loader'
          }
        ]
      },
      plugins: [
        new webpack.optimize.UglifyJsPlugin(),
        new HtmlWebpackPlugin({template: './src/index.html'})
      ]
    };
    
    module.exports = config;

    插件(plugins)

    loader 被用于转换某些类型的模块,而插件的使用范围包括,从打包优化和压缩,一直到重新定义环境中的变量。可以用来处理各种任务.
    使用某个插件,只需要require(),然后添加到 plugins 数组中.多数插件可以通过选项(option)自定义,也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例。

    示例:

    const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
    const webpack = require('webpack'); // 用于访问内置插件
    const path = require('path');
    
    const config = {
      entry: './src/main.js',
      output: {
        path: path.resolve(__dirname, 'dist'), //生成文件(emit)的路径
        filename: 'yq-webpack.bundle.js' // webpack bundle 的名称
      },
      module: {
        rules: [
          {test: /.txt$/, use: 'raw-loader'}
        ]
      },
      plugins: [
        new webpack.optimize.UglifyJsPlugin(),
        new HtmlWebpackPlugin({template: './src/index.html'})
      ]
    };
    
    module.exports = config;

     模块

      在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为_模块_。

    每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。 精心编写的_模块_提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的。
    对比 Node.js 模块,webpack _模块_能够以各种方式表达它们的依赖关系

    • ES2015 import 语句
    • CommonJS require() 语句
    • AMD define 和 require 语句
    • css/sass/less 文件中的 @import 语句。
    • 样式(url(...))或 HTML 文件(<img src=...>)中的图片链接(image url)

    resolver 是一个库(library),用于帮助找到模块的绝对路径。一个模块可以作为另一个模块的依赖模块,然后被后者引用,如下:

    import foo from 'path/to/module'
    // 或者
    require('path/to/module')

    所依赖的模块可以是来自应用程序代码或第三方的库(library)。resolver 帮助 webpack 找到 bundle 中需要引入的模块代码,这些代码在包含在每个 require/import 语句中。 当打包模块时,webpack 使用 enhanced-resolve 来解析文件路径

    webpack 中的解析规则

    webpack 能够解析三种文件路径:
    绝对路径:

    import "/home/me/file";
    
    import "C:\Users\me\file";

    相对路径

    import "/home/me/file";
    
    import "C:\Users\me\file";

    在这种情况下,使用 import 或 require 的资源文件(resource file)所在的目录被认为是上下文目录(context directory)。在 import/require 中给定的相对路径,会添加此上下文路径(context path),以产生模块的绝对路径(absolute path)。

    模块路径

    import "module";
    
    
    import "module/lib/file";

    模块将在 resolve.modules 中指定的所有目录内搜索。

    一旦根据上述规则解析路径后,解析器(resolver)将检查路径是否指向文件或目录。如果路径指向一个文件:
    如果路径具有文件扩展名,则被直接将文件打包。
    否则,将使用 [resolve.extensions] 选项作为文件扩展名来解析,此选项告诉解析器在解析中能够接受哪些扩展名(例如 .js, .jsx)。

    如果路径指向一个文件夹,则采取以下步骤找到具有正确扩展名的正确文件:

    如果文件夹中包含 package.json 文件,则按照顺序查找 resolve.mainFields 配置选项中指定的字段。并且 package.json 中的第一个这样的字段确定文件路径。
    如果 package.json 文件不存在或者 package.json 文件中的 main 字段没有返回一个有效路径,则按照顺序查找 resolve.mainFiles 配置选项中指定的文件名,看是否能在 import/require 目录下匹配到一个存在的文件名。
    文件扩展名通过 resolve.extensions 选项采用类似的方法进行解析。
    webpack 根据构建目标(build target)为这些选项提供了合理的默认配置。
  • 相关阅读:
    hdu 1856 More is better
    hdu 1014 Uniform Generator
    hdu 1412 {A} + {B}
    hdu 1022 Train Problem I
    hdu 1027 Ignatius and the Princess II
    hdu 2377 Bus Pass
    POJ 1141 Brackets Sequence
    guava学习,集合专题
    org.apache.commons等常用工具学习
    utf-8mb4和排序规则
  • 原文地址:https://www.cnblogs.com/yuqing6/p/8484557.html
Copyright © 2011-2022 走看看