webpack 学习笔记:核心概念(下)

Plugins

Loaders 是用来处理 webpack 默认不支持的类型文件,将文件转换为 webpack 能正确认识的 module。Plugins 功能更加宽泛,用来做 Loaders 做不了的事情,比如:bundle 优化、资源文件管理、环境变量注入等。

以 HtmlWebpackPlugin 这个插件为例,它的作用是生成一个 html 文件,将我们打包后的脚本插入进去。

一、首先安装依赖

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

二、在 webpack.config.js 中配置

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './path/to/my/entry/file.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
    },
    module: {
        rules: [
            // See: https://webpack.js.org/loaders/raw-loader/
            { test: /\.txt$/, use: { loader: 'raw-loader', options: { esModule: false } } }
        ]
    },
    plugins: [
        // See: https://webpack.js.org/plugins/html-webpack-plugin/
        new HtmlWebpackPlugin()
    ]
};

webapck 插件是通过 plugins 选项来配置添加的。上面我们指定打包过程中,使用 HtmlWebpackPlugin 这个插件。

三、执行打包

$ npx webpack

Hash: 24ab0a25d3bb40a069db
Version: webpack 4.44.2
Time: 196ms
Built at: 2020-09-26 11:50:08 ├F10: AM┤
                     Asset       Size  Chunks             Chunk Names
                index.html  219 bytes          [emitted]  
my-first-webpack.bundle.js   1.64 KiB       0  [emitted]  main       
Entrypoint main = my-first-webpack.bundle.js
[0] ./path/to/my/entry/file.js 246 bytes {0} [built]
[1] ../package.json 375 bytes {0} [built]
[2] ./path/to/my/entry/test.txt 253 bytes {0} [built]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
Child HtmlWebpackCompiler:
     1 asset
    Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
       1 module

在 dist/ 下能看到多出一个 index.html 文件。

<!doctype html><html><head><meta charset="utf-8"><title>Webpack App</title><meta name="viewport" content="width=device-width,initial-scale=1"></head><body><script src="my-first-webpack.bundle.js"></script></body></html>

webpack 学习笔记:核心概念(下)

使用 HtmlWebpackPlugin 时,如果没有显式传入模板文件,插件内部会使用默认的一套模板来注入 bundle 脚本。当然也可以手动指定使用的模板文件。

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    // ......
    plugins: [
        new HtmlWebpackPlugin({ template: './src/index.html' })
    ]
};

指定 src/index.html 为模板文件,默认支持 ejs 模板语法借助 lodash template 方法)。

接下来打包:

$ npx webpack

Hash: 7030b4ec93118804aa9d
Version: webpack 4.44.2
Time: 206ms
Built at: 2020-09-26 12:07:52 ├F10: PM┤
                     Asset       Size  Chunks             Chunk Names
                index.html  231 bytes          [emitted]
my-first-webpack.bundle.js   1.94 KiB       0  [emitted]  main
Entrypoint main = my-first-webpack.bundle.js

......
Child HtmlWebpackCompiler:
     1 asset
    Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
    [0] ../node_modules/html-webpack-plugin/lib/loader.js!./src/index.html 476 bytes {0} [built]

依然打包成功了。

Mode

前面我们打包时,一直会看到下面的 warning。

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

表示在写配置文件时,要显式设置 option 选项,否则默认使用的是 “production”,当然还可以取 “development” 和 “none” 值。它是用来针对不同环境,启用 webpack 内置优化的。

module.exports = {
  mode: 'production' // 'production'(默认值) | 'development' | 'none'
};

“production”mode 前面已经看到过了,接下来再试试“development”mode。

