Specify a root path for imports? - vue.js

I'm converting my ongoing Vue.js app over to use vue-cli/Webpack and imported modules Something I'm finding rather tedious at the moment is specifying the relative paths for imports accurately. E.g. import bus from '../../bus', import Cell from '../Cell'. Easy to make a mistake.
I'm assuming it must be straightforward enough to specify a base or root directory and specify absolute paths from that, but I can't see where one would do that. For example, in the standard vue-cli webpack setup, the code I'm working on is all in the 'src' directory, inside which I have 'components', 'mixins', etc. It would be handy if I could use import xxx from 'components/xxx', import yyy from 'components/a/yyy'. How would I do that?

With vue-cli, you put webpack settings in vue-config.js, in the same folder as package.json.
vue-config.js:
var path = require('path')
module.exports = {
configureWebpack: {
resolve: {
alias: {
src: path.resolve(__dirname, 'src')
}
},
}
}
This will allow you to do
import HelloWorld from 'src/components/HelloWorld.vue'
instead of
import HelloWorld from '../components/HelloWorld.vue'
See https://cli.vuejs.org/config/#vue-config-js for more info.

The solution is already in place, in fact, just not well-documented. In webpack.base.conf.js, there is this:
resolve: {
extensions: ['', '.js', '.vue', '.json'],
fallback: [path.join(__dirname, '../node_modules')],
alias: {
'vue$': 'vue/dist/vue.common.js',
'src': path.resolve(__dirname, '../src'),
'assets': path.resolve(__dirname, '../src/assets'),
'components': path.resolve(__dirname, '../src/components')
}
}
I've added my own alias, 'mixins': path.resolve(__dirname, '../src/mixins'). So I can now use e.g. import Field from 'mixins/Field', along with e.g. import ScrollableTable from 'components/ScrollableTable'.

I am using laravel and the laravel-mix package.
To make it work add this to your webpack.mix.js :
const path = require('path');
mix.webpackConfig({
resolve: {
alias: {
'#': path.resolve(__dirname, 'resources/js')
},
},
});

You can use something like this:
import { routes } from '#/router/routes'
where /router folder is on the root of my project and I can import my routes anywhere :)
Note: I'm using VueJS 2.0

Create a vue.config.js file at the project root that will contain
var path = require('path');
module.exports = {
configureWebpack : {
resolve: {
modules : [
path.resolve("./src"),
path.resolve("./node_modules")
]
},
}
}

Just use # symbol as root in the path for the import.
For example, let's say you have a firebase folder under root and a firebaseConfig.js
file like this
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "...somekey...",
authDomain: "...someApp....firebaseapp.com",
databaseURL: "https://...someApp....firebaseio.com",
projectId: "...someProjId...",
storageBucket: "",
...bla bla bla...
};
export default firebaseConfig;
in the firebase folder.
You can import the config file anywhere using the following instruction:
import firebaseConfig from '#/firebase/firebaseConfig'

Late answer: To create an alias for all folders inside src. Uses Damian Helme solution. All credits should go to him.
Allows you to import:
import HelloWorld from 'components/HelloWorld.vue'
From:
import HelloWorld from '../components/HelloWorld.vue'
Create vue.config.js on the root folder of the project. Note: Doesn't automatically update when new folders are created, you will need to manually restart.
const path = require('path');
const fs = require('fs');
//Find all files in src and make alias
const dirs = fs.readdirSync(path.resolve(__dirname, 'src'));
const alias = {
src: path.resolve(__dirname, 'src')
}
dirs.forEach(name => {
const filePath = path.resolve(__dirname, 'src', name);
//Only add folders
if (fs.statSync(filePath).isDirectory()) {
alias[name] = filePath;
}
});
module.exports = {
configureWebpack: {
resolve: {
alias
},
}
}

Create vue.config.js file on the root directory
const path = require('path');
module.exports = defineConfig({
configureWebpack: {
resolve: {
alias: {
src: path.resolve(__dirname, 'src')
}
}
}
})
Once after done with the configuration. We can now able to target the file inside src directory using below import statement.
import About from src/component/About.vue
If you have another main folder inside the src directory. You can achieve by using the below command.
package: path.resolve(__dirname, 'src/package')

Related

Add script into HTML using vite and vue 3

