webpack学习相关
具体内容可以查看笔记
1、为什么使用webpack?
查看官方解释回顾一下历史,之前是如何开发项目的
第一阶段
(1)在每个html文件中都引用大量的<script>标签
这种方式会造成网络瓶颈,并且加载大量的无用代码
(2)只引入一个js文件,这个js里包含了整个项目的所有代码,几万行甚至几十万行代码。这种方式会导致作用域不好区分,同时难以维护
第二阶段
IIFE立即执行函数(function(){})()解决大型项目的作用域问题,Grunt、Gulp就是使用这种模式。当然这样做也有一些问题,比如修改了一个文件也要重新构建整个项目。引入第三方库时,即使只需要少量代码,也要引入整个第三方库代码,不能做到代码分割。
第三阶段
使用webpack(本质上,webpack只是静态模块打包工具)
当然,webpack是基于以下的基础条件或者启发之后产生的(1)node.js的诞生,让js可以在浏览器之外的计算器和服务中运行(2)common.js引入了require机制,允许在当前文件中加载其他模块(浏览器不支持common.js的模块机制,因此出现了Browserify, RequireJS 和 SystemJS 等打包工具,允许我们编写能够在浏览器中运行的common.js模块)
2、webpack基本使用
查看官方文档
(1)安装webpack和webpack-cli
npm install webpack webpack-cli --save-dev
(2)创建配置文件
在根目录下创建3个文件
- webpack.common.js
- webpack.dev.js
- webpack.prod.js
然后修改package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
"start": "webpack serve --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
},
这样子,就可以在npm run start和npm run build时使用不同的配置了
webpack.common.js 具体代码
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { resolve } = require("path");
/*
通常module.exports={...配置对象}
当在命令行中输入webpack --env envName时,module.exports=(env)=>{}可以接收命令行中env参数
*/
module.exports = (env) => ({
entry: () =>
new Promise((resolve) => {
setTimeout(() => {
resolve({
index: { import: "./src/index.js" },
print: { import: "./src/print.js" },
});
}, 50);
}),
output: {
filename: "js/[name].[contenthash].js",
path: path.resolve(__dirname, "dist"),
clean: true,
pathinfo: false,
// 将项目打包成为库(还需要在package.json添加module: src/index.js,允许使用import的方式引用库)
// library: {
// name: "libraryName",
// type: "umd",//兼容common.js(const library=require("library"))、ADM([require("library"),function(library){}])、script标签引用
// },
},
module: {
rules: [
{
test: /\.css$/i,
// include: path.resolve(__dirname, "src"), //包含的目录
use: [
// path.resolve(__dirname, "webpackLoaders/aLoader/a-load.js"),
"style-loader",
"css-loader",
],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset/resource", //webpack5.x内置,用于处理静态资源
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource", //webpack5.x内置,用于处理静态资源
},
],
},
optimization: {
// 添加新文件的引入时,不会改变原chunk的module.id,之前的chunk的hash值得以保留,浏览器会从缓存中读取
moduleIds: "deterministic",
/* runtimeChunk:single表示:
a.js和b.js同时引入c.js(export default {count:0})时,该对象只实例化一次。如果html同时加载a、b两个js,则count++会执行两次。
如果不设置runtimeChunk,则c.js会实例化两次,a、b两个js执行count++则互不影响
runtimeChunk:single的目的是为了保存数据
参考文档:https://bundlers.tooling.report/code-splitting/multi-entry/
*/
runtimeChunk: "single",
// 将node_modules中的库,单独存放到vendor这个chunk中
splitChunks: {
chunks: "all",
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendorName",
chunks: "all",
},
},
},
},
// externals配置不需要打包的外部依赖(即配置中的依赖需要通过script在html引用)
// externals: {
// lodash: {
// commonjs: "lodash",
// commonjs2: "lodash",
// amd: "lodash",
// root: "_",
// },
// },
plugins: [
new HtmlWebpackPlugin({
title: "development",
}),
],
});
webpack.dev.js 具体代码
const path = require("path");
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js")();
const HandleConsole = require("./webpackPlugins/handleConsole.js");
const config = merge(common, {
mode: "development",
devtool: "inline-source-map",
devServer: {
contentBase: "./dist",
hot: true,
},
module: {
rules: [
{
test: /\.text$/i,
loader: path.resolve(__dirname, "webpackLoaders/aLoader/a-load.js"),
},
],
},
// plugins: [new HandleConsole({ test: 123 })],
});
module.exports = config;
webpack.prod.js 相关代码
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js")();
module.exports = merge(common, {
mode: "product",
// devtool: "inline-source-map",
});
3、webpack打包library
大致操作跟上面的一样,只需要配置output中的library即可
output: {
library: {
name: "libraryName",
type: "umd",//兼容common.js(const library=require("library"))、ADM([require("library"),function(library){}])、script标签引用
},
}
如果想要通过import的方式引用library,还需要在package.json添加"module": "src/index.js"
4、开发webpack-loader
参考文档loader的作用就是让各种资源,比如image、less等文件,转换成能够被webpack解析的模块,它的本质其实是一个返回值为string或者Buffer的函数。
module.exports = function (content) {
return content
};
webpack提供了一些常用loader供使用,当然,它也提供了接口供第三方开发loader。比如,我们想要开发一个text-loader用来解析text文件,并且中间插入两个a-loader、b-loader用来做额外的处理。修改webpack.config.js
module.exports={
...
resolveLoader: {
modules: ["node_modules", path.resolve(__dirname, "webpackLoaders")],
extensions: [".js", ".json"],
mainFields: ["module", "main"],
},
module: {
rules: [
{
test: /\.text$/i,
use: [
{
loader: "text-loader",
options: {
test: "luyi",
},
},
{
loader: "b-loader",
options: {
test: "fanny",
},
},
{ loader: "a-loader" },
],
},
],
},
}
注意,loader是从右到左执行(官方文档),我们这里想要先执行a-loader,最后执行text-loader就需要倒着写。然后在根目录下创建这三个文件具体代码a-loader
module.exports = function (content) {
return `外来者aaa:${content}`;
};
b-loader
module.exports = function (content) {
console.log("bbbbb", content);
return `:${content},外来者b`;
};
text-loader是一个目录,包含了3个文件,package.json、index.js是包的逻辑代码,html.js是用来将内容放置到html页面内。index.js
const { getOptions, stringifyRequest } = require("loader-utils");
const path = require("path");
module.exports = function (content) {
let options = getOptions(this);
return `
import handleHtml from ${stringifyRequest(
this,
require.resolve("./html.js")
)};
handleHtml('hello world:${content}');
`;
};
html.js
export default function (content) {
let endTip = document.createElement("div");
endTip.innerHTML = content;
document.body.appendChild(endTip);
}
一旦某个文件,引入text,就会在html中执行loader处理之后的内容比如,test.text内容
###这里是test.text的内容###
import "path/to/test.text"
5、开发webpack-plugin
官方文档webpack-plugin可以影响打包流程,需要了解webpack内部的生命周期等钩子。plugin的本质是一个有apply属性的函数
const pluginName = "HandleConsole";
class HandleConsole {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log("################ 开始编译1 #######################");
console.log(compilation);
console.log("################ 开始编译2 #######################");
});
}
}
module.exports = HandleConsole;
以上就是一个基本的plugin还需要在webpack.config.js中添加配置
const HandleConsole = require("./webpackPlugins/handleConsole.js");
module.exports={
...
plugins: [new HandleConsole({ test: 123 })],
}
转载自:https://segmentfault.com/a/1190000040273932