/******/ (function(modules) { // webpackBootstrap
/******/     // The module cache
/******/     var installedModules = {};
/******/
/******/     // The require function
/******/     function __webpack_require__(moduleId) {
/******/
/******/         // Check if module is in cache
/******/         if(installedModules[moduleId]) {
/******/             return installedModules[moduleId].exports;
/******/         }
/******/         // Create a new module (and put it into the cache)
/******/         var module = installedModules[moduleId] = {
/******/             i: moduleId,
/******/             l: false,
/******/             exports: {}
/******/         };
/******/
/******/         // Execute the module function
/******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/         // Flag the module as loaded
/******/         module.l = true;
/******/
/******/         // Return the exports of the module
/******/         return module.exports;
/******/     }
/******/
/******/
/******/     // expose the modules object (__webpack_modules__)
/******/     __webpack_require__.m = modules;
/******/
/******/     // expose the module cache
/******/     __webpack_require__.c = installedModules;
/******/
/******/     // define getter function for harmony exports
/******/     __webpack_require__.d = function(exports, name, getter) {
/******/         if(!__webpack_require__.o(exports, name)) {
/******/             Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/         }
/******/     };
/******/
/******/     // define __esModule on exports
/******/     __webpack_require__.r = function(exports) {
/******/         if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/             Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/         }
/******/         Object.defineProperty(exports, '__esModule', { value: true });
/******/     };
/******/
/******/     // create a fake namespace object
/******/     // mode & 1: value is a module id, require it
/******/     // mode & 2: merge all properties of value into the ns
/******/     // mode & 4: return value when already ns object
/******/     // mode & 8|1: behave like require
/******/     __webpack_require__.t = function(value, mode) {
/******/         if(mode & 1) value = __webpack_require__(value);
/******/         if(mode & 8) return value;
/******/         if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/         var ns = Object.create(null);
/******/         __webpack_require__.r(ns);
/******/         Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/         if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/         return ns;
/******/     };
/******/
/******/     // getDefaultExport function for compatibility with non-harmony modules
/******/     __webpack_require__.n = function(module) {
/******/         var getter = module && module.__esModule ?
/******/             function getDefault() { return module['default']; } :
/******/             function getModuleExports() { return module; };
/******/         __webpack_require__.d(getter, 'a', getter);
/******/         return getter;
/******/     };
/******/
/******/     // Object.prototype.hasOwnProperty.call
/******/     __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/     // __webpack_public_path__
/******/     __webpack_require__.p = "";
/******/
/******/
/******/     // Load entry module and return exports
/******/     return __webpack_require__(__webpack_require__.s = "./path/to/my/entry/file.js");
/******/ })
/************************************************************************/
/******/ ({

/***/ "../package.json":
/*!***********************!*\
  !*** ../package.json ***!
  \***********************/
/*! exports provided: name, version, description, main, scripts, keywords, author, license, devDependencies, default */
/***/ (function(module) {

eval("module.exports = JSON.parse(\"{\\\"name\\\":\\\"webpack-demos\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"description\\\":\\\"\\\",\\\"main\\\":\\\"index.js\\\",\\\"scripts\\\":{\\\"test\\\":\\\"echo \\\\\\\"Error: no test specified\\\\\\\" && exit 1\\\"},\\\"keywords\\\":[],\\\"author\\\":\\\"\\\",\\\"license\\\":\\\"ISC\\\",\\\"devDependencies\\\":{\\\"html-webpack-plugin\\\":\\\"^4.5.0\\\",\\\"raw-loader\\\":\\\"^4.0.1\\\",\\\"webpack\\\":\\\"^4.44.2\\\",\\\"webpack-cli\\\":\\\"^3.3.12\\\"}}\");\n\n//# sourceURL=webpack:///../package.json?");

/***/ }),

/***/ "./path/to/my/entry/file.js":
/*!**********************************!*\
  !*** ./path/to/my/entry/file.js ***!
  \**********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

eval("const pkg = __webpack_require__(/*! ../../../../../package.json */ \"../package.json\")\r\nconst p = __webpack_require__(/*! ./test.txt */ \"./path/to/my/entry/test.txt\")\r\n\r\nfunction say(what = 'Hello webpack') {\r\n    return `📢(v${pkg.version}) ${what}`\r\n}\r\n\r\n// Sees: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML\r\ndocument.body.insertAdjacentHTML('afterbegin', `\r\n    <h1>${say()}</h1>\r\n    ${\r\n        p.match(/[^\\r\\n]+/g).map(line => `<p>${line}</p>`).join('')\r\n    }\r\n`)\r\n\n\n//# sourceURL=webpack:///./path/to/my/entry/file.js?");

/***/ }),

/***/ "./path/to/my/entry/test.txt":
/*!***********************************!*\
  !*** ./path/to/my/entry/test.txt ***!
  \***********************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = \"While loaders are used to transform certain types of modules, plugins can be leveraged to perform a wider range of tasks like bundle optimization, asset management and injection of environment variables.\\r\\n\\r\\nIn order to use a plugin, you need to require() it and add it to the plugins array. Most plugins are customizable through options. Since you can use a plugin multiple times in a configuration for different purposes, you need to create an instance of it by calling it with the new operator.\";\n\n//# sourceURL=webpack:///./path/to/my/entry/test.txt?");

/***/ })

/******/ });

最终打包的文件中,包含详细的注释内容,注明当前那部分代码的文件来源。

