I'm trying to use react-gtm-module in my Gatsby project, I used the library #loadable/component to load this module in my component. So, when I run gatsby develop, I get the error TagManager.initialize is not a function
This is the code:
import loadable from '#loadable/component';
const TagManager = loadable(() => import('react-gtm-module'));
export const setupGtm = () => {
if (typeof window !== 'undefined') {
TagManager.initialize({
gtmId: 'GTM-ID',
});
}
};
I would really like to use the react-gtm-module because I already have several codes already pre-configured, does anyone know how to use no gatsby?
Thanks!!
For this to run properly, you have to install the Gatsby plugin called Google Tagmanager inside your gatsby project, you can do that. by running
npm install gatsby-plugin-google-tagmanager
When you are done, you have to get the plugin set up in your gatsby-config.js or gatsby-config.ts file.
Check out this doc from Gatsby for more info.
Don't use the React-based dependency. It's far way easy to use the native Gatsby plugins for that since they will insert the script in the needed places automatically. I would suggest get riding off that snippet and using gatsby-plugin-google-tagmanager:
// In your gatsby-config.js
plugins: [
{
resolve: "gatsby-plugin-google-tagmanager",
options: {
id: "YOUR_GOOGLE_TAGMANAGER_ID",
// Include GTM in development.
//
// Defaults to false meaning GTM will only be loaded in production.
includeInDevelopment: false,
// datalayer to be set before GTM is loaded
// should be an object or a function that is executed in the browser
//
// Defaults to null
defaultDataLayer: { platform: "gatsby" },
// Specify optional GTM environment details.
gtmAuth: "YOUR_GOOGLE_TAGMANAGER_ENVIRONMENT_AUTH_STRING",
gtmPreview: "YOUR_GOOGLE_TAGMANAGER_ENVIRONMENT_PREVIEW_NAME",
dataLayerName: "YOUR_DATA_LAYER_NAME",
// Name of the event that is triggered
// on every Gatsby route change.
//
// Defaults to gatsby-route-change
routeChangeEventName: "YOUR_ROUTE_CHANGE_EVENT_NAME",
// Defaults to false
enableWebVitalsTracking: true,
},
},
]
You can omit the options you won't use.
Related
I'm trying to set up plotly.js in nuxt but whatever I do I get this cryptic error
self is not defined
I tried to install plotly.js and plotly.js-dist same error shows.
I would prefer to make custom build so I tried like this in nuxt plugins:
// here we use custom partial bundle
import plotly from 'plotly.js/lib/core';
import barpolar from 'plotly.js/lib/barpolar';
export default function (_, inject) {
plotly.register([barpolar]);
inject('plotly', plotly);
}
but whenever I register nuxt plugin site crashes with aforementioned error.
Even not going down custom bundle route, and using dist lib still fails just the same.
I also tried not to employ nuxt plugins system but to import manually and to set up, same things happen.
I also added ify-loader as recommended here: https://github.com/plotly/plotly-webpack
and this is my nuxt.config.js in regards to webpack plugin:
build: {
extend(config, { isClient }) {
console.log('config :>> ', config);
config.module.rules.push({
test: /\.js$/,
use: [
'ify-loader',
'transform-loader?plotly.js/tasks/compress_attributes.js',
],
});
},
},
still no luck.
I presume this is problem with webpack 5 and plotly.js not working well together in default setup but I have no idea how to solve this.
Help appreciated.
The reason why this wasn't working is that plotly tried to access document, and in SSR that would obviously fail.
So to fix this I just had to assign plugin in client only mode like this:
plugins: [
// other plugins
{ src: '~/plugins/plotly', mode: 'client' },
],
and it worked.
I want to use jsdom within a Gatsby project, in order to be able to load and render a separate webpage within a React component.
However, when I try to build with Gatsby, I get a series of Webpack errors which look like this:
undefined failed
Can't resolve 'child_process' in
'/Users/john/WebstormProjects/analytics/web/node_modules/jsdom/lib/jsdom/living/xhr'
I think this may be because Webpack is using the 'web' target mode and not 'node'. I've tried putting a webpack.config.js file in the root directory:
module.exports = {
target: 'node',
}
However, this didn't do anything. I also tried to use onCreateWebpackConfig, but I'm not sure if this is correct, as I couldn't get this to work either:
//gatsby-node.ts
export { onCreateWebpackConfig } from "./src/gatsby/on-create-webpack-config";
// ./src/gatsby/on-create-webpack-config
export const onCreateWebpackConfig = ({ actions } : any) => {
actions.setWebpackConfig({
target: 'node',
});
}
I have 2 questions:
Is it possible to use jsdom in a Gatsby project and if so, what do I need to do? If it's just to use the target mode, then:
How do I set the target mode in Gatsby to be node and not web?
How do I set the target mode in Gatsby to be node and not web?
It looks like you can alter the webpack config to set the target:
// gatsby-node.js
exports.onCreateWebpackConfig = ({ actions, getConfig }) => {
const config = getConfig();
config.target = 'node';
actions.replaceWebpackConfig(config);
};
https://www.gatsbyjs.com/docs/how-to/custom-configuration/add-custom-webpack-config/#modifying-the-babel-loader
I'm trying to get i18next to work in my Gatsby project but I keep running into the below error whenever i try to build using yarn build.
From my package.json:
"i18next": "^19.8.2",
"react-i18next": "^11.7.3",
My i18n/index.js file:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
// ...
i18n.use(initReactI18next).init({
fallbackLng: "en",
// have a common namespace used around the full app
ns: ["translations"],
defaultNS: "translations",
wait: true,
useSuspense: false
}, (err, t) => {
i18n.t('en');
});
// load additional namespaces after initialization
i18n.loadNamespaces('translations', (err, t) => {
i18n.t('i18n', { lng: 'en' } );
});
// i18n resource bundles for views
const i18nResourceBundlesViews = [
{
intro: {
en: { ...intro.en },
ja: { ...intro.ja },
},
},
// ...
];
// i18n resource bundles for components
const i18nResourceBundlesComponents = [
{
header: {
en: { ...header.en },
ja: { ...header.ja },
},
},
{
footer: {
en: { ...footer.en },
ja: { ...footer.ja },
},
},
];
// Load i18n resource bundles from each resource object
const getI18nResourceBundles = (resource) => {
const key = Object.keys(resource)[0];
const enBundle = resource[key].en;
const jaBundle = resource[key].ja;
// English translations
i18n.addResourceBundle('en', key, enBundle);
// Japanese translations
i18n.addResourceBundle('ja', key, jaBundle);
};
// i18n resource bundles for views
i18nResourceBundlesViews.forEach((resource) => {
getI18nResourceBundles(resource);
});
// i18n resource bundles for components
i18nResourceBundlesComponents.forEach((resource) => {
getI18nResourceBundles(resource);
});
export default i18n;
The full error message after yarn build
❯ yarn build
yarn run v1.22.5
$ gatsby build
success open and validate gatsby-configs - 0.044s
success load plugins - 0.800s
success onPreInit - 0.016s
success delete html and css files from previous builds - 0.027s
success initialize cache - 0.009s
success copy gatsby files - 0.154s
success onPreBootstrap - 0.020s
success createSchemaCustomization - 0.007s
success source and transform nodes - 1.225s
success building schema - 0.415s
success createPages - 0.021s
success createPagesStatefully - 0.104s
success onPreExtractQueries - 0.002s
success update schema - 0.052s
success extract queries from components - 0.418s
success write out requires - 0.008s
success write out redirect data - 0.005s
warn The icon(./static/favicon/favicon-512.png) you provided to 'gatsby-plugin-manifest' is not square.
The icons we generate will be square and for the best results we recommend you provide a square icon.
success Build manifest and related icons - 0.183s
success onPostBootstrap - 0.192s
⠀
info bootstrap finished - 6.260 s
⠀
warn Browserslist: caniuse-lite is outdated. Please run:
npx browserslist#latest --update-db
success Building production JavaScript and CSS bundles - 19.520s
success Rewriting compilation hashes - 0.010s
success run queries - 20.490s - 6/6 0.29/s
failed Building static HTML for pages - 4.770s
ERROR #95313
Building static HTML failed for path "/404/"
See our docs page for more info on this error: https://gatsby.dev/debug-html
37 | var _this = this;
38 |
> 39 | namespaces.forEach(function (ns) {
| ^
40 | if (!_this.usedNamespaces[ns]) _this.usedNamespaces[ns] = true;
41 | });
42 | }
WebpackError: TypeError: namespaces.forEach is not a function
- context.js:39 ReportNamespaces.addUsedNamespaces
node_modules/react-i18next/dist/es/context.js:39:1
- useTranslation.js:41 useTranslation
node_modules/react-i18next/dist/es/useTranslation.js:41:1
- index.jsx:27 Footer
src/components/theme/Footer/index.jsx:27:38
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
In my Footer/index.jsx where the error originally occurs (line 27):
const { t, i18n } = useTranslation({useSuspense: false});
Any help would be greatly appreciated. Thank you
This issue has been resolved.
Reference including the solution: https://github.com/benji011/portfolio.benjaminlo.io/pull/9#issuecomment-707612060
I think I've managed to pinpoint the two issues you were originally
having. I've uploaded the fixes I've made, please see if it builds for
you. It builds fine for me.
1. React suspense:
i18n appears to use Suspense but this is problematic for Gatsby. See
here.
The fix is quite straightforward and I've added it to the config.
2. The i18ncheck statement: ```const i18nCheck = i18n.languages.toLowerCase().includes('en') ||
i18n.languages.toLowerCase().includes('en-');```
This statement is problematic.
There are two variables that contain the languages.
language, which I think is the current language, and is set to a string: en
languages which is an array of languages. This is set to ['en', 'dev'].
If you want to check for the array languages, then we can't use
toLowerCase() like it was used. It will result in an error as we are
applying toLowerCase() on the entire array and not an element of the
array. toLowerCase() must be used on a string and won't ork on an
array. We would have to loop through the array and then apply
toLowerCase(). I don't think you were wanting to check the array
though as the language, for example 'en', would always be in the
array.
Another issue related to this is that i18n might not have the
property yet, so we need to check that it has the property first.
The best approach, imo, is to just check the language to see if it
is en or en-.
Regarding ESLint and Prettier:
You should use both.
ESLint is a linter and will show code errors. The project already has
an ESLint config, you just need the plugin. There might be a window
that pops up when you open the project, which you must then choose
Allow.
Prettier is a formatter and will format your code e.g. split up a long
line into 3 separate lines
In my react project if I use some non-existent className from css modules file,
// mycss.modules.scss
.thing { color: red }
// index.jsx
import styles from mycss.modules.scss
<div className={styles.otherThing}>Some div</div>
// Browser would return:
<div>Some div</div>
it quietly fails without letting me know that this class does not exist. How I can check if this class name exist or not and throw an error. Would be great to receive an error during build time, when saving file.
If you are open to typescript solution, I found one TS plugin for you.
typescript-plugin-css-modules
It can populate the styles object with type information for available keys.
You don't have to switch whole project to typescript, you can add // #ts-check directive at the top of this file to enable the TS engine design time check.
Unless you want to put forth a pull request to add something like a strict mode option to the webpack loader itself, i dont think theres much you can do since its just a base object. An easy alternative is to just do styles.styleName.toString(), this way if styleName is undefined, it will throw an error.
Actually it is possible in javascript code. But I think that className exist check is not good idea.
document.styleSheets[].rules[].selectorText
original link How can you determine if a css class exists with Javascript?
add this function to the top:
// index.jsx
import styles from mycss.modules.scss
function strictStyles (clsName){
if(styles[clsName]){
return styles[clsName]
}else{
throw "CSS class doesn't exist";
}
}
...
<div className={strictStyles(otherThing)}>Some div</div>
...
NOTE: This solution does not require you to change any of your code, just add the loader and it should work out of the box. Please note the caveat about production builds at the end, or check the source for full instructions at Github.
I have created a Webpack loader that works with CSS/LESS/Other CSS module loaders.
The full source and readme can be found on GitHub.
For those who just want to add the loader to their project, it can be used like this:
Add this webpack loader source file somewhere, e.g /webpack/loaders/css-module-proxy.js
/**
* A CSS/LESS/Style module loader that prepends a proxy in non-production builds.
*
* The proxy checks if the loaded style module actually contains the style we are trying to fetch.
* If it doesn't exist (its accessor returns undefined), we crash on debug (non-production) builds!
*
* Inspired by https://github.com/royriojas/css-local-loader
*/
module.exports = function cssLocalLoader(source, map) {
this.cacheable();
if (process.env.NODE_ENV !== "production") {
// noMatch:
// Makes sure that any access prefixed with underscore are filtered out
// otherwise it will crash at runtime when Webpack is probing the locals export.
// toJsonMatch:
// Makes sure that toJSON access on the locals object gets proxied to the correct
// toJSON function.
const requireWrapper = `
// If the access matches this regexp, skip it
const oldLocals = exports.locals;
const noMatch = /^[_]+/;
const toJsonMatch = /^toJSON$/;
const proxy = new Proxy(oldLocals, {
get: function(target, name) {
if (noMatch.test(name)) {
return undefined;
}
if (toJsonMatch.test(name)) {
return oldLocals.toJSON;
}
const clz = target[name];
if (clz === undefined) {
throw new Error("Error: LESS / CSS class named \\"" + name + "\\" does not exist");
}
return clz;
}
});
exports.locals = proxy;
`;
const newSource = `${source}\n\n${requireWrapper}`;
this.callback(null, newSource, map);
} else {
this.callback(null, source, map);
}
};
And then use it from your webpack config, example below is for LESS:
{
test: /\.module\.less$/,
use: [
{ loader: path.resolve("webpack/loaders/css-module-proxy.js") },
{
loader: "css-loader",
options: {
modules: true,
importLoaders: 1,
localIdentName: "[name]__[local]__[hash:base64:5]",
},
},
{ loader: "less-loader" },
],
},
Don't forget to build your release code with NODE_ENV=production or it may crash when a user visits your site...
I'm working on migrating a Nuxt.js project from Nuxt#1.4 to 2.7, and after updating the Webpack config as required, etc. I'm now running into the following error.
When I try to access any of the pages on the website, I hit the stock Nuxt loading screen showing bundling progress, which then immediately refreshes ad infinitum. The application never progresses past this screen, and the tab title never changes from Nuxt.js: Loading app....
There are no errors in the console, nor any compile time errors, but when I go to the devtools Network tab, I see a failed (HTTP 500) request to localhost:3000, with the following error as response payload:
NuxtServerError
render function or template not defined in component: NuxtLoading
I looked into NuxtLoading, and the only reference to it I can find is a file in the .nuxt folder called nuxt-loading.vue, which looks like a regular functioning component. It has a render() method, which is implemented as follows:
render(h) {
let el = h(false)
if (this.show) {
el = h('div', {
staticClass: 'nuxt-progress',
class: {
'nuxt-progress-notransition': this.skipTimerCount > 0,
'nuxt-progress-failed': !this.canSucceed
},
style: {
'width': this.percent + '%',
'left': this.left
}
})
}
return el
}
What I've tried:
Reinstall node_modules;
rm -rf .nuxt && yarn dev (EDIT: and yarn.lock);
Upgrading element-ui to latest version.
Thanks in advance for any help. If any more info is needed, please ask.
You have a wrong configuration for i18n loader. It should be like this:
config.module.rules.push({
resourceQuery: /blockType=i18n/,
type: 'javascript/auto',
loader: '#kazupon/vue-i18n-loader'
});
Or you can use nuxt-i18n module, that will setup this for you using vueI18nLoader option.