webpack
webpack 就是一个前端资源打包工具,它依据模块的依赖关系进行动态剖析,而后将这些模块依照指定的规定生成对应动态资源。
根本应用
在本地装置 webpack
yarn add webpack webpack-cli --dev
文件目录,创立 webpack.config.js
配置文件(在 webpack v4 中,能够毋庸任何配置,然而大多数我的项目会须要很简单的设置)。
const path = require("path");module.exports = { /** * 默认值为 production * development 优化打包速度,增加一些调试过程须要的辅助 * production 优化打包后果 **/ mode: "development", entry: "./src/main.js", // 入口文件 output: { filename: "bundle.js", // 输入文件名 path: path.join(__dirname, "dist"), // 输入文件门路 },};
运行打包命令
yarn webpack
资源模块加载
Webpack 默认只能解决 js 文件,非 js 文件通过 loader 加载解决
文件资源
安装文件资源对应 loader
yarn add css-loader style-loader --dev
文件引入
// main.jsimport createHeading from "./heading.js";import "./main.css";const heading = createHeading();document.body.append(heading);
webpack 配置文件
通过css-loader
实现对 css 文件的解决,还须要style-loader
将打包后的 css 文件引入页面
留神:loader 的记录机制是从后往前,所以数组中 css loader 在后先应用,style loader 在后,后应用
const path = require("path");module.exports = { mode: "none", entry: "./src/main.js", output: { filename: "bundle.js", path: path.join(__dirname, "dist"), }, module: { rules: [ { test: /.css$/, use: ["style-loader", "css-loader"], }, ], },};
图片资源
因为 index.html
没有生成到 dist
目录,而是放在我的项目的根目录下,所以把我的项目根目录作为网站根目录,而 webpack 会默认认为所有打包后果都放在网站的根目录上面,导致在根目录下查找图片资源。解决办法配置 publicPath: 'dist/'
。
webpack 打包时遇到图片文件,依据配置文件配置,匹配到文件加载器,文件加载器开始工作,先将导入的文件 copy 到输入目录,而后将文件 copy 到输入目录过后的门路,作为以后模块的返回值返回,这样资源就被公布进去了。
装置图片资源对应 loader
yarn add file-loader --dev
文件引入
import createHeading from "./heading.js";import "./main.css";import icon from "./icon.png";const heading = createHeading();document.body.append(heading);const img = new Image();img.src = icon;document.body.append(img);
webpack 配置文件
const path = require("path");module.exports = { mode: "none", entry: "./src/main.js", output: { filename: "bundle.js", path: path.join(__dirname, "dist"), publicPath: "dist/", }, module: { rules: [ { test: /.css$/, use: ["style-loader", "css-loader"], }, { test: /.png$/, use: "file-loader", }, ], },};
URL 资源
data urls
是非凡的 url
协定,能够用来间接示意一个文件,传统 url
要求服务器有一个对应文件,而后咱们通过申请这个地址失去这个对应文件。 而 data url
是一种以后 url
就能够间接示意文件内容的形式,这种 url
中的文本蕴含文件内容,应用时不会发送任何 http 申请。
html 内容: data:text/html;charset=UTF-8,<h1>xxx</h1>
png 类型文件:data:image/png;base64,iVBORw0KGgoAAAANSUhE...
装置资源对应 loader
yarn add url-loader --dev
webpack 配置文件
... module: { rules: [ { test: /.css$/, use: ["style-loader", "css-loader"], }, { test: /.png$/, use: { loader: "url-loader", options: { limit: 10 * 1024, // 对于小于10kb的图片资源应用 url-loader, 大于则应用 file-loader }, }, }, ], },
罕用加载器分类
- 编译转换类
- 文件操作类
- 代码查看类
webpack 与 es2015
webpack 因为模块打包须要,所以解决了 import 和 export,然而并不能转化代码中其余的 es6 个性
装置资源对应 loader
yarn add babel-loader @babel/core @babel/preset-env --dev
module: { rules: [ { test: /.js$/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, }, { test: /.css$/, use: ["style-loader", "css-loader"], }, { test: /.png$/, use: { loader: "url-loader", options: { limit: 10 * 1024, // 对于小于10kb的图片资源应用 url-loader, 大于则应用 file-loader }, }, }, ], },
模块加载形式
模块加载的形式有遵循 ES Modules 规范的 import
申明,遵循 CommonJS 规范的 require
函数,遵循 AMD 规范的 define
函数和 require
函数
除了下面形式,触发模块加载形式还有 css 款式代码中的 url
函数和 @import
指令,html 代码中图片标签的 src
属性
html 中的 src
属性触发模块加载
yarn add html-loader --dev
{ test:/.html$/, use:{ loader:'html-loader' }}
然而 html-loader 只能解决 html 下 img:src 属性,其余额定属性通过 attrs 配置
{ test:/.html$/, use:{ loader:'html-loader', //默认只能解决html img src属性,其余额定属性通过attrs配置 options:{ attrs:['img:src','a:href'] } }}
开发一个 loader
webpack 加载资源过程相似于工作管道,能够在加载过程中顺次应用多个 loader,然而最终后果必须是 js 代码。
每个 webpack loader 都须要导出一个函数,输出就是加载到的资源文件的内容,输入就是此次加工过后的后果。
const marked = require("marked");module.exports = (source) => { const html = marked(source); return html;};
module: { rules: [ { test: /.md$/, use: [ "html-loader", "./md-loader", //模块名称或文件门路,相似nodejs的require ], }, ];}
插件机制
loader 专一实现资源模块加载,plugin 解决其余自动化工作,加强 webpack 自动化能力
主动革除目录插件
装置扩大包
yarn add clean-webpack-plugin --dev
const path = require("path");const { CleanWebpackPlugin } = require("clean-webpack-plugin");module.exports = { mode: "none", entry: "./src/main.js", output: { filename: "bundle.js", path: path.join(__dirname, "dist"), publicPath: "dist/", }, module: { rules: [ ... ], }, plugins: [new CleanWebpackPlugin()],};
主动生成 HTML
装置扩大包
yarn add html-webpack-plugin --dev
dist 下生成 html,解决以前根下 html 中的引入门路须要通过 publicpath 申明硬编码的问题。
const path = require("path");const { CleanWebpackPlugin } = require("clean-webpack-plugin");const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = { mode: "none", entry: "./src/main.js", output: { filename: "bundle.js", path: path.join(__dirname, "dist"), // publicPath: "dist/", }, plugins: [new CleanWebpackPlugin(), new HtmlWebpackPlugin()],};
自定义元数据
const path = require("path");const { CleanWebpackPlugin } = require("clean-webpack-plugin");const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = { mode: "none", entry: "./src/main.js", output: { filename: "bundle.js", path: path.join(__dirname, "dist"), }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ title: "webpack plugin sample", meta: { viewport: "width=device-width", }, template: "./src/index.html", }), ],};
模板文件
<!--./src/index.html--><!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Webpack</title> </head> <body> <div class="container"> <!-- 拜访插件配置数据 --> <h1><%= htmlWebpackPlugin.options.title %></h1> </div> </body></html>
同时输入多个页面文件
const path = require("path");const { CleanWebpackPlugin } = require("clean-webpack-plugin");const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = { mode: "none", entry: "./src/main.js", output: { filename: "bundle.js", path: path.join(__dirname, "dist"), }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ title: "webpack plugin sample", meta: { viewport: "width=device-width", }, template: "./src/index.html", }), new HtmlWebpackPlugin({ filename: "about.html", }), ],};
动态文件拷贝插件
yarn add copy-webpack-plugin --dev
const CopyWebpackPlugin = require("copy-webpack-plugin");plugins: [ //参数数组,指定拷贝的文件门路(通配符,目录,相对路径) new CopyWebpackPlugin({ patterns: ["public"], }),];
插件机制工作原理
webpack plugin 是通过钩子机制实现。
钩子机制相似于 web 中的事件。在 webpack 工作过程中会有很多环节,为了便于插件的扩大,webpack 简直给每一个环节都埋下了钩子,这样咱们在开发插件时,能够通过往这些不同的节点下来挂载不同工作,就能够轻松扩大 webpack 的能力。
开发一个插件
webpack 要求插件必须是一个函数或者是一个蕴含 apply 办法的对象,个别咱们都会把插件定义为一个类型,而后再这个类型中定义一个 apply 办法
定义一个插件往钩子上挂载工作,这个插件用于革除 bundle.js 中无用的正文
MyPlugin 文件
module.exports = class MyPlugin { apply(compiler) { // 此办法在webpack启动时主动被调用,compile配置对象,配置信息 console.log("MyPlugin 启动"); // 通过hooks属性拜访钩子emit // 参考:https://webpack.docschina.org/api/compiler-hooks/ // tap办法注册钩子函数(参数1:插件名称,参数2:挂载到钩子上的函数) compiler.hooks.emit.tap("MyPlugin", (compilation) => { // compilation 能够了解为此次打包的上下文,所有打包过程产生的后果都会放到这个对象中 // compilation.assets属性是个对象,用于获取行将写入目录当中的资源文件信息 for (const name in compilation.assets) { // console.log("文件名称:",name); 如图 // console.log("文件内容:",compilation.assets[name].source()); if (name.endsWith(".js")) { //获取内容 const contents = compilation.assets[name].source(); //替换内容 const withoutComments = contents.replace(/\/\*\*+\*\//g, ""); //笼罩老内容 compilation.assets[name] = { source: () => withoutComments, size: () => withoutComments.length, //返回内容的大小,webpack要求必须加 }; } } }); }};
配置文件
const path = require("path");const { CleanWebpackPlugin } = require("clean-webpack-plugin");const HtmlWebpackPlugin = require("html-webpack-plugin");const CopyWebpackPlugin = require("copy-webpack-plugin");const myPlugin = require("./MyPlugin.js");module.exports = { mode: "none", entry: "./src/main.js", output: { filename: "bundle.js", path: path.join(__dirname, "dist"), // publicPath: "dist/", }, plugins: [new CleanWebpackPlugin(), new myPlugin()],};