设置成“none”的话,表示不会对输出做任何内置优化。

/******/ (function(modules) { // webpackBootstrap
/******/     // The module cache
/******/     var installedModules = {};
/******/
/******/     // The require function
/******/     function __webpack_require__(moduleId) {
/******/
/******/         // Check if module is in cache
/******/         if(installedModules[moduleId]) {
/******/             return installedModules[moduleId].exports;
/******/         }
/******/         // Create a new module (and put it into the cache)
/******/         var module = installedModules[moduleId] = {
/******/             i: moduleId,
/******/             l: false,
/******/             exports: {}
/******/         };
/******/
/******/         // Execute the module function
/******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/         // Flag the module as loaded
/******/         module.l = true;
/******/
/******/         // Return the exports of the module
/******/         return module.exports;
/******/     }
/******/
/******/
/******/     // expose the modules object (__webpack_modules__)
/******/     __webpack_require__.m = modules;
/******/
/******/     // expose the module cache
/******/     __webpack_require__.c = installedModules;
/******/
/******/     // define getter function for harmony exports
/******/     __webpack_require__.d = function(exports, name, getter) {
/******/         if(!__webpack_require__.o(exports, name)) {
/******/             Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/         }
/******/     };
/******/
/******/     // define __esModule on exports
/******/     __webpack_require__.r = function(exports) {
/******/         if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/             Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/         }
/******/         Object.defineProperty(exports, '__esModule', { value: true });
/******/     };
/******/
/******/     // create a fake namespace object
/******/     // mode & 1: value is a module id, require it
/******/     // mode & 2: merge all properties of value into the ns
/******/     // mode & 4: return value when already ns object
/******/     // mode & 8|1: behave like require
/******/     __webpack_require__.t = function(value, mode) {
/******/         if(mode & 1) value = __webpack_require__(value);
/******/         if(mode & 8) return value;
/******/         if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/         var ns = Object.create(null);
/******/         __webpack_require__.r(ns);
/******/         Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/         if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/         return ns;
/******/     };
/******/
/******/     // getDefaultExport function for compatibility with non-harmony modules
/******/     __webpack_require__.n = function(module) {
/******/         var getter = module && module.__esModule ?
/******/             function getDefault() { return module['default']; } :
/******/             function getModuleExports() { return module; };
/******/         __webpack_require__.d(getter, 'a', getter);
/******/         return getter;
/******/     };
/******/
/******/     // Object.prototype.hasOwnProperty.call
/******/     __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/     // __webpack_public_path__
/******/     __webpack_require__.p = "";
/******/
/******/
/******/     // Load entry module and return exports
/******/     return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

const pkg = __webpack_require__(1)
const p = __webpack_require__(2)

function say(what = 'Hello webpack') {
    return `📢(v${pkg.version}) ${what}`
}

// Sees: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
document.body.insertAdjacentHTML('afterbegin', `
    <h1>${say()}</h1>
    ${
        p.match(/[^\r\n]+/g).map(line => `<p>${line}</p>`).join('')
    }
`)


/***/ }),
/* 1 */
/***/ (function(module) {

module.exports = JSON.parse("{\"name\":\"webpack-demos\",\"version\":\"1.0.0\",\"description\":\"\",\"main\":\"index.js\",\"scripts\":{\"test\":\"echo \\\"Error: no test specified\\\" && exit 1\"},\"keywords\":[],\"author\":\"\",\"license\":\"ISC\",\"devDependencies\":{\"html-webpack-plugin\":\"^4.5.0\",\"raw-loader\":\"^4.0.1\",\"webpack\":\"^4.44.2\",\"webpack-cli\":\"^3.3.12\"}}");

/***/ }),
/* 2 */
/***/ (function(module, exports) {

module.exports = "While loaders are used to transform certain types of modules, plugins can be leveraged to perform a wider range of tasks like bundle optimization, asset management and injection of environment variables.\r\n\r\nIn order to use a plugin, you need to require() it and add it to the plugins array. Most plugins are customizable through options. Since you can use a plugin multiple times in a configuration for different purposes, you need to create an instance of it by calling it with the new operator.";

/***/ })
/******/ ]);

Browser Compatibility

webpack 支持 IE9+ 以上的所有现代浏览器。如果需要支持旧版浏览器,那么就需要加载 Promise polyfill 来支持 Promise API,以便支持 webpack 动态引入(Dynamic Imports) 特性。

Environment

webpack 需要 Node.js 8.x 及以上版本的支持。

(完)

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!