Using the 'gf' command in Vim to resolve JavaScript modules with a Webpack tilde alias

Recently, I joined a Vue.js project that makes use of the tilde (~) notation in module imports. For example:

import WhateverApi from '~/api/whatever';

The project repository is a mix of various files including a Vagrant machine setup, a Laravel backend application, configuration files, and a Vue.js single-page application (SPA). The SPA is located within a nested folder structure (resources/assets/js/) which is considered as the project root denoted by ~.

While using Vim, I noticed that when I try to jump to a linked file using the gf command with the path shown above, Vim throws an error indicating that the file does not exist. This could be due to Vim interpreting the tilde as the user's home folder.

After searching online, I couldn't find a solution mainly because I was unsure of what exactly to look for. It seems like some sort of magic being done by Webpack. The other team members who use WebStorm/PHPStorm do not encounter this issue.

How can I configure Vim to correctly resolve the path within the project's scope?

Update with an example:

Webpack provides an alias setting, allowing the definition of custom paths to be used as aliases in source code files. Here's an example configuration:

resolve: {
    alias: {
        vue$: 'vue/dist/vue.esm.js',
        '~': path.resolve(__dirname, 'resources/assets/js'),
        sass: path.resolve(__dirname, 'resources/assets/sass'),
    },
    extensions: ['*', '.js', '.vue', '.json'],
},

Ignoring the $vue key specific to Vue.js with Webpack, focus on ~ and sass. These act as substitute filters replacing every occurrence of ~ in paths with resources/assets/js and resources/assets/sass, respectively. However, import statements vary. Below is an example of a Vue single file component with both types of import statements:

<template>
    <div>
        <p>Some content.</p>
    </div>
</template>

<script>
    import WhateverApi from '~/api/whatever';

    export default {};
</script>

<style lang="scss" scoped>
    @import '~sass/variables/all';
</style>

It would be helpful if Vim could resolve these combinations using the following rules while using gf:

  • Paths starting with ~/ should replace ~ with resources/assets/js and attempt to locate files with extensions .js, .vue, and .json.
  • Paths starting with ~sass should replace ~ with resources/assets/sass and attempt to find files with the extension .scss.

I understand this may be complex and was implemented before my joining the team. There is a project aimed at simplifying this process (https://github.com/davidosomething/vim-enhanced-resolver), but it seems to be broken as it throws errors when attempting to resolve existing paths.

Any assistance provided will be greatly appreciated.

Answer №1

After searching online, I came up empty-handed because I'm not sure exactly what to look for.

If you're seeking help with Vim, it's best to start by consulting the Vim help documentation itself. For instance, if you're using the gf command, refer to the help section for gf to understand its functionality:

:h gf
[count]gf       Edit the file whose name is under or after the cursor.
                Mnemonic: "goto file".
                Uses the 'isfname' option to determine valid characters in a file name. Trailing punctuation characters such as ".,:;!" are disregarded. Escaped spaces "\ " are condensed to a single space.
                The 'path' option provides directory names to search for the file. More information on relative directories and wildcards can be found in the 'path' option details.
                Suffixes added to file names are checked with the 'suffixesadd' option.
                <b>If the file is not located, 'includeexpr' adjusts the name for another attempt.</b>

Additionally, you may want to explore :h 'includeexpr'. For instance, this expression will replace an initial ~ with resources/assets/js:

set inex=substitute(v:fname,'^\\~','resources/assets/js','')

Answer №2

Thanks to some guidance from sidyll, I finally got this code working after a lot of trial and error and consulting instructional resources. The key components include using recursive substitute() functions, regex capture groups, and the suffixesadd command:

set includeexpr=substitute(substitute(v:fname,'^\\~\/','resources/assets/js/',''),'^\\~sass/\\(.*\\)/\\(.*\\)$','resources/assets/sass/\\1/_\\2','')
set suffixesadd=.js,.vue,.scss

Although it may not be the most elegant solution, this is just how Vimscript tends to be.

Answer №3

One way to handle project paths in Vim is by using the substitude and includeexpr method, although it's not the most efficient solution.

I recently discovered the plugin vim-npr, which has made managing project paths a breeze for me.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Updating a MongoDB document using only the data from checked checkboxes

Imagine having data structured like this: _id:60e2edf7014df85fd8b6e073 routineName:"test" username: "tester" monday:[{ _id: 60e430d45395d73bf41c7be8 exercise: "a" }{ _id: 60e4329592e ...

The conundrum of nested function wrapping in Typescript and its impact on

Upon calling the following function, it returns a Promise<boolean>: const fnc = (i:number) : Promise<boolean> => Promise.resolve(true) // Promise<boolean> const res1 = errorHandler(errorPredicates.sdkError1, fnc, null, 4); However, ...

Tips for utilizing html2canvas for printing a website page

Looking to replicate the on-screen appearance of my webpage when printing? I stumbled upon a helpful script called html2canvas: Check out how I implemented it below. Encountering 2 issues: After clicking the print button in Chrome, the print dialog app ...

Is it feasible to package shared modules into individual files using Browserify?

In my web app, I am using Browserify, Babel, and Gulp to bundle my scripts into a single file. However, when I checked the file size, it was over 3MB which seems excessive to me. Although I'm not entirely sure how Babel and Browserify modify my sourc ...

Guide on how to display registration form data on the current page as well as on a separate page

I am facing an issue with outputting registration form data to two different pages after successful validation. Specifically, I want the form data to be displayed on both the current page (form.php) and another page (profile.php). Despite my efforts to fin ...

Using an arrow function to assign a value to a variable

I have a quick question as I'm still learning arrow functions. I understand that they implicitly return, and we can use implicit returns with expressions. However, my question is about the following scenario: $scope.setEdit = () => { $scope.edit = ...

React-dnd supporting multiple draggable and droppable elements

I am facing a challenge with making multiple elements draggable using react-dnd. I have an array of 4 fields that I would like to make draggable, but when I map through the array and give each element a className of 'element', they do not move as ...

Manipulate the DOM elements within the ng-repeat directive

Hello, I am currently new to AngularJS and have just begun learning how to create directives. While working on a sample project, I encountered an issue with accessing DOM elements rendered inside my directive. Some elements were not accessible in the link ...

Retrieve the HTML data and save it as page.html, displayed in a VueJS preview

After developing an innovative VueJS-based application for managing front-end content, I am now eager to enhance it with a 'download' button feature. This new functionality will allow users to easily download the previewed and edited content in H ...

Cloud function for Firestore to recursively update a subcollection or collection group

I've been working on this cloud function: import pLimit from "p-limit"; const syncNotificationsAvatar = async ( userId: string, change: Change<DocumentSnapshot> ) => { if (!change.before.get("published") || !change.after.exists) { ...

Numerous obj elements simultaneously loaded within a single viewport

My goal is to incorporate multiple obj models into separate scenes, following the concept from webgl_multiple_elements.html. I have successfully loaded a single obj file and now want to add it to each individual scene. Although the obj file loads without ...

Why does the return value of a function in Node.js and JavaScript sometimes appear as undefined?

I am completely stumped by this issue. I've been trying to figure it out, but so far, no luck.. this is the code snippet function part1(sql, controltime, headers_view, results_view, tmp){ var timerName = "QueryTime"; var request = ne ...

Ensure to utilize object identities while employing QUnit.deepEqual() with an array

Let's set the scene: I have a function that returns an array of objects. These objects do not have any enumerable properties, but are sourced from a common cache or store. In my test cases, I want to verify if the contents of the returned array are a ...

Achieving consistent text alignment in HTML and CSS without relying on tables

As I delve into the world of HTML and CSS, I've taken a traditional approach by crafting a login page complete with three input controls (two text inputs and one button). To ensure proper alignment of these elements, I initially turned to the trusty & ...

When ts-loader is used to import .json files, the declaration files are outputted into a separate

I've encountered a peculiar issue with my ts-loader. When I import a *.json file from node_modules, the declaration files are being generated in a subfolder within dist/ instead of directly in the dist/ folder as expected. Here is the structure of my ...

Just running JavaScript code repeatedly in a loop

After running this script, I observed that there are 20 repetitions of the <button> tags. <?php for ($i = 1; $i <= 20; $i++) { ?> <button id="btn-<?php echo $i;?>">Button<?php echo $i;?></button> <script t ...

Utilize "Occasion" alongside a different variable

Trying to pass the id received by the uploadFile function to the progressHandler function, while still needing the "event" to work. Struggling to make it happen, can someone provide assistance? function uploadFile(arquivo, id) { alert(id) ...

Firebase Error: Trying to access properties of null object (indexOf)

Whenever I try to console.log(docSnap), a Firebase error shows up as seen in the image below. Despite attempting various solutions, none have proved effective. https://i.sstatic.net/9R4vE.png useEffect(() => { if (folderId === null) { ...

Steps for Setting Up and Organizing a Fresh Event

My goal is to generate new events (using document.createEvent() or Jquery.Event) by duplicating all essential attributes, and then sending the clone to prevent alterations to the original event. For reference, the source code can be found at http://jsfid ...

Events not appearing on Vue.js Vuetify Calendar

I am having some issues with my vue.js vuetify calendar. While I can successfully change the display type based on the property 'type', I am struggling to show day events in the calendar. Despite following this example, my calendar does not disp ...