webpack 依赖管理
webpack 提供的模块加载方式很多,ES2015 的静态加载方式是官方推荐的,但有时需要加载大批量的模块,就可以使用 webpack 模块方法的 require.context
。
需求
假设有这么一个项目:
src/
packages/
one.js
tow.js
app.js
其中 app.js
是主文件,主文件需要加载所有 packages
文件夹下的文件。
为了测试方便,one.js
、tow.js
默认导出一个函数并打印一句话:
/**
* @file one.js
* path: src/packages/one.js
*/
export default function one() {
console.log("this is one");
}
/**
* @file tow.js
* path: src/packages/tow.js
*/
export default function tow() {
console.log("this is tow");
}
模块上下文
要想在 src/app.js
中导入整个 packages
需要创建一个 模块上下文,模块上下文具有目标目录下所有模块的引用。
创建一个模块上下文使用 require.context
方法:
require.context(directory, (useSubdirectories = false), (regExp = /^\.\//));
它有三个参数:
directory
:要搜索的文件夹目录;useSubdirectories
:是否搜索子目录;regExp
:过滤文件的正则表达式。
尝试在 src/app.js
中创建模块上下文:
/**
* @file app.js
* path: src/app.js
*/
const context = require.context("./packages", true, /\.js$/);
模块上下文提供以下 API 使用:
context.resolve(key)
:函数,传入请求的模块路径得到模块 id,模块 id 和路径很像;context.keys()
:函数,返回被模块上下文处理请求的数组;context.id
:当前模块上下文的模块 id。context(key)
:函数,传入模块请求,返回指定模块。
都使用看看:
修改 src/app.js
:
/**
* @file app.js
* path: src/app.js
*/
const context = require.context("./packages", true, /\.js$/);
// 使用 id
console.log(`id:`, context.id, `\n`);
// 使用 keys
console.log(`keys:`, context.keys(), `\n`);
// 使用 resolve
console.log(`resolve:`);
context.keys().forEach((key) => console.log(context.resolve(key)));
console.log(`\nmodules:`);
context.keys().forEach((key) =>
/* 访问的模块需要使用 .default 访问默认导出 */
context(key).default()
);
打包执行
安装 webpack 和 webpack-cli 打包测试:
npm install --save webpack webpack-cli
然后添加 webpack.config.js
到根目录:
/**
* @file webpack.config.js
*/
const path = require("path");
module.exports = {
mode: "development",
entry: "./src/app.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
};
接着执行命令(windows 下):
npx webpack web; node ./dist/bundle.js
可以看到控制台输出为:
id: ./src/packages sync recursive \.js$
keys: [ './one.js', './tow.js' ]
resolve:
./src/packages/one.js
./src/packages/tow.js
modules:
this is one
this is tow
观察可知:
- id 为模块上下文的相关信息组成;
- keys 包含了引入的模块路径;
- resolve 解析的是模块基于项目的路径;
- 使用模块上下文可以直接访问模块,默认导出为模块的
default
属性。
在 Vue 中使用
使用 Vue 代码
假定项目目录如下:
src/
packages/
One.vue
Tow.vue
VueApp.vue
其中 src/packages/One.vue
内容修改为:
<script>
/**
* @file One.vue
* path: src/packages/One.js
*/
export default {
name: "One",
};
</script>
<template>
<p>this is One</p>
</template>
src/packages/Tow.vue
的修改类似,不在赘述,注意组件名 name
不要相同。
导入整个 src/packages
文件夹里的 Vue 文件
在 src/VueApp.vue
文件中,编写以下代码:
<script>
/**
* @file VueApp.vue
* path: src/VueApp.vue
*/
/** 模块上下文,获取 src/packages/ 文件夹下所有的 Vue 文件 */
const context = require.context("./packages", true, /\.vue$/);
/** 组件包,使用组件名作为键,组件作为值填充 */
const packages = context.keys().reduce((prev, key) => {
const Component = context(key).default;
prev[Component.name] = Component;
return prev;
}, {});
export default {
components: { ...packages },
data() {
return {
ComponentNames: Object.keys(packages),
};
},
};
</script>
<template>
<div>
<h2>Vue Components!</h2>
<!-- 使用 Component 组件渲染 packages 下的所有组件 -->
<Component v-for="name in ComponentNames" :key="name" :is="name" />
<p>packages 文件夹下所有组件的名称为:{{ ComponentNames }}</p>
</div>
</template>
在你的脚手架中引入这个这个组件,你可以看到动态渲染了 src/packages/
文件夹下的所有 Vue 组件。
在 React 中使用
假定项目文件夹如下:
src/
packages/
One.jsx
Tow.jsx
ReactApp.jsx
使用 React 代码
修改 src/packages/One.jsx
文件内容如下:
/**
* @file src/packages/One.jsx
*/
import React from "react";
export default function One() {
return <p>this is One</p>;
}
src/packages/Tow.jsx
文件类似,不再赘述。
导入整个 src/packages
文件夹里的 jsx 文件
在 src/ReactApp.jsx
中编写以下代码:
/**
* @file ReactApp.jsx
* path: src/ReactApp.jsx
*/
import React from "react";
/** 模块上下文,获取 src/packages/ 文件夹下所有的 jsx 文件 */
const context = require.context("./packages", true, /\.jsx$/);
/** 组件包 */
const packages = context.keys().map((key) => context(key).default);
export default function ReactApp() {
return (
<section>
<h2>React Components!</h2>
{packages.map((Component) => (
<Component key={Component.name} />
))}
<p>packages 文件夹下所有组件的名称为:{packages.map((v) => v.name).join(",")}</p>
</section>
);
}
这样 src/ReactApp.jsx
组件就可以渲染所有 src/packages/
文件夹下的内容了。
参考: