Is it possible to inject a variable value into a javascript comment? - javascript

TL;DR: is it possible to inject constant variables (that won't change during runtime) in comments
I've come across a very unique situation where I need my comments to have a specific value in them.
I'm code splitting in React and the way to name chunks in react is to add comment next to the import like this:
const MyComponent = lazy(() =>
import('./MyComponent' /* webpackChunkName: "MyComponent" */)
)
This gives my lazy loaded chunks readable names over generated id names.
There's a section in my codebase where I generate lazy loaded routes for my components based on my folder structure, but I've hit a wall where I can't set my chunk name to a variable set by a function.
Here's my function:
function generateLink(label: string) {
const path = label.replaceAll(' ', '');
return {
Element: lazy(
() => import(`./pages/${path}`, /* webpackChunkName: "{{this should be path}}" */)
),
label,
path
};
}
Is there anyway for me to inject the path variable into that comment?
An extra side note, this generateLink function is not run during runtime, the links are static.

Unfortunately there's no simple method for injecting variables into your comments. However, there is a webpack solution to your specific problem, just use Magic Comments
Updating your generateLink function to the following should resolve your problem.
function generateLink(label: string) {
const path = label.replaceAll(' ', '');
return {
Element: lazy(
() => import(`./pages/${path}`, /* webpackChunkName: "[request]" */)
),
label,
path
};
}
Now if your path is HomePage, your chunk name will resolve to /HomePage.[chunkId].js
Just make sure that all your file names are unique, otherwise webpack will suffix a number to your chunks for non-unique file names.
E.g. if you have 2 file names of HomePage.jsx, then you will end up with /HomePage0.[chunkId].js and /HomePage2.[chunkId].js

This question has been answered before in https://stackoverflow.com/a/52345836/2188587
You can use a placeholder [request] and webpack will automatically use the resolved file name.
import(/* webpackChunkName: "[request]" */ `./pages/${path}`)
I checked the docs, it still exists.
Exception: It will use the file name, so if you have nested files and path variable can also use directories, you're probably out of luck.

Related

How to access the app object from a Vue single file component?

My end goal: I'm using a custom HTML element in a component template (<gcse:searchresults-only>) and I'd like to register the element with Vue. The method given by that page for registering custom elements is through app.config.compilerOptions.isCustomElement.
But I'm using a single file component and the global app object is not defined. Is there a way to obtain it? Or is there an alternative way to set config options from within a single file component?
Do I need to set it from outside this component? I figured that since I'm only using this custom element here, it makes sense for only this file to have to know about it instead of managing it in some global context.
In case it matters, I'm actually doing this within Gridsome.
This is how we do it (like in the docs). I think it's fine to make it globally available as it will also have a bunch of ESLint warnings, etc
vue.config.js
module.exports = {
chainWebpack: config => {
// ignore errors about external custom html elements
config.module.rule('vue').use('vue-loader').tap(options => ({
...options,
compilerOptions: {
isCustomElement: tag => tag === 'gcse:searchresults-only',
},
}));
},
};

Nextjs - first level dynamic route

I want to have user profiles in my app at domain.com/:username .How do I do it? creating a new folder in /pages will create a new URL section like /user/:username which I don't want.
Just name your file inside pages as [username].js
Creating a dynamic route
You can create a dynamic route by putting the filename in brackets. For instance:
pages/[id].js
pages/[slug].js
pages/posts/[slug].js
pages/[author]/[slug].js
pages/[author]/bio.js
Notice how the dynamic route can be at any level. It doesn't simply need to be at the root of the pages folder, and it doesn't need to be the last level of the url either. Also notice that you can name the dynamic route anything you want. You're not restricted to just using [id] or [slug].
In your case, use pages/[username].js
Accessing the route name
If you create a dynamic route at pages/posts/[slug].js, any page at https://example.com/posts/slug-of-the-post will lead to that page. However, you likely want different content on each page (i.e., that the user is on https://example.com/posts/slug-of-the-post, not https://example.com/posts/slug-of-a-different-post. For this, you need to access the contents of the route.
Inside the page
You can use the router to get the name of the route.
// pages/posts/[slug].js
import { router } from 'next/router'
export default function PostPage() {
const router = useRouter()
const slug = router.query.slug // "slug" because that was the name of the file
return <>{/* page contents */} </>
}
So on page https://example.com/posts/slug-of-the-post, the variable slug will be slug-of-the-post.
If you used [id].js, use router.query.id instead.
GetStaticProps/GetServerSideProps
Using the server-side functions, the process is very similar.
// pages/posts/[slug].js
// bottom of the file
export async function getServerSideProps(context) {
const slug = context.params.slug
return {
props: {},
}
}
Docs
By the way, I'd also recommend checking out the docs if you haven't already:
https://nextjs.org/docs/routing/dynamic-routes

Best way to maintain a list of static constant values in nodejs

I have a nodejs application where I am using graphql queries and mutations which are in template literal format.
I want to store all these template literals in one single file and access it from anywhere in the application.
The template literals should be immutable so that it doesn't get changed.
What would be the best way to do this nodejs.
A solution I found in stackoverflow is something like this.
class GraphqlLiteral {
constructor() {
}
static #query1 =`string literal template` ;
static getQuery1() {
return this.#query1;
}
}
I tried the above solution in my nodejs app in glicth but its says unexpected token #.
you could create a simple js file. Have an object, don't export it. Export the getter.
Another common pratice is to use .ENV file.
https://www.npmjs.com/package/dotenv
const queryStrings = {
"query1":"query1"
}
export default (key) => return queryStrings[key] ;
What characters are valid for JavaScript variable names?
You can't start a variable with #, which is why it is an unexpected token.
Below is how I do it. I don't see a reason to make a class and a function to retrieve values, it adds complexity. Just declare constant values and export them (Unless you want to add some unique functionality - like a static method that builds queries based on parameters).
Just make a query.js file:
export const query1 = `this is query 1`;
export const query2 = `this is query 2`;
Then in a new file:
import query1 from './query';
console.log(query1); // "this is query 1"

Gatsby: Why Do I (Or Do I Even?) Need to Use exports.onCreateNode to Create Pages?

All of the examples in the Gatsby documentation seem to assume you want to define an exports.onCreateNode first to parse your data, and then define a separate exports.createPages to do your routing.
However, that seems needlessly complex. A much simpler option would seem to be to just use the graphql option provided to createPages:
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const { data } = await graphql(query);
// use data to build page
data.someArray.forEach(datum =>
createPage({ path: `/some/path/${datum.foo}`, component: SomeComponent }));
However, when I do that, I get an error:
TypeError: filepath.includes is not a function
I assume this is because my path prop for createPage is a string and it should be "slug". However, all the approaches for generating slugs seem to involve doing that whole exports.onCreateNode thing.
Am I missing a simple solution for generating valid slugs from a path string? Or am I misunderstanding Gatsby, and for some reason I need to use onCreateNode every time I use createPage?
It turns out the error I mentioned:
TypeError: filepath.includes is not a function
Wasn't coming from the path prop at all: it was coming from the (terribly named) component prop ... which does not take a component function/class! Instead it takes a path to a component (why they don't call the prop componentPath is just beyond me!)
But all that aside, once I fixed "component" to (sigh) no longer be a component, I was able to get past that error and create pages ... and it turns out the whole onCreateNode thing is unnecessary.
Why Do I Need to Use exports.onCreateNode to Create Pages?
You do not.
Gatsby heavily uses GraphQL behind the scenes. The Gatsby documentation is about teaching users that many of the features in Gatsby are often only available via GraphQL.
You can create pages without GraphQL as you do in answer with data.someArray.forEach ... but that is not the intended way. By skipping createNodeField you will not be able to query for these fields within your page queries. If you don't need these fields via GraphQL then your solution is perfect.

Are GatsbyJS GraphQL queries tied to the component where it's written?

I have a couple yaml files with meta content that represent pages of a site that get ingested by Gatsby's data source/transform system - one of the files looks something like this:
path: /about/
pageTitle: About Us
metaDescription: Learn more about our team and what we do
...
I also have a base yaml file with meta content that other pages default to if meta content is missing or was not particularly written for that page.
path: Base
pageTitle: Welcome to our website
metaDescription: We are the leading company of industry x in ...
...
My current solution is to pass a graphql query variable $slug that is the page path, i.e., /about/ via the onCreatePage hook in gatsby-node.js,
exports.onCreatePage = ({ page, boundActionCreators }) => {
const { createPage, deletePage } = boundActionCreators;
return new Promise(resolve => {
const oldPage = Object.assign({}, page);
deletePage(oldPage);
createPage({
...oldPage,
context: {
$slug: oldPage.path
}
});
resolve();
});
};
add a graphql query in layout/index.js filtering for Base meta content,
query BasePageQuery {
pagesYaml(path: { eq: "Base" }) {
path
pageTitle
metaDescription
...
}
}
and a more generic graphql query on every single page where field path (from the yaml file) matches the query variable $slug:
query AboutPageQuery($slug: String) {
pagesYaml(path: { eq: $slug }) {
path
pageTitle
metaDescription
...
}
}
Instead of adding a graphql query onto every single page, I'm thinking instead to add both queries into layout/index.js, and avoid having to manually add the above query to all other pages.
query BasePageQuery($slug: String) {
base: pagesYaml(path: { eq: "Base" }) {
path
pageTitle
metaDescription
...
}
page: pagesYaml(path: { eq: $slug }) {
path
pageTitle
metaDescription
...
}
}
However, it isn't working as expected - this.props.data in the layout component only returns the base content and completely ignores my second query. It appears as if the query is tied to my layout/index.js component, and the $slug variable isn't reflecting the page component that's being rendered.
Which brings me to my question(s) -
Are graphql queries tied to the component that it's being written in? In this particular case - is $slug always going to be whatever path layout/index.js is?
Is there a way to print out graphql variables, or somehow verify what the variable is at a given point in time?
Is there a better solution to what I'm trying to achieve?
I don't quite understand the question about where GraphQL queries are tied to but I think that it will be more clear to you when you understand that you passed slug as a variable to the createPage function in your gatsby-node.js file. So for every page that is being created when you run createPage, the slug variable will be whatever you passed to it.
Again, do that in your gatsby-node.js file, in the createPage function.
gatsby-config.js would be a more appropriate place for the "default" or "base" information you want. Check out the example gatsby-starter-blog. There are information in the gatsby-config.js that are then being queried in the blog-post.js template alongside with the post's data.

Categories

Resources