Vuejs / NuxtJs include components from dynamically set directory - javascript

I am using NuxtJs / VueJs
I have a problem where by i need to set the path of a component dynamically. Why I hear you ask ?
Well I am creating a set of sites that will use the same basic codebase but only the look and feel will differ and thus for each domain want to load the components from the specific dir. The basic component names etc will remain the same just want to be able to change a few things which are beyond just some v-if statements in the component or css.
eg.
Site1: sites/mysite/HomePageHero.vue
Site2: sites/yoursite/HomePageHero.vue
Now i know about dynamic components but the problem there is i will have to add each sites components to the page every time i create a new site and i dont want to do that. So the more sites I create the bigger that list will get.
I just want to set the site name in the .env add the components to the dir and it all works (or something similar)
So if you take my code below , i need the DYNAMICHERE to be dynamic. There is probably something simple that I am missing.
import HomePageHero from '#/components/sites/DYNAMICHERE/HomePageHero'
Just for clarification as per the first response to this . I have tried doing the following which doesn't obviously work
import HomePageHero from '#/components/sites/' + process.env.THEME . + '/HomePageHero'

I finally got some time to play around with this and I fixed the problem which was best for my solution using the following code
I am using dotenv to define the env variables
const HomePageHero = () => import('#/components/sites/' + process.env.WEBSITE_NAME + '/HomePageHero');
Hattip to this article:
https://vuedose.tips/tips/dynamic-imports-in-vue-js-for-better-performance/
There still may be a cleaner solution but this works well for me.

If you are using laravel then you have 1 option: process.env.YOUR_SITE

This is what we're doing:
declare site names in package.json
use same name for mongodb
import components and use the one that matches mongodb process.env name
"scripts": {
"siteOne": "cross-env MONGO_DB=siteOne API_URL=http://localhost:3000 MONGO_URL=mongodb://localhost NODE_ENV=development nodemon server/index.js --watch server",
"siteTwo": "cross-env MONGO_DB=siteTwo API_URL=http://localhost:3000 MONGO_URL=mongodb://localhost NODE_ENV=development nodemon server/index.js --watch server",
"build_siteOne": "MONGO_DB=siteOne nuxt build",
"build_siteTwo": "MONGO_DB=siteTwo nuxt build",
"start": "node server/index.js",
},
<template>
<div class="footer">
<div class="container">
<component :is="footerComponent"></component>
</div>
</div>
</template>
<script>
import Footer_siteOne from '~/components/Footer_siteOne.vue';
import Footer_siteTwo from '~/components/Footer_siteTwo.vue';
export default {
components: {
Footer_siteOne,
Footer_siteTwo,
},
computed: {
footerComponent: function() {
return 'Footer_'+process.env.MONGO_DB;
}
}
}
</script>

Related

DevExtreme in Nuxt3 failing during build

