427

I'm starting out a new vue.js project so I used the vue-cli tool to scaffold out a new webpack project (i.e. vue init webpack).

As I was walking through the generated files I noticed the following imports in the src/router/index.js file:

import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello' // <- this one is what my qusestion is about

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/',
            name: 'Hello',
            component: Hello
        }
    ]
})

I've not seen the at sign (@) in a path before. I suspect it allows for relative paths (maybe?) but I wanted to be sure I understand what it truly does.

I tried searching around online but wasn't able to find an explanation (prob because searching for "at sign" or using the literal character @ doesn't help as search criteria).

What does the @ do in this path (link to documentation would be fantastic) and is this an es6 thing? A webpack thing? A vue-loader thing?

UPDATE

Thanks Felix Kling for pointing me to another duplicate stackoverflow question/answer about this same question.

While the comment on the other stackoverflow post isn't the exact answer to this question (it wasn't a babel plugin in my case) it did point me in the correct direction to find what it was.

In in the scaffolding that vue-cli cranks out for you, part of the base webpack config sets up an alias for .vue files:

Alias location within project

This makes sense both in the fact that it gives you a relative path from the src file and it removes the requirement of the .vue at the end of the import path (which you normally need).

Thanks for the help!

Flip
  • 6,233
  • 7
  • 46
  • 75
Chris Schmitz
  • 20,160
  • 30
  • 81
  • 137
  • 4
    [See my comment](http://stackoverflow.com/questions/42711175/what-does-the-symbol-do-in-javascript-imports#comment72543541_42711175). – Felix Kling Mar 12 '17 at 16:47
  • 4
    @FelixKling It is not an exact duplicate because it doesn't answer the whole question, *is this an es6 thing? A webpack thing? A vue-loader thing?* – Estus Flask Mar 12 '17 at 16:52
  • 1
    Yeah, I think the question was similar but not a duplicate. Regardless I figured out where it was coming from and updated the question with an explanation since I can't add it as an answer. – Chris Schmitz Mar 12 '17 at 16:56
  • 1
    @estus: the answer makes it pretty clear that it isn't part of ES6 but a webpack configuration thing, don't you think? And that's exactly the case here as well, only that the nature of the configuration is a bit different. – Felix Kling Mar 12 '17 at 17:05
  • @FelixKling I believe when estus pointed out that there was still a question about what kind of a thing it is I had not yet added the update (I saw his comment come in as I was typing the update). I'm all set and there's a detailed explanation about my particular instance so I'm good to go. Thanks guys. – Chris Schmitz Mar 12 '17 at 17:08
  • I still believe this is a duplicate. If you want you could post your information over there as answer, or wait until this one is reopened. – Felix Kling Mar 12 '17 at 17:09
  • @FelixKling If the question is more narrow than a 'dupe' and has a chance to get more detailed answer, why should it be closed? It is obvious for me that it is Webpack thing, but the OP asked if it is specific to Vue loader or not. – Estus Flask Mar 12 '17 at 17:12
  • @estus: I understand your point. But isn't the whole point of having "more generic" questions/answeres for them to be applicable to more situations and therefore more questions could be closed as dupes of them? What's the point in repeating the same answer if only one sentence is different. What would you do if someone asks the question tomorrow: "What's the meaning of @ in an import in a FooBar project?" (where FooBar is another amazing library and webpack is used as module bundler)? – Felix Kling Mar 12 '17 at 17:28
  • 1
    @FelixKling It depends. But since the question you've linked doesn't have detailed answer that explains what's up with Webpack, it may probably deserve an answer. Usually having 'Possible duplicate of ...' comment is enough to designate the link between the questions, and vox populi does the rest. I've seen the questions being over-duped on SO too often. – Estus Flask Mar 12 '17 at 17:40

13 Answers13

370

This is done with Webpack resolve.alias configuration option and isn't specific to Vue.

In Vue Webpack template, Webpack is configured to replace @/ with src path:

  const path = require('path');

  ...
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      ...
      '@': path.resolve('src'),
    }
  },
  ...

The alias is used as:

