I'm following the tutorial here https://www.gatsbyjs.com/docs/using-gatsby-without-graphql/ and I have my gatsby-node.js filled in.
My current directory structure is:
public
src
-pages
-templates
--program_group.js
static
gatsby-config.js
gatsby-node.js
inside my gatsby-node.js file I have
programGroups.forEach(program => {
createPage({
path: `/programs/${program}/`,
component: require.resolve("src/templates/program_group.js"),
context: { program },
})
})
and when I run gatsby develop it says, "Cannot find module 'src/templates/program_group.js'"
I've tried changing the path to ./src/..... and ../src/ and every combination. The documentation says it should be relative to the config file, which the above path is...
Thoughts?
Try using relative paths using path.resolve. This should work:
const path = require(`path`); // import it outside the function
programGroups.forEach(program => {
createPage({
path: `/programs/${program}/`,
component: path.resolve("./src/templates/programGroup.js"),
context: { program },
})
})
You can't underscore the templates due to naming issues to, that's another point to avoid.
So, oddly, you cannot have underscores in the template file name. This should be fixed in the gatsby compiler.
Solution: don't use _ in your template names
Related
I'm having troubles when trying to load a html file from my public folder in a React application created with create-react-app. Am I missing a config setting somewhere in webpack?
I currently have this folder structure:
And I want to show the test.html file inside an Iframe in my React component like this:
import React from 'react';
const Component = props => {
return (<iframe src="/test/index.html"title="Docuvieware" />);
};
export default Component;
But this is giving me a "Cannot GET /test/index.html" in the Iframe. Also when surfing directly to http://localhost:3000/test/index.html I get a white page that says 'Cannot GET /test/index.html'
I also tried to use "process.env.PUBLIC_URL" inside my component but this was undefined.
I have managed to fix this by using CopyWebpackPlugin.
Just added the test folder in my src folder, and then added the following line to my webpack config:
new CopyWebpackPlugin([{ from: 'src/test', to: 'test' }]),
and then /test/index.html gave the correct path.
The simplest version of the code might look like it.
In the webpack config do next.
const path = require('path');
paths.root = path.resolve(__dirname, '..');
paths.publicFiles = path.join(paths.root, 'public');
paths.test = path.join(paths.publicFiles, 'test');
plugins: [
new CopyWebpackPlugin([
{ path.join(paths.test, 'index.html'), to: 'src/test-frame.html' }
])
]
then in your component use the next lines (change localhost if needed):
<iframe
src="http://localhost:3000/src/test-frame.html"
id="unique-id"
title="Frame test"
// remove these styles later
style={{ minHeight: `50vh`, width: '100vw' }}
/>
I am currently trying to overwrite a javascript file from an existing plugin.
I've been following the documentation but I am struggling with the path for the JS class to overwrite.
In the docs is an example code:
import CookiePermissionPlugin from 'src/plugin/cookie/cookie-permission.plugin';
export default class MyCookiePermission extends CookiePermissionPlugin {
}
So I implemented the following code:
import QuantityField from 'src/plugin/FilterRangeSlider/filter-range-slider.plugin';
export default class ExampleQuantityField extends QuantityField {
This code does not work for me, since the original file is in the vendor directory and my plugin is in the custom directory. When trying to compile (eg bin/build-storefront.sh) I receive the following error message:
Module not found: Error: Can't resolve 'src/plugin/FilterRangeSlider/filter-range-slider.plugin' in '<project root>/custom/plugins/ExampleProductFilter/src/Resources/app/storefront/src/filter-range-slider'
Any idea how I can import that class as stated in the docs?
Node.js provides a bunch of in-built file-system functionalities. The __dirname points to the root directory.
So, this should work.
import QuantityField from `${__dirname}/vendor/store.shopware.com/mmeesrangesliderpro/src/Resources/app/storefront/src/script/filter-range-slider.plugin`
My current solution is not really clean...
import QuantityField from '../../../../../../../../../vendor/store.shopware.com/mmeesrangesliderpro/src/Resources/app/storefront/src/script/filter-range-slider.plugin';
Isnt there any plugin root variable or something similar?
There is - I believe - no easier way to accomplish this.
If each plugin would extend the webpack config as described in
https://developer.shopware.com/docs/guides/plugins/plugins/administration/extending-webpack
const path = require('path');
module.exports = () => {
return {
resolve: {
alias: {
MmeesRangeSliderPro: path.join(__dirname, '..', 'src')
}
}
};
};
The alias could be used instead of the Plugin Root.
But this is not the case, so the following is not working:
import QuantityField from 'MmeesRangeSliderPro/plugin/FilterRangeSlider/filter-range-slider.plugin';
You can add a console.log(webpackConfig) to the bottom of Resources/app/storefront/webpack.config.js to validate this.
alias: {
src: '/home/user/example/projects/example.de/vendor/shopware/storefront/Resources/app/storefront/src',
assets: '/home/user/example/projects/example.de/vendor/shopware/storefront/Resources/app/storefront/assets',
jquery: 'jquery/dist/jquery.slim',
scss: '/home/user/example/projects/example.de/vendor/shopware/storefront/Resources/app/storefront/src/scss',
vendor: '/home/user/example/projects/example.de/vendor/shopware/storefront/Resources/app/storefront/vendor'
}
And those again to not really allow locating the module.
If it is a third-party plugin, replace the path with an absolute path like the following
import ThirdPartyPlugin from '/app/custom/plugins/ThirdPartyPlugin/src/Resources/app/storefront/src/third-party-plugin/third-party-plugin.plugin';
I'm new to react-native coming from vue background, one thing I hate in react is having to use relative path imports in my components, I find myself doing something like:
import HomeScreen from '../../components/screens/HomeScreen'
If my folder structure changes it means I will have to do a search and replace in all of m components using that component, not cool and prone to be a dev hell.
Is it possible to use absolute paths like with node modules, is there a library where I can use aliases or similar, with vue I could import my components in the app.js like Vue.component('home-screen ...) and I could use them without having to import.
you can add a package.json file with a name key
{
"name": "#components"
}
in any folder and metro will recognize it.
You can then import as #components/screens/HomeScreen
If you are using vscode, you can add a jsconfig.json file to your project root to enable import autocomplete.
Here is mine:
{
"compilerOptions": {
"baseUrl": "",
"paths": {
"#components/*": ["src/components/*"],
"#helper/*": ["src/helper/*"],
"#actions/*": ["src/actions/*"],
"#constants/*": ["src/constants/*"],
"#primitives": ["src/primitives/index.js"],
"#graphql": ["src/graphql/index.js"],
"#services/*": ["src/services/*"],
"#assets/*": ["assets/*"]
}
}
}
The easy method
Add a package.json to important directories with a {"name":"<prefix>"}, similar to a monorepo.
If you are doing this, you can probably also think about making it a full monorepo since there is very little extra work
The incredibly complex method
This method is easier for using things like webpack resolver, etc.
Create a metro.config.js at the root with the following content
module.export = {
resolver: {
resolveRequest: (
context: ResolutionContext,
moduleName: string,
platform: string | null
) => {
//...
return Resolution;
}
}
}
Resolution Context
The resolution context is an object that holds attributes of the running resolution, most importantly originModulePath which is the path of the requiring module.
Resolution
The resolution is an object of either:
{ type: "empty" } for empty sources
{ type: "sourceFile", filePath: string } for JS, JSON, etc. files
{ type: "assetFiles", filePaths: string[] } for any other type (e.g. not metro compilable)
For this method, I would recommend looking at metro-resolver's types since this method is abysmally documented
We have project of around 100 pages. We are migrating our front end to some emerging technology. We almost have finalized Vue.js(with vue cli). Vue CLI is building project in one build.js. We have a problem with that. We have frequent requirement changes. So after every small change, we will have to upload whole build js and that will need regression testing of the whole project. Is there any way that build will be module wise? So that only changed module need to be uploaded on live after changes.
Using the Vue router:
The following approach will tell the compiler (Webpack) to "return" the component vs "including" it. Resulting in the given component being "chunked" into its own file for lazy loading.
e.g.
export default new Router({
routes: [
// Home component to be included in bundle.js
{
path: '/',
name: 'home',
component: Home
},
// code splitting - generate a separate unique chuck for about component.
{
path: '/about',
name: 'about',
component: () => import(/* webpackMode: "lazy" */ '#/views/About.vue')
}
]
})
Output = bundle.js and about.js or... 100 other files, given you have a component per page.
more on component lazy loading: https://router.vuejs.org/guide/advanced/lazy-loading.html
Using webpack:
You can extend and/or modify the default compiler (webpack) configuration by adding a vue.config.js file to the project root.
e.g.
// vue.config.js
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// mutate config for production...
} else {
// mutate for development...
}
}
}
Be sure to read all the documentation at https://cli.vuejs.org/guide/webpack.html as some settings should not be mutated directly.
more on webpack code splitting: https://webpack.js.org/guides/code-splitting
Let's say I have 5 jsx files and each file uses some config parameter.
My index.js file imports all of these 5 jsx files.
Instead of having my config data spread accross 5 files, is there a way for my jsx files to get the data from a global JS object which has loaded the data from a config file?
I've seen some examples, but I've not been able to get them to work.
JS6 import function | Example using webpack
Assuming ES6:
config.js
export const myConfig = { importantData: '', apiUrl: '', ... };
Then:
jsxFileOne.js, jsxFileTwo.js, ...
import { myConfig } from 'config.js';
There are other ways to import & export things globally leveraging webpack, but this should get you started.
If your project is built using Webpack, consider using node-env-file.
Example config file snippets:
development.env
API_SERVER_URL=https://www.your-server.com
webpack.config.js
const envFile = require('node-env-file');
...
const appSettingsFile = isDevBuild ? '/settings/development.env' : '/settings/production.env';
try {
envFile(path.join(__dirname + appSettingsFile));
} catch (error) {
console.log("Failed to read env file!: " + __dirname + appSettingsFile);
}
...
plugins: [
new webpack.DefinePlugin({
"process.env": {
API_SERVER_URL: JSON.stringify(process.env.API_SERVER_URL)
}
})
...
]
Inside your js/jsx code, you can now access process.env.API_SERVER_URL variable which will contain the required value.
It seems dotenv package is more popular, you can try this out as well.
Very old problem, that nobody took the time to solve, until now. I leave this for future readers because this is a top search result for configuration in React.
I created wj-config to deal exactly with this. Be sure to pay close attention to the React notes as you will need to enable top-level awaits in webpack, either by ejecting or using the #craco/craco NPM package.
You may also read this blog post that explains its use.