I am trying to include DevExtreme UI components into Nuxt 3 project. I took basic Nuxt3 app generated via npx nuxi init nuxt-app and started with bending it.
This is my test component with very basic DevExtreme menu:
<template>
<div id="container">
<dxMenu>
<dxItem icon="home" />
<dxItem text="O aplikaci" />
<dxItem icon="key" />
</dxMenu>
</div>
</template>
<script lang="ts">
import DxMenu, { DxItem } from 'devextreme-vue/menu.js';
import { defineComponent } from 'vue'
export default defineComponent({
components: {
DxMenu, DxItem
}
})
</script>
Then I just render the component in my app.vue. I have no other configuration related to that (apart from importing DevExtreme css file via nuxt.config.ts).
My nuxt.config.ts looks just like this:
import { defineNuxtConfig } from 'nuxt'
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
css : [
'#/assets/css/dx.generic.zdd-scheme.css'
]
})
I was quite successful for dev environement - running npm run dev works like charm. But when I try npm run build it always fails.
The output looks like this:
i Client built in 11430ms 13:38:43
i Building server... 13:38:43
āˆš Server built in 4482ms 13:38:47
āˆš Generated public .output/public nitro 13:38:47
start Building server... nitro 13:38:47
ERROR Rollup error: Error: Cannot find module devextreme/ui/menu imported from file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/node_modules, file:///C:/ATOS_Projekty/ZDD/web-ui/app/,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/_index.js, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nuxt/node_modules/_index.js, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nitropack/node_modules/_index.js, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nitropack/node_modules
ERROR Error: Cannot find module devextreme/ui/menu imported from file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nitropack/node_modules, file:///C:/ATOS_Projekty/ZDD/web-ui/app/, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/_index.js, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nuxt/, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules/_index.js,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nitropack/, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/node_modules/_index.js,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/node_modules
at resolvePath (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/mlly/dist/index.mjs:1079:10)
at _resolve (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/dist/shared/nitro.8d0213e3.mjs:304:22)
at Object.resolveId (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/dist/shared/nitro.8d0213e3.mjs:348:34)
at async resolveId (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/rollup/dist/es/shared/rollup.js:21737:26)
at async ModuleLoader.resolveId (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/rollup/dist/es/shared/rollup.js:22037:19)
at async /C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/#rollup/plugin-commonjs/dist/es/index.js:773:14
at async Promise.all (index 0)
at async /C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/#rollup/plugin-commonjs/dist/es/index.js:765:30
at async rewriteRequireExpressionsAndGetImportBlock (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/#rollup/plugin-commonjs/dist/es/index.js:1312:28)
at async transformCommonjs (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/#rollup/plugin-commonjs/dist/es/index.js:1874:23)`
devextreme-vue/menu is importing from devextreme/ui/menu, but it looks like this module is not being passed through during build.
Do I have to declare the dependency somewhere in my code to notify build server to use it? I have tried various things already (like trying to convince Vite (rollup) not to perform tree shaking or to switch to Webpack instead), but always ending up with the same result. But maybe I just fail to do it correctly, I still have to learn a lot about how exactly the things work here. Any help/clues will be appreciated.
This is my package.json in case I shall change or install something there.
{
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare",
"start": "nuxt start"
},
"devDependencies": {
"nuxt": "3.0.0-rc.8"
},
"dependencies": {
"devextreme": "22.1.4",
"devextreme-vue": "22.1.4"
}
}
EDIT: my node is 16.17.0 and npm 8.19.0, maybe the versions are relevant...
So the working solutuion appears to be adding a plugin, in my case named dx.client.ts, but it shouldn't matter, into /plugins folder which imports all necessary components and makes them globally available inside the application:
import { DxButton } from "devextreme-vue/button";
import { DxMenu, DxItem } from 'devextreme-vue/menu';
// the list goes on as the app grows
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp
.component("DxButton", DxButton)
.component("DxMenu", DxMenu)
.component("DxItem", DxItem);
// the list goes on as the app grows
});
I also had to add:
ssr: false
option into nuxt.config.ts, otherwise I ended up with Entry module cannot be external (devextreme-vue). error message during build.
So it has some limitations, but so far it works.
EDIT: it turned out, that while it works fine for some DevExtreme components without further adjustments, some components (like DxForm) also require to disable tree-shaking during Vite build - see how to do it. Otherwise the necessary files are lost in the build process and vague runtime error TypeError: f(...)[t] is not a function appears while rendering the component.
Thanks Stefan (stenet) for the right answer provided here

Parcel Bundler beautify, lint, and create .min.js