import '@/<path inside src folder>';
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • 258
    JavaScript just isn't JavaScript anymore. Babel/webpack gives us this Frankenstein language and somehow new developers are meant to know where ECMAScript spec ends and userland plugins/transforms begin. It's really sad, imo. – Mulan Mar 13 '17 at 04:13
  • 3
    @naomik It's up to user to introduce such tricks into the setup or not. It's not a big deal for Vue since it relies on its custom .vue file format anyway. – Estus Flask Mar 13 '17 at 10:58
  • 29
    Personally I think the ability to add flexibility if you want it is a good thing. I see it less as frankenstein and more like voltron; you can do stuff as a lion or combine different lions together to have a bigger robot. Yeah, sometimes you get questions like this one, but it's not like the answers can't be found. Really, you can take the frankenstein or voltron view with any project of any size, it's just "using and understanding dependencies". – Chris Schmitz Mar 13 '17 at 14:39
  • 1
    @ChrisSchmitz It depends on the context and the perspective. Doing something like this will restrict the project to use Webpack. May be not a good thing if the project intends to use native ES6 modules when they will arrive, or it's Node where CommonJS can be used for modules. Long relative paths can be harder to maintain and refactor, on the other hand. – Estus Flask Mar 13 '17 at 14:49
  • Jeeze, this was happening a year ago. I'm just getting started and I'm wondering how far gone everything is. :P – LJD Dec 05 '18 at 00:44
  • Does this work for import assets? mean import a css file in the style section on a SFC vue file. – Phoeson Jan 03 '19 at 05:32
  • @Kevin This depends on your setup. Yes, this may work for css as well. As it can be seen in the snippet, `extensions` option specifies extensions that are affected. – Estus Flask Jan 03 '19 at 10:38
  • Set an alias for asset folder works for me, e.g: 'assets': resolve('src/assets'), so I can import like this: @import "~assets/css/iconfont.css"; – Phoeson Jan 03 '19 at 10:55
  • 8
    When using `vue-cli` v3+ you should use `~@` to reference `src` folder. E.g.: `$font-path: '~@/assets/fonts/';` – Consta Gorgan Jan 25 '19 at 23:18
  • @AnthonyWinzlet The link seems to be wrong, it refers to this post. – Estus Flask Apr 05 '19 at 07:14
  • @estus oops. Apologies here it is https://stackoverflow.com/questions/55509973/how-to-define-socket-variable-globally – Ashh Apr 05 '19 at 07:15
  • @AnthonyWinzlet This question is unrelated, though I was able to answer it, so I've tried to do this. – Estus Flask Apr 05 '19 at 07:32
  • @estus I cannot find this file in my project. Is a global configuration? Where can I find (and change it)? – Ahmad Shahwan May 14 '19 at 20:00
  • @AhmadShahwan Webpack configuration is stored by default in webpack.config.js, but this may differ depending on a project. – Estus Flask May 14 '19 at 23:08
  • Thank you @estus. After searching, I think that the webpack.config.js used is the one shipped in vue-cli package, and is loaded by its service. – Ahmad Shahwan May 15 '19 at 12:50
  • 1
    @AhmadShahwan If you're using vue-cli then that's true. You can access webpack.config.js directly by ejecting the project but you likely don't need to do that, see https://cli.vuejs.org/guide/webpack.html – Estus Flask May 15 '19 at 12:58
  • does this also apply to the *.js files in a new vue project or only .vue files? – Tallboy Sep 06 '20 at 16:43
  • @Tallboy Yes, to all script files. You can see this here, https://github.com/vuejs-templates/webpack/blob/1.3.1/template/build/webpack.base.conf.js#L35-L41 – Estus Flask Sep 06 '20 at 16:49
  • Question, why we need to use ```@``` when we can use ```src``` directly? What's the advantages of this extra layer of functionality? – Duke Oct 20 '20 at 10:12
  • 1
    @RintoGeorge To avoid relative paths in imports, it's `@/lib/foo` instead of `../../../lib/foo`. `@` is the shortest name and doesn't collide with NPM packages. Doing the same thing for `src/lib/foo` absolute path is an extra layer too because it's not standardized and depends on a setup similarly to `@` (also there's certainly a package of the same name). – Estus Flask Oct 20 '20 at 10:28
  • Can I usually replace @/ with ./ ? Is there any difference ? –  Apr 10 '23 at 18:51
  • @AlexanderFilippovich The difference is that ./ is relative path, and aliased one is absolute. You use an alias if you don't want ../../../... paths and don't want to refactor them when module location is changed – Estus Flask Apr 10 '23 at 18:54
35

Also keep in mind you can create variables in tsconfig as well:

