Copy file to non-project directory after webpack compliation - reactjs

I want to develop a React app for work in a directory and copy the bundle file over to a local instance of our website, which runs on a Django backend in a different directory on my local file system. But, of course, I can quickly develop in one directory and copy the bundle to another directory using my file system. Still, I was hoping to automate this each time I compiled.
I have written a plugin for my webpack config file and can read the bundle and write it to a separate file within the project directory (using the fs package). Still, I can't find a way to write the copy to a different directory on my file system. So it either ends up in the project directory I am compiling from, or I get an error.
Error: ENOENT: no such file or directory
Is such a thing possible? For example, I suppose I could write the bundle to the other directory in the first place and not copy it if the webpack output can write to a different location.
Here is the code for my plugin in my webpack.config.js so far. In this example, I was trying to write it to the desktop for testing, but ultimately I would like to put it in a different directory.
class Copy {
apply(compiler) {
compiler.hooks.afterEmit.tap('Copy', (compilation) => {
//const file = compilation.getAsset('bundle.js')
//console.log(file.name)
let string = fs.readFileSync('./static/js/bundle.js')
fs.writeFile('/Users/<username>/Desktop/bundle.js', string, (err) => {
if (err) throw err
console.log(err)
})
})
}
}
I've tried multiple options for the path in the fs.writeFile function such as the whole absolute path C:/Users/<username>/Desktop/bundle.js and have tried it with and without the leading / though I believe it needs one if I don't provide the drive letter.
Any help would be appreciated.

Figured out what the path should actually be. I am running WSL2 on Windows 10 and compiling via webpack on a linux terminal. If I provide the full directory using WSL syntax
/mnt/c/Users/<username>/Desktop/bundle.js
for example, I can write the bundle where it needs to go.

Related

How to have Nx environment variables in React app per environment?

