Webpack+TypeScript如何配置别名全局引入根目录framework模块
我当前使用 Webpack、TypeScript、HTML 与 SCSS 搭建单页应用项目,项目路由存放在根目录的 /framework/ 文件夹下,所有业务源码存放于 /src/ 目录。
目前在深层子目录文件(例如 /src/pages/home/index.ts)中引入 framework 模块时,必须书写冗长的多层相对路径:
import * as framework from '../../../framework/';
我希望能免去这类繁琐的相对路径写法,参考过相关方案尝试后均未生效,先后做过两次配置尝试:
已尝试的无效方案
方案1:配置 Webpack resolve 别名 + ProvidePlugin
在 webpack.dev.config.js 中添加如下配置:
// File: /webpack.dev.config.js resolve: { alias: { framework: path.resolve(__dirname, './framework') // 构建或重启dev-server时,如果路径错误会直接抛出报错 } }, devtool: 'inline-source-map', plugins: [ new HtmlWebpackPlugin(), new webpack.ProvidePlugin({ framework: [path.resolve(path.join(__dirname, 'framework')), 'framework'] }) ],
该配置没有实现预期的路径简化效果。
方案2:在入口文件挂载全局变量
在 /src/index.ts 中尝试将 framework 路径挂到全局:
// File: /src/index.ts const path = require('path'); global.fw = String(path.resolve(__dirname, "framework"));
该写法在 TypeScript 环境下直接抛出类型错误:
fs: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.ts(7017)
需求
需要可行的落地方案,实现以下任意一种引入效果即可:
- 类似
import * as framework from '@framework';的别名引入 - 类似
import * as framework from '@framework/main';的带子路径别名引入 - 配置为可全局直接调用的 framework 变量
要实现别名引入,必须同时配置 Webpack 解析规则和 TypeScript 路径解析规则,之前方案失效的核心原因是只配了 Webpack,TS 侧找不到对应模块声明,具体配置步骤如下:
1. 修正 Webpack 别名配置
首先调整 webpack.dev.config.js 里的 resolve 别名,建议别名统一加 @ 前缀避免和第三方依赖重名,同时删掉不必要的 ProvidePlugin 配置(ProvidePlugin 是用来自动加载模块、无需手动 import 的,不是用来做路径别名的):
// webpack.dev.config.js const path = require('path'); module.exports = { // 其他原有配置... resolve: { alias: { '@framework': path.resolve(__dirname, 'framework/'), // 别名指向根目录framework文件夹 // 如果需要简化src目录下的引入路径也可以加别名,可选 '@': path.resolve(__dirname, 'src/') }, // 自动解析的文件扩展名,按项目实际需要配置 extensions: ['.ts', '.js', '.scss', '.json'] }, plugins: [ new HtmlWebpackPlugin(), // 删掉之前写的framework相关ProvidePlugin配置 ] }
注意:如果生产环境用了单独的 webpack 配置文件(比如 webpack.prod.config.js),需要把同样的 resolve 别名配置同步过去,否则生产构建会报模块找不到。
2. 配置 TypeScript 路径映射
打开项目根目录的 tsconfig.json,在 compilerOptions 下添加 paths 配置,让 TS 能识别别名对应的路径:
{ "compilerOptions": { // 其他原有配置... "baseUrl": "./", // 必须配置baseUrl,paths是相对于baseUrl解析的 "paths": { "@framework/*": ["framework/*"], // 匹配@framework/xxx的引入,映射到根目录framework/xxx "@framework": ["framework/index.ts"] // 匹配直接引入@framework的情况,指向framework的入口文件 } } }
配置完之后重启 TS 服务和 Webpack devServer,就可以直接用目标写法引入了:
// 不管文件在多深的src子目录,都可以直接写 import * as framework from '@framework'; // 引入framework下的子模块 import mainModule from '@framework/main';
3. 如果需要全局变量方案(不推荐,优先用别名引入)
如果确实要配置全局可直接调用的变量,不要自己往global上挂属性,分两步配置:
- 修正 Webpack ProvidePlugin 的配置写法,实现模块自动注入:
new webpack.ProvidePlugin({ framework: path.resolve(__dirname, 'framework/index.ts') }) - 在项目的全局类型声明文件(一般是
src/global.d.ts,没有就自己新建一个)里声明全局变量类型,解决TS类型报错:
配置完之后不需要手动import,所有文件里可以直接用// 先引入framework的类型 import type * as FrameworkModule from '@framework'; declare global { const framework: typeof FrameworkModule; } export {}framework.xxx调用对应方法。
内容的提问来源于stack exchange,提问作者FortyGazelle700