I have one js file which needs to be put in the public directory and needs to add it in the final production build as a text/javascript.
I have checked the options in vite config but couldn't find anything useful. The files I add contain a global JSON object and can be accessed directly.
To achieve this, I tried this solution.
vite.config.ts
import { fileURLToPath, URL } from "url";
import path from 'path';
// import test from "./src/assets/test.js"
import test from "./public/test.js"
import { defineConfig , loadEnv} from "vite";
import vue from "#vitejs/plugin-vue";
import { loadingScript } from 'vite-plugin-loading-script'
export default defineConfig(({ command, mode }) => {
// Load env file based on `mode` in the current working directory.
// Set the third parameter to '' to load all env regardless of the `VITE_` prefix.
const env = loadEnv(mode, process.cwd(), '')
return {
// vite config
define: {
__APP_ENV__: JSON.stringify(env.VITE_REDIRECT_URL),
__TEST__: test,
},
plugins: [vue()],
server: {
hmr: {
overlay: false,
},
},
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
},
build: {
// rollupOptions: {
// external: ['__APP_ENV__'],
// output: {
// globals: {
// __APP_ENV__: JSON.stringify(env.VITE_REDIRECT_URL),
// }
// }
// }
}
}
});
test.js
export default {
REDIRECT_URL: "https://example.com/",
API_URL: "https://example.com/",
};
with the above changes, I got the console.log('__TEST__', __TEST__) as expected JSON object but it doesn't work with the production build.
maybe you can try including the js file to the html in the public directory

ISO proper way to chain Webpack via vue.config.js to add global .scss imports to my .vue files (vue-cli-plugin-nativescript-vue)

I have Vue.js project I've setup previously that dynamically adds defined .scss files to my .vue template files, so I can access my variables, mixins, etc. in the templates without #importing them, or having them duplicate code from imports.
My problem is I'm setting up a NativeScript/Vue.js project with vue-cli-plugin-nativescript-vue and was curious if anyone has successfully setup their webpack to allow the same functionality. It's my understanding that the plugin replaces webpack with the latest when you run, as specified in the docs https://cli.vuejs.org/guide/webpack.html#replacing-loaders-of-a-rule.
Below is my vue.config.js (which compiles with no error) but doesn't seem to be working. I'm probably missing something or don't understand exactly how this is working, any help is appreciated.
const path = require('path')
module.exports = {
chainWebpack: config => {
const ofs = ['vue-modules', 'vue', 'normal-modules', 'normal']
const cssRules = config.module.rule('css')
const postRules = config.module.rule('postcss')
const addSassResourcesLoader = (rules, type) => {
rules
.oneOf(type)
.use('sass-resoureces-loader')
.loader('sass-resources-loader')
.options({
resources: './src/styles/_global.scss', // your resource file or patterns
})
}
ofs.forEach(type => {
addSassResourcesLoader(cssRules, type)
addSassResourcesLoader(postRules, type)
})
return config
},
}
Vue CLI provides a config to augment your CSS loaders:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
scss: {
// sass-loader#^8.0.0
prependData: `import "~#/styles/_global.scss";`,
// sass-loader#^9.0.0 or newer
additionalData: `import "~#/styles/_global.scss";`,
}
}
}
}

Babel aliases. WebStorm doesn't recognize sub-directories

I recently moved from webpack path aliases to babel-plugin-module-resolved as it integrates better with testing frameworks.
.babelrc
{
"presets": [
["env", { "modules": false } ],
"react",
"stage-2",
"flow"
],
"plugins": [
["module-resolver", {
"alias": {
"static": "./static",
"common": "./src/common",
"data": "./src/data"
}
}],
["styled-jsx/babel", { "plugins": ["styled-jsx-plugin-sass"] }],
"react-hot-loader/babel"
]
}
WebStorm automatically recognizes imports for static/.. but can't resolve imports like common/.. and data/...
Is it possible to somehow instruct IDE about this configuration?
P.S. Right now I have src directory marked as Resource Root but this doesn't quite work as well.
One option I've taken is to create a fake webpack file that creates the same aliases. Leaves an unnecessary file in your codebase, but fixes all the name resolution issues.
Example:
webpack.junk.js
module.exports = {
resolve: {
alias: {
'static': path.resolve(__dirname, './static'),
'#common': path.resolve(__dirname, './src/common'),
'#data': path.resolve(__dirname, './src/data'),
},
},
};
Following SimplyComplexable's solution (I can't comment on his reply, sorry), I've create a new webpack.intellij.js that loads the project's webpack config (webpack.js), reads the .babelrc file to generates the resolve.alias section for the exported config, then explicitly pointed IntelliJ to this file in the preferences:
const path = require('path');
const fs = require('fs');
const { merge } = require('webpack-merge');
const webpackConfig = require('./webpack.js');
const babelRc = JSON.parse(fs.readFileSync('./.babelrc').toString('utf8'));
const aliases = {};
for (let i = 0; i < babelRc.plugins.length; i+=1) {
if (Array.isArray(babelRc.plugins[i]) &&
babelRc.plugins[i][0] === 'module-resolver') {
const a = babelRc.plugins[i][1].alias;
for (const entry of Object.entries(a)) {
aliases[entry[0]] = path.resolve(__dirname, entry[1]);
}
}
}
module.exports = merge(webpackConfig, {
resolve: {
alias: aliases
}
});
This solution allows me to have the aliases configured in one single place (.babelrc) while still having IntelliJ recognise them :)

Why are my js files being loaded as `index.html` instead of the actual js files created by webpack?