Context
I have a three projects inside my Nx workspace, two applications which are react apps (both of them have shared logic, however they are intended for different platforms web and microsoft teams and must be separated) and a library which contains logic for an api client, which both of the applications use.
The api client project requires the variable base URL which is environment specific.
I can define environment variables and introduce file replacements in the build process for .ts files (e.g. environment.ts is replaced with environment.production.ts, when configuration is production), however I do not want to reference this file (environment.ts) in the api client project so as not to introduce two way dependencies.
What have I tried
From the api project I was not able to extract the logic which depends on the URL variable as this is tied to some code generation which is changeable.
I succeeded in providing this variable by using .env file in the root of the application project, the variable is in the format NX_MY_URL, and could be accessed with process.env.NX_MY_URL.
However I was not able to change this variable when changing the build configuration (e.g. development, test, production). I have tried adding a fileReplacements task such as
"configurations": {
"development": {
"fileReplacements": [
{
"replace": "apps/ra-web/src/environments/environment.ts",
"with": "apps/ra-web/src/environments/environment.development.ts" //<----- This works fine
},
{
"replace": "apps/ra-web/.env",
"with": "apps/ra-web/.development.env" //<----- This does not work, .env values remain
}
],
Question
How can .env files be replaced based on Nx target's configuration?
Why the mentioned approach does not work?
The reason of why the fileReplacements approach is not working is because those replacements are meant for the building process, which is the bundler the one in charge (webpack or vite, etc). That file content replacement is actually working, yet it doesn't happen at file system level but at memory level (for the bundling process). As your application code does not "import" that .env file (and you should not directly depend on it), then those file replacements make no difference in the build output.
On the other side, Nx is in charge of reading the .env file (at file-system level) and loading the data as environment variables so that when the bundling process starts, those are available. This a completely separate process than the fileReplacements done by the bundler.
How to achieve what you are looking for?
If you think about projects in libs as shareable/re-usable code, then you can imagine those are external dependencies added to your apps (or other libs). As those dependencies are external, they should rely on their implementor to get the data needed for them to work.
Having the above in mind, your lib public API (the main index.ts file) should be parametrized to receive that base URL that will depend on each application. With that you can keep working with the environment.ts file replacements, get the value in the app and pass it down to the lib.
Example:
// app's main.tsx
import { environment } from './environments/environment';
import { apiClient } from '#myorg/api-client';
apiClient.init({ baseUrl: environment.baseUrl });
// api-client's index.ts
export { apiClient } from './lib/api-client';
// api-client's api-client.ts
export const apiClient = {
init: ({ baseUrl }) => { ... }
};
If you still need to work with the .env file (not trying to replace it), just the the env vars in the environment.ts as work with it as mentioned above.

How to add extra resources files in production in electron using electron-forge

I have a file that i need compulsory to make my application work,i am able to use the file in development by specifying fixed path var path = process.cwd() + '/src/app/components/task/Scripts'; and the file name after that,but after packaging the app i want to move the file i need in extraResources folder in system from where i will be able to use it let path = pathPackage.join(process.resourcesPath, 'extraResources');,i am using electron-forge maker to produce a production build exe,how ever there is no extraResources folder created after installing the exe,i am specifying it in package.json file
"build": {
"extraResources": [
"./extraResources/**"
]
},
Can someone provide a solution for it,i have tested all examples but none of them worked
As it mentions in the documention (actual options documented here), you can add files using the extraResource option of the packagerConfig configuration.
extraResource
extraResource: string | string[]
One or more files to be copied directly into the app's
Contents/Resources directory for macOS target platforms, and the
resources directory for other target platforms. The resources
directory can be referenced in the packaged app via the
process.resourcesPath value.
For example, in your package.json file:
{
"config": {
"forge": {
"packagerConfig": {
"extraResource": [
"./src/extraResources/file.txt",
"./src/extraResources/folder"
]
}
}
}
}
The files will be placed in the process.resourcesPath directory when running npm run package.

Gatsby build path issues

Having issues running gatsby build with gatsby-starter-wordpress-advanced theme:
Error: ENOENT: no such file or directory, open 'C:\Users\Tobias\Desktop\Gatsby\gatsby-starter-wordpress-advanced\.template-cache\tmp-\.js'"
I figured this might be a problem with the path. The path should rather look like:
writing tmp-new-page/ template: open '.template-cache/tmp-new-page.js'
See repo: https://github.com/henrikwirth/gatsby-starter-wordpress-advanced/blob/master/create/utils.js
Line 53 you find the function createPageWithTemplate. I've tried console.log(page.uri) to see what's going on. It outputs the filename correctly. I've also tried with gatsby clean to clear the cache. It seems to be some kind of backslash issue where the path comes with a \ .js at the end instead of sample-page.js:
no such file or directory, open 'C:\Users\Tobias\Desktop\Gatsby\gatsby-starter-wordpress-advanced\.template-cache\sample-page\.js'
The issue have been resolved. The problem was related to update in WPGraphQL WordPress plugin. Had to update the paths, because the page.uri is different in the newer versions of WPGraphQL. Before it was just: some-page now it is /some-page/.
Secondly in the page template creation process the theme was using the uri, therefore, this messed up the paths for the template files. This has been switched to page.slug instead now and some extra checks, to make sure the frontPage is not ending up producing a wrong path.
The master branch of the starter theme have been updated.

Webpack/React json file not loading externally on build

Im trying to use the azure environment variables with my react build. So far I have an appsettings.json file that I load into react with:
import settings from './appsettings.json';
I then have webpack copy the json into build folder which goes to azure. However I think after build the app isnt actually loading the file as I can see some of my variables embedded in the "chunk.js" so its not actually reaching out the the json file in root anymore? Am I importing the file in the wrong way?
C
Two possible solutions:
var json = require('./data.json'); //with path
change your settings.json to settings.js and use module.exports = {} in it.
I believe azure would accept different forms of setting files, not limited to json.

Loading a needed file, relative vs absolute paths

We have a program people can compile on their machines. It has an HTTP interface but can also be invoked by command line.
In order to provide some nice-looking error pages for HTTP clients, we want to provide error pages. We are using a very simple solution with go's html/template package.
So in order for the program to find the templates, we currently do:
func init() {
prefStr := "path/to/http/tmpl"
pathPrefix,err := filepath.Abs(prefStr)
if err != nil {
log.Warn("Template path %s is not available!", prefStr)
}
pathPrefix + "/err.html"
}
Now when debugging the app, this usually works well - we are in the package's root directory, so filepath.Abs() resolves correctly, like so:
$GOPATH/github.com/user/repo/path/to/http/tmpl (expanding $GOPATH correctly)
But when we invoke the app via executable from the command line, this doesn't work. The command line could of course be invoked from anywhere on the filesystem, for convenience for example to provide a file in the current directory as a parameter.
In short, running /some/other/path/on/fs/our-executable filename.txt results in the init() function above breaking due to wrong concatenation of the directory: it takes /some/other/path/on/fs/ to create the absolute path, which is wrong. Thus it crashes with
panic: open /some/other/path/on/fs/path/to/http/tmpl/err.html: no such file or directory
I've searched and so far only found this:
How can I open files using relative paths in Go?
But this exactly doesn't apply for us.
Another solution proposes to bundle compiled go resources, but this seems rather odd as the error pages are html text.
We've also tried
https://stackoverflow.com/a/31464648/169252
but it has the same effect.
How can we make sure that the paths are always resolved correctly? This seems rather something which shouldn't be too difficult to be done, but we haven't managed so far.
EDIT: This is not an exact duplicate of the question How can I open files using relative paths in Go?. As already mentioned in my question text, I already had looked it up myself. It suggests to use filepath.Abs(). But as laid out in my question, for us this doesn't work, as if our executable is called from different places, filepath.Abs() doesn't return the same value, and thus doesn't work for us.
I think your challenge here is that people can install the program anywhere on the disk and the program will have to be smart enough to know where it is later on.
One of the common approach that I have seen is that people typically use environment variables to anchor them to the application's installation path. I believe you may have seen environment variables with naming pattern of *_HOME like JAVA_HOME, MAVEN_HOME and their values are always filepath to the installation place.
I guess you can do the same here. Force your users to have MYAPP_HOME variable define and at the start of the application make sure that it is set or else throw an error saying MYAPP_HOME is not set.
Then all you need to do would be a simple lookup of the value for MYAPP_HOME + /http/tmpl to source for the template html files.
Example:
package main
import "os"
func main() {
// Assuming MYAPP_HOME has been verified that it is set
// Then:
tmlPath := os.Getenv("MYAPP_HOME") + "/http/tmpl/"
errTml := tmlPath + "err.html"
}
If you're not keen on using the current working directory, or passing the directory in, you can find the absolute executable path by calling os.Executable from the os package.
appPath, err := os.Executable()
The os package will generally contain os specific stuff like how to get the current working directory. It's worth looking through the pkg docs and list of packages at golang.org if your'e ever stuck, as they are pretty good typically you'll find an answer there.
https://golang.org/pkg/os
Another approach you can take here if users install with go get is to rely on the fact that your templates will be installed with the pkg under GOPATH, so you can always find them at $GOPATH/src/your/project/path/templates (or ~/go the default gopath now that it is not strictly required).
The safest way is probably to bundle them with the binary in a virtual file system as this means you depend on nothing external and don't care where your app is hosted or even if it has access to files at all.
I recommend using a relative path in this case.
According to your description, it seems like you are developing a web application. While it works fine on individual developer's machine, you need to be mindful that your application can be deployed under any directory on your production server. You cannot determine where you app is going to be deployed, but you can always determine where static files are relative to the root directory of your app.
When you invoke your app in the command line, you should have all the required static files copied to the same relative path exactly the same with your development environment. My typical structure is:
project/
|- config.json
|- main.go
|- package1/
|- package2/
|- static/
|- templates/
| |- index.html
| |- base.html
|- css/
|- javascript/
|- image/
When you are ready to run your application from command line, be sure to copy your config.json and the static/ directory to the same level as your executable binary. Then all you need to do is to use relative paths in your code without any nightmares.
For the records: as we just have two templates, we resorted to store them as strings in a go file so that they get compiled. Our html templates are very simple, so this is a reasonable way to do it.

Resources