Part 8: 使用模块的Alias别名来增强Jest的可配置度
Enhance Jest configuration with Module Aliases
使用模块的Alias别名来增强Jest的可配置度
Learn how to use Module Aliases Jest configuration to avoid using relative paths.
学习如何用模块别名来配置Jest,这样可以避免使用相对地址。
The module managers we have in the JavaScript community, mainly ES Modules and CommonJS, don’t support project-based paths. They only support relative paths for our own modules, and paths for the node_modules folder. When a project grows a bit, it’s common to see paths such:
在Js社区内我们可以用的模块管理工具,比如ES模块化或者CommonJS,都不太支持基于项目目录的路径,而是仅支持我们自己模块的相对路径,以及node_modules文件夹。如果项目结构越来越复杂,我们可能会看到如下长长的路径:
import SomeComponent from '../../../../components/SomeComponent'
Luckily, we have different ways to cope with this, in a way that we can define aliases for folders relative to the project root, so we could the above line like:
还好,我们有各种方法来应对这种情况,一种方法就是我们设置某些相对于根目录的文件夹的别名,就像上面的引用,就可以变为如下表示:
import SomeComponent from '@/components/SomeComponent'
The @ here is an arbitrary character to define the root project, you can define your own. Let’s see what solutions we have to apply module aliasing. Let’s start from where we left it on the last article.
这里的@符号是定义项目根目录的字符,你也可以定制自己想要的别名。来看一下我们如何设置模块别名,这就是我们最后一篇文章要讲的。
Webpack aliases
Webpack别名
Webpack aliases are very simple to set up. You just need to add a resolve.alias property in your webpack configuration. If you take a look at the build/webpack.base.conf.js, it already has it defined:
Webpack的别名设置非常简单。你只需要在配置文件中的resolve.alias
里设置,文件路径是build/webpack.base.conf.js
。
{
...
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
}
}
}
Taking this as an entry point, we can add a simple alias that points to the src folder and use that as the root:
以此为切入点,我们可以添加一些简单的别名,指向根目录中的src文件夹:
{
...
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': path.join(__dirname, '..', 'src')
}
}
}
Just with this, we can access anything taking the root project as the @ symbol. Let’s go to src/App.vue and change the reference to those two components:
这样设置以后,我们可以访问到任何资源通过@标识符。我们试着用新方法引用资源:
import MessageList from '@/components/MessageList'
import Message from '@/components/Message'
...
And if we run npm start and open the browser at localhost:8080, that should work out of the box.
如果我们启动npm的服务,打开浏览器访问localhost:8080
,可以发现之前的设置已经生效了。
However, if we try to run the tests by running npm t, we’ll see Jest doesn’t find the modules. We still didn’t configured Jest to do so. So let’s go to package.json where the Jest config is, and add "@/([^\\.]*)$": "<rootDir>/src/$1" to moduleNameMapper:
但是,如果我们尝试执行测试用例,运行npm t
后,我们可以看到Jest报错说没有找到相关模块。我们至今还没搞清楚为什么Jest不支持这种配置。为了解决这个问题,我们去package.json
中的Jest配置内容里添加一段代码:"@/([^\\.]*)$": "<rootDir>/src/$1" to moduleNameMapper:
"jest": {
"moduleNameMapper": {
"@(.*)$": "<rootDir>/src/$1",
"^vue$": "vue/dist/vue.common.js"
}
}
...
Let’s explain it:
让我解释下这段代码的用处:
@(.*)$
: Whatever starts with @, and continues with literally whatever ((.*)$)
till the end of the string, grouping it by using the parenthesis
@(.*)$
:无论什么路径,只要以@开头,并且后面以((.*)$)
结尾,这里使用括号对其进行正则分组。
<rootDir>/src/$1
: <rootDir>
is a special word of Jest, meaning the root directory. Then we map it to the src, and with 1 we append the whatever clause from the `(.*)` statement. `/src/1:其中
<rootDir>是Jest中的一个关键字,代表着根目录。然后我们映射到src目录,并且$1代表着与前文中
(.*)`匹配的分组。
For example, @/components/MessageList
will be mapped to ../src/components/MessageList when you’re importing it from the src or test folders.
例如,当我们引入src或者test文件夹中的资源时,@/components/MessageList
等价于../src/components/MessageList
。
That’s really it. Now you can even update your App.test.js
file to use the alias as well, since it’s usable from within the tests:
用法就是这样。现在我们可以用别名的方式更新App.test.js
文件了:
import { shallow } from "vue-test-utils"
import App from "@/App"
...
And it will work for both .vue and .js files.
这种方式对vue和js格式的文件都有效。
Multiple aliases
多个别名
Very often, multiple aliases are used for convenience, so instead of using just a @ to define your root folder, you use many. For example, let’s say you have a actions and models folder. If you create an alias for each one, and then you move the folders around, you just need to change the aliases instead of updating all the references to it in the codebase. That’s the power of module aliases, they make your codebase more maintainable and cleaner.
通常我们不会只用@来索引资源,我们可以设置多个别名来更方便的引入模块。举个例子,比如说你有一个actions和models的文件夹。如果你对他们分别设置别名,然后你挪动了文件夹,这时你只需要在配置文件中修改一次别名引用地址,就不用在代码中修复海量的引用地址的指向了。这就是模块别名的妙用。
Let’s add a components alias in build/webpack.base.conf.js
:
让我们在build/webpack.base.conf.js
中添加components文件夹的别名。
{
...
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': path.join(__dirname, '..', 'src')
'components': path.join(__dirname, '..', 'src', 'components')
}
}
}
Then, we just need to add it as well to the Jest configuration in package.json:
然后我们只需要package.json中再次添加一些配置:
"jest": {
"moduleNameMapper": {
"@(.*)$": "<rootDir>/src/$1",
"components(.*)$": "<rootDir>/src/components/$1",
"^vue$": "vue/dist/vue.common.js"
}
}
...
As simple as that. Now, we can try in App.vue to use both forms:
就这么简单。现在我们在App组件中试下这两种方式:
import MessageList from 'components/MessageList'
import Message from '@/components/Message'
Stop and re-run the tests, and that should work, as well as if you run npm start and try it.
不要反复试了,这两个方法都能生效。
Other solutions
其他解决办法
I’ve seen babel-plugin-webpack-alias, specially used for other testing frameworks such as mocha which doesn’t have a module mapper.
我已经调研过babel-plugin-webpack-alias
了,特别是用在其他测试框架中,比如mocha等不支持模块映射的框架。
I haven’t tried it myself, since Jest already gives you that, but if you have or wanna try, please share how it went!
我没有亲自试,因为Jest已经提供这些功能了,但是如果你还是想亲自尝试一下,可以给大家分享一下!
Conclusion
总结
Adding module aliases is very simple and can keep your codebase much cleaner and easier to maintain. Jest makes it as well very easy to define them, you just need to keep in in sync with the Webpack aliases, and you can say bye-bye to the dot-hell references.
添加模块别名非常简单,而且可以让你的代码简洁高效。Jest让我们很简便地定义别名,你只需要让Jest和Webpack同步别名的设置,你就可以跟见鬼的'点点式'引用说拜拜了!