"paths": {
  "@components": ["src/components"],
  "@scss": ["src/styles/scss"],
  "@img": ["src/assests/images"],
  "@": ["src"],
}

This can be utilized for naming convention purposes:

import { componentHeader } from '@components/header';
Tyler Canton
  • 571
  • 6
  • 14
  • But this kind of alias will be left bare in the source JS and then at run-time you'll need to have a wrapper intercede to make the alias work. Maybe there's a way via babel for this TS syntax to get converted at build time? With Typescript's `tsc` is does not and therefore you'll need something like `module-alias` or `tsconfig-paths`. – ken May 27 '20 at 22:55
  • 1
    after I add this settings, vs code can not reslove path and cannot go into the file when click the impored module. – JackChouMine Oct 16 '21 at 07:19
  • In what file do I usually need to define the "paths" Object ? –  Apr 10 '23 at 18:57
5

I get over with following combination

import HelloWorld from '@/components/HelloWorld'
=>
import HelloWorld from 'src/components/HelloWorld'

IDE will stop warning the uri, but this causes invalid uri when compile, in "build\webpack.base.conf.js"

resolve: {
  extensions: ['.js', '.vue', '.json'],
  alias: {
    'src': resolve('src'),
  }
},

Bingoo!

3

Maybe try adding in webpack. mix.webpackConfig references laravel mix.

mix.webpackConfig({

    resolve: {
        alias: {
            '@imgSrc': path.resolve('resources/assets/img')
        }
    }
});

And then in vue use.

<img src="@imgSrc/logo.png" />
Paul
  • 129
  • 5
2

resolve('src') no works for me but path.resolve('src') works

resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': path.resolve('src')
    },
    extensions: ['*', '.js', '.vue', '.json']
  },
1

Something must have changed. The answer given here is no longer correct. This project in Chapter09 uses the @ sign in its import statements but the webpack.config.js file doesn't have a path resolve statement:

let service = process.VUE_CLI_SERVICE

if (!service || process.env.VUE_CLI_API_MODE) {
  const Service = require('./lib/Service')
  service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
  service.init(process.env.VUE_CLI_MODE || process.env.NODE_ENV)
}

module.exports = service.resolveWebpackConfig()
Dean Schulze
  • 9,633
  • 24
  • 100
  • 165
1

A similar approach used in Vue3 and Vite, the alias can be found in vite.config.js

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(),vueJsx()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
});
Trey
  • 11
  • 4
0

An example to apply in Next.js would be to use the file next.config.js to add the next content.

const path = require('path');

module.exports = {
  webpack: (config, options) => {
    config.resolve.alias = {
      '@': path.resolve(process.cwd(), 'src'),
    };
    return config;
  }
};
0

It refers to an alias path found in your config.js file

jocoio
  • 1
  • 2
  • 2
    Hey @jocoio, thanks for hopping in and adding an answer. It's always awesome to see new contributors looking to help! A bit of help from my end: your answer is correct, but to be more helpful for people who come across it you could provide more explanation and context. Check out the other answers to the question here. there are lots of great examples to go by. Thanks again for chipping in – Chris Schmitz Dec 09 '22 at 02:04
0

@ refers to the src folder inside your root directory, it can be configured while bootstrapping your app.

0

We sometimes use '@' to import from a components directory with a path "src/components/Add.vue". If we need to access this file from a diff directory like "src/views/AboutView.vue", we can use this to import Add.vue inside AboutView.vue as import Add from "@/components/Add.vue", inside your tag. This is the same as using import Add from "../components/Add.vue" '@' points to the root directory of your app(src folder)

0

In simple words, the "@" symbol is used as "src" when importing files/components.

I have configured my webpack.common.js file like below

resolve: {
  extensions: [".ts", ".js", ".vue"],
  alias: {
      '@': path.resolve(__dirname,'src/')
  }
}

I have imported the vuex store like this import store from "@/store"; instead of import store from "../store"

You can read more about Webpack Aliases in Vue here

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
batSDK
  • 11
  • 1
  • 2
-2

import { createApp, markRaw } from "vue";

import { createPinia } from "pinia";

import App from "./App.vue";

import router from "./router";

// import "./assets/main.css";

const app = createApp(App);

const pinia = createPinia()

pinia.use(({ store })=>{ store.$router = markRaw(router) })

app.use(pinia);

app.use(router);

app.mount("#app");

Madkday
  • 1
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 08 '23 at 14:45