I'm new the world of automating/testing/bunding with JS and I've got parcel setup for the most part but I noticed that when it builds files, it does not actually save them with the .min.js part in the file name. I'm wondering if theres a way to do this without having to rename the build file manually.
I'm also trying to find a way to have parcel go through the original source files(the ones that you work on) and lint and beautify them for me
Here's what my package.json looks like
{
"name": "lpac",
"version": "1.3.1",
"description": "",
"dependencies": {},
"devDependencies": {
"parcel": "^2.0.0-rc.0"
},
"scripts": {
"watch": "parcel watch --no-hmr",
"build": "parcel build"
},
"targets": {
"lite-maps": {
"source": ["./path/file1.js", "./path/file2.js", "./path/file3.js"],
"distDir": "./path/build/"
}
},
"browserslist": "> 0.5%, last 2 versions, not dead",
"outputFormat" : "global",
}
I checked out the docs but I couldn't find anything on linting or beautifying with parcel. How can i go about doing that? If you have tutorial links to doing so please also share because resources/tutorials seem scarce for anything other than the basic watching and building files
Unfortunately, there is no out-of-the-box setting that can cause parcel javascript output look like [fileName].[hash].min.js instead of [fileName].[hash].js. The .min.js extension is just a convention to keep output files distinct from source files, though - it has no effect at runtime - and the fact that parcel does automatic content hashing makes it easy enough to tell this. And even though they don't have a .min.js extension, these output files are definitely still minified and optimized by default.
However, if you really, really want this anyways, it's relatively simple to write a Namer plugin for parcel that adds .min.js to all javascript output:
Here's the code:
import { Namer } from "#parcel/plugin";
import path from "path";
export default new Namer({
name({ bundle }) {
if (bundle.type === "js") {
const filePath = bundle.getMainEntry()?.filePath;
if (filePath) {
let baseNameWithoutExtension = path.basename(filePath, path.extname(filePath));
// See: https://parceljs.org/plugin-system/namer/#content-hashing
if (!bundle.needsStableName) {
baseNameWithoutExtension += "." + bundle.hashReference;
}
return `${baseNameWithoutExtension}.min.js`;
}
}
// Returning null means parcel will keep the name of non-js bundles the same.
return null;
},
});
Then, supposing the above code was published in a package called parcel-namer-js-min, you would add it to your parcel pipeline with this .parcelrc:
{
"extends": "#parcel/config-default",
"namers": ["parcel-namer-js-min", "..."]
}
Here is an example repo where this is working.
The answer to your second question (is there "a way to have parcel go through the original source files(the ones that you work on) and lint and beautify them for me") is unfortunately, no.
However, parcel can work well side-by-side with other command line tools that do this do this. For example, I have most of my projects set up with a format command in the package.json, that looks like this:
{
...
"scripts": {
...
"format": "prettier --write src/**/* -u --no-error-on-unmatched-pattern"
}
...
{
You can easily make that command automatically run for git commits and pushes with husky.

Fail Gatsby build if environment variable missing

I have experimented with adding environment variables to my Gatsby project using .env.development and .env.production files and it's working great.
I would like to have my builds fail if one of the environment variables is missing, however I can't seem to see how to enable this functionality.
I have read through the Gatsby environment variables documentation, but can't seem to see how this would work? is this possible?
I believe it uses dotenv/webpack define plugin under the hood.
Iā€™m sure there are other ways to do this, but with some quick tests, this approach seems to be working well for me.
In your gatsby-config.js file, you can choose to explicitly require the dotenv, so you can use those environment variables in your config.
I added the following, and now the Gatsby build will fail unless the specified environment variables are present.
// Load the environment variables, per
// https://www.gatsbyjs.org/docs/environment-variables/#server-side-nodejs
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
})
function checkEnv(envName) {
if (typeof process.env[envName] === 'undefined' || process.env[envName] === '') {
throw `Missing required environment variables: ${envName}`
}
}
try {
checkEnv('NODE_ENV')
checkEnv('EXAMPLE_MISSING_ENV')
checkEnv('EXAMPLE_API_KEY')
} catch (e) {
throw new Error(e)
}
// The rest of the config file
I could imagine customizing this further, ex. logging a warning for a variable with a fallback versus throwing an error for one that is required by your content sourcing plugin or theme. Hope this is helpful as a starting point!
I couldn't find built-in solution for this on Gatsby neither. You may do it manually, but still not too easy.
First problem: If you wanna load your environment from file while running npm script; it can not be loaded right away. But you may trigger a script file, and it can load this environment variables before your check.
lets say build.sh on root directory of project :
source ./.env.development # this line will set env variables
if [ "$API_KEY" = 927349872349798 ] ; then
npm run build
fi
Another problem rises; some developers might want to run it on windows maybe. So better use famous cross-env package.
npm i cross-env
Then everything is ready, add your secure-build :
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1",
"secure-build": "cross-env-shell \"./build.sh\""
},
And run it :
npm run secure-build
This solution looks too much for me as we created a build.sh and install a new package. Maybe there is cleaner solution. I am not Gatsby Guru after all.
I added env checking to the onPreInit life cycle hook in gatsby-node.ts:
const envVariablesList = [
"ENV1",
"ENV2",
"ENV3",
];
function envVarChecker(vars: string[]): string | undefined {
return vars.find(
(item) => process.env[item] === undefined || process.env[item] === ""
);
}
export const onPreInit: GatsbyNode["onPreInit"] = ({ actions }) => {
const emptyEnv = envVarChecker(envVariablesList);
if (emptyEnv !== undefined) {
throw new Error(`Env variable: ${emptyEnv} is empty!`);
}
};
It fails build almost at the very beginning (during pre-bootstrap phase) if any of the declared variables is missing

Build a Vue component for "unpkg"

I want to publish my component on unpkg.com. Actually it is there, but not working. I tried to use the same build (umd) as for my npm build, but I think I would need a specific build for unpkg. Here are the relevant parts of my package.json now:
...
"main": "dist/vuePolar.umd.js",
"unpkg": "dist/vuePolar.umd.min.js",
"scripts": {
"package": "vue-cli-service build --target lib --name vuePolar src/components/Polar.vue",
...
}
I suspect I need to build a IIFE instead of an UMD file, but there is nothing like that in my dist folder:
demo.html
vuePolar.common.js
vuePolar.common.js.map
vuePolar.umd.js
vuePolar.umd.js.map
vuePolar.umd.min.js
vuePolar.umd.min.js.map
Any idea how to get a build that works with unkpg?
Actually, it is ok to publish your component as UMD. I had to register my component in the Vue instance, like so:
<div id="app">
<polar :item="3">hoi</polar>
</div>
<script>
var app = new Vue({
el: '#app',
components: { polar: vuePolar},
})
</script>
Now it works. I got confused by an example that did not require the component to be registered.

Noflo custom components

I'm trying to build a working example using a custom component using noflo. Could somebody please explain how I should reference my component from within my .fbp file. The examples in the docs all seem to relate to npm based components.
Thanks
Assuming you have components/ComponentName.coffee (or .js), and this file is registered in package.json as
noflo: {
components: {
"ComponentName": "components/ComponentName.coffee"
}
}
then you should be able to refer to it in a .fbp file as
'hello' -> IN node(ComponentName)
or
'hello' -> IN node(packagename/ComponentName)
where packagename is the project name set in package.json.
The declaration in the package.json can be automated using grunt-noflo-manifest.
It is the same for noflo-browser, just with component.json instead of package.json

Categories

Resources