I'm creating a simple build from webpack, using typescript, jade, and stylus. When the final index.html file is spit out, however, it seems to think the js files are just the index.html file and not the actual js files bundled up by webpack and dynamically inserted at the bottom of the html body.
My project directory structure looks like this:
- dist (compiled/transpiled files)
- server
- dependencies
- index.js
- app.js
- app.[hash].js
- polyfills.[hash].js
- node_modules
- src
- server
- dependencies
- index.ts
- app.ts
- client (ng2 ts files)
- index.jade
This is my webpack build:
'use strict';
const webpack = require('webpack');
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const WebpackShellPlugin = require('webpack-shell-plugin');
const rootDir = __dirname;
/**
* Resolve paths so that we don't have to use relative paths when importing dependencies.
* Very helpful when scaling an application and changing the location of a file that my require another file
* in the same directory as the one it used to be in
*/
const pathResolves = [path.resolve(rootDir, 'src'), path.resolve(rootDir, 'node_modules')];
console.log('path', path.resolve(rootDir, 'src/server'));
module.exports = {
entry: {
'app': path.resolve(rootDir, 'src/client/main.ts'),
'polyfills': [
'core-js/es6',
'core-js/es7/reflect',
'zone.js/dist/zone'
]
},
output: {
path: path.resolve(rootDir, 'dist'),
filename: '[name].[hash].js'
},
module: {
rules: [
{
test: /\.component.ts$/,
use: [
{
loader: 'angular2-template-loader'
},
{
loader: 'ts-loader',
options: {
configFileName: path.resolve(rootDir, 'tsconfig.client.json')
}
}],
include: [path.resolve(rootDir, 'src/client')]
},
{
test: /\.ts$/,
use: [
{
loader: 'ts-loader',
options: {
configFileName: path.resolve(rootDir, 'tsconfig.client.json')
}
}
],
exclude: /\.component.ts$/
},
{
test: /\.jade$/,
use: ['pug-ng-html-loader']
},
{
test: /\.styl$/,
use: [
{ loader: 'raw-loader' },
{ loader: 'stylus-loader' }
]
}
]
},
resolve: {
extensions: ['.js', '.ts', '.jade', '.styl'],
modules: pathResolves
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'polyfills'
}),
new HTMLWebpackPlugin({
template: path.resolve(rootDir, 'dist/index.html')
}),
/**
* Define any environment variables for client
*/
new webpack.DefinePlugin({
APP_ENV: JSON.stringify(process.env.APP_ENVIRONMENT || 'development')
}),
/**
* This plugin is required because webpack 2.0 has some issues compiling angular 2.
* The angular CLI team implemented this quick regexp fix to get around compilation errors
*/
new webpack.ContextReplacementPlugin(
/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
'./'
)
]
};
And finally, this is the src/server/app.ts file that serves up index.html:
import * as express from 'express';
import * as fs from 'fs';
import * as morgan from 'morgan';
import {
Config
}
from './dependencies/config';
export
function app(Container) {
const app = express();
const config: Config = Container.get(Config);
if (config.log.dev) {
app.use(morgan('combined'));
}
app.get('/', (req: express.Request, res: express.Response) => {
const indexPath: string = `dist/index.html`;
const encodeType: string = `utf-8`;
const html = fs.readFile(indexPath, encodeType, (err: Error, result: string) => {
if (err) {
return res.status(500).json(err);
}
return res.send(result);
});
});
return app;
}
The browser console shows the following 404 error messages (they're red in the browser console) when i go to localhost:3000:
GET http://localhost:3000/polyfills.9dcbd04127bb957ccf5e.js
GET http://localhost:3000/app.9dcbd04127bb957ccf5e.js
I know it's supposed to be getting the js files from dist/[file].[hash].js, but can't seem to make it work with webpack. Also, I should note that I set NODE_PATH to ./ in my gulp nodemon config. Any ideas why this isn't working?
Figured it out on my own. Forgot to add app.use(express.static('dist')) middleware to the app.ts file.

How would I import a module within an npm package subfolder with webpack?

Lets say theres a package in node_modules called foo and I want to import a module within a library such as foo/module via webpack & babel...
import Foo from 'foo'; works
import SomeOtherModule from 'foo/module'; fails with the following:
Module not found: Error: Cannot resolve module 'foo/module' in
/Users/x/Desktop/someproject/js
Which makes make it seem like webpack is looking for the file in the wrong place instead of node_modules
My webpack.config looks like this:
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: ['babel-polyfill','./js/script.js'],
output: {
path: __dirname,
filename: './build/script.js'
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
cacheDirectory: true,
presets: ['es2015']
}
}
],
},
plugins: [
new webpack.NoErrorsPlugin()
],
stats: {
colors: true
},
devtool: 'source-map'
};
It should work with import 'foo/module';. It will resolve file ./node_modules/foo/module.js or ./node_modules/foo/module/index.js and not something like ./node_modules/foo/node_modules/module/index.js if it expected (in that case you better to install module via npm).
You can define a custom path using the module attribute in your package.json. Example:
{
...
"module": "dist/mylib.min.js",
...
}
See What is the "module" package.json field for?