How to setup StencilJS components on S3 and CloudFront - node.js

I have a few components and I want to deploy them into S3 and make them reachable with CloudFront.
My problem is that I don't know what file(s) I need to upload to S3 and which file needs CloudFront needs to point to as entry point.
Here's my stencil.config.tsx:
import { Config } from '#stencil/core';
export const config: Config = {
namespace: 'stencil-test',
taskQueue: 'async',
outputTargets: [
{
type: 'dist',
esmLoaderPath: '../loader',
dir: './build/dist'
},
{
type: 'www',
serviceWorker: null // disable service workers
}
]
};
I tried executing npm run build that generated a couple of folders: build/loader and build/dist there's a lot of stuff within each folder but I have no idea how which folder and files are supposed to do what.
It was hoping the build command would generate a minified file that contained all the stuff needed (is this how it works?) so I could eventually do something like the following where I want to use my components:
<script type="module" src='https://cdn.jsdelivr.net/npm/my-name#0.0.1/dist/myname.js'></script>
Can anyone offer some guidance or point me towards any resources?

The www output target is meant for generating apps and not really relevant for component libraries. To host your components, you should upload the whole generated dist folder. Only the files that the client needs are downloaded, which depends on the client and which components they access (lazy-loading). So you don't need to worry about the amount of files. See https://stenciljs.com/docs/distribution.
To start, Stencil was designed to lazy-load itself only when the component was actually used on a page. There are many benefits to this approach, such as simply adding a script tag to any page and the entire library is available for use, yet only the components actually used are downloaded.
If you want to generate a single bundle containing all your components, there's an output target called dist-custom-elements-bundle. For the differences to dist you can have a look at the same docs link above.
One of the main differences is that loading the script doesn't automatically register the components for you, you'll have to either do it manually per component (using customElements.define(), or define them all using the defineCustomElements() export. The official documentation for that output target is https://stenciljs.com/docs/custom-elements.

Related

AppImage from electron-builder with file system not working

I’m using Electron Builder to compile my Electron app to an .AppImage file, and I’m using the fs module to write to an .json file, but it’s not working in the appimage format (it’s working fine when I have the normal version not made with Electron Builder). I can still read from the file.
The code (preload):
setSettings: (value) => {fs.writeFileSync(path.join(__dirname, "settings.json"), JSON.stringify(value), "utf8")}
The code (on the website):
api.setSettings(settings);
The project: https://github.com/Nils75owo/crazyshit
That's not a problem with AppImage or Electron Builder but with the way you're packaging your app. Since you didn't post your package.json*, I can only guess what's wrong, but probably you haven't changed Electron Builder's default behaviour regarding packing your application.
By default, Electron Builder compiles your application, including all resources, into a single archive file in the ASAR format (think of it like the TAR format). Electron includes a patched version of the fs module to be able to read from the ASAR file, but writing to it is obviously not supported.
You have two options to mitigate this problem: Either you store your settings somewhere in the user's directory (which is the way I'd go, see below) or you refrain from packing your application to an ASAR file, but that will leave all your JavaScript code outside the executable in a simple folder. (Note that ASAR is not capable of keeping your code confidential, because there are applications which can extract such archives, but it makes it at least a little harder for attackers or curious eyes to get a copy of your code.)
To disable packing to ASAR, simply tell Electron Builder that you don't want it to compile an archive. Thus, in your package.json, include the following:
{
// ... other options
"build": {
// ... other build options
"asar": false
}
}
However, as I mentioned above, it's probably wiser to store settings in a common place where advanced users can actually find (and probably edit, mostly for troubleshooting) them. On Linux, one such folder would be ~/.config, where you could create a subdirectory for your application.
To get the specific application data path on a cross-platform basis, you can query Electron's app module from within the main process. You can do so like this:
const { app } = require ("electron"),
path = require ("path");
var configPath;
try {
configPath = path.join (app.getPath ("appData"), "your-app-name");
} catch (error) {
console.error (error);
app.quit ();
}
If you however have correctly set your application's name (by using app.setName ("...");), you can instead simply use app.getPath ("userData"); and omit the path joining. Take a look at the documentation!
For my Electron Applications, I typically choose to store settings in a common hidden directory (one example for a name could be the brand under which you plan to market the application) in the user's home directory and I then have separate directories for each application. But how you organise this is up to you completely.
* For the future, please refrain from directing us to a GitHub repository and instead include all information (and code is information too) needed to replicate/understand your problem in your question. That'd save us a lot of time and could potentially get you answers faster. Thanks!

Gatsby Failed Build - error "window" is not available during server side rendering

I have been trying to build my gatsby (react) site recently using an external package.
The link to this package is "https://github.com/transitive-bullshit/react-particle-animation".
As I only have the option to change the props from the components detail, I cannot read/write the package file where it all gets together in the end as it is not included in the public folder of 'gatsby-build'.
What I have tried:
Editing the package file locally, which worked only on my machine but when I push it to netlify, which just receives the public folder and the corresponding package.json files and not the 'node-modules folder', I cannot make netlify read the file that I myself changed, as it requests it directly from the github page.
As a solution I found from a comment to this question, we can use the "Patch-Package" to save our fixes to the node module and then use it wherever we want.
This actually worked for me!
To explain how I fixed it: (As most of it is already written in the "Patch Package DOCS), so mentioning the main points:
I first made changes to my local package files that were giving the error.(For me they were in my node_modules folder)
Then I used the Patch Package Documentation to guide my self through the rest.
It worked after I pushed my changes to github such that now, Patch Package always gives me my edited version of the node_module.
When dealing with third-party modules that use window in Gatsby you need to add a null loader to its own webpack configuration to avoid the transpilation during the SSR (Server-Side Rendering). This is because gatsby develop occurs in the browser (where there is a window) while gatsby build occurs in the Node server where obviously there isn't a window or other global objects (because they are not even defined yet).
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
if (stage === "build-html") {
actions.setWebpackConfig({
module: {
rules: [
{
test: /react-particle-animation/,
use: loaders.null(),
},
],
},
})
}
}
Keep in mind that the test value is a regular expression that will match a folder under node_modules so, ensure that the /react-particle-animation/ is the right name.
Using a patch-package may work but keep in mind that you are adding an extra package, another bundled file that could potentially affect the performance of the site. The proposed snippet is a built-in solution that is fired when you build your application.

React dynamic image importing in development

I am building a React application which needs to display images dynamically which are stored, by the thousands, on a server-side file system. All of my attempts to successfully implement this have failed, including many which were taken from responses to similar questions.
Some details:
I used create-react-app to initialize my application. I am running in development mode (have not run npm-build). I'm using Express.js (Node.js) as a web-server, which I interact with through a proxy (only '/api' http requests use the proxy). My js code which attempts to 'require' the images is in the 'src' folder. The images are located in an 'images' folder in the default 'public' folder.
I thought I had found the solution when reading this page from create-react-app, as it states to use the public folder when 'You have thousands of images and need to dynamically reference their paths'. The page further instructs to use '%PUBLIC_URL%' or 'process.env.PUBLIC_URL' to access the 'public' folder. When using either of these I receive an 'Error: Cannot find module' message. Upon checking I notice that 'process.env.PUBLIC_URL' contains an empty string, and quickly notice that PUBLIC_URL is ignored in development mode.
I find this to be tremendously confusing, given that the 'Using the Public Folder' page is apparently describing the development phase of production, and yet it advises the use of something which is meaningless during development. Adding to my confusion, it appears as if the contents of that page resolved the issue for nearly all of those who have encountered a similar requirement in the past (example: 1, example: 2; both fail for me). Likewise, all attempts to to construct relative paths to the 'public' folder from the 'src' folder have yielded error messages. Failed code example:
let img = process.env.PUBLIC_URL + '/images/Team.jpg';
<img src={require(`${img}`)} alt="X" />
Error: Cannot find module '/images/Team.jpg'
I never imagined showing images in React would be so difficult. Any help is truly very much appreciated.
I think you are correct, you just don't need the require, return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />; as you can see their docs
If you open in your browser http://localhost:PORT/images/Team.jpg that should open.
That's the reason process.env.PUBLIC_URL is empty in development, because they resolve everything inside this folder directly.

Route static page with vue-router

I'm fairly new to web development and I was wondering if there was a way to route a static web page with its own stylesheets and javascripts, using vue-router.
Let's say I have a directory called staticWebPage that contains:
an index.html file
a javascripts directory containing .js files
and a stylesheets directory containing .css files
Now, I'd like to map /mystaticwebpage to this index.html file so it displays that particular static web page.
I'd like to do something like this:
import VueRouter from 'vue-router'
import AComponent from './components/AComponent.vue'
import MyHtmlFile from './references/index.html'
router.map({
'/acomponent': {
component: AComponent
},
'mystaticwebpage': {
component: MyHtmlFile
}
})
Of course, this doesn't work as I can only reference Vue components in router.map.
Is there a way to route to that ./staticWebPage/index.html file using all the .js and .css file contained in the /staticWebPage directory?
So for your case you can do something that uses Webpack’s code-splitting feature.
More precisely, what you want is probably async components. So the code (and the css) used in the component definition (including any script you included there) will be loaded only when the corresponding page is accessed.
In large applications, we may need to divide the app into smaller
chunks and only load a component from the server when it’s actually
needed. To make that easier, Vue allows you to define your component
as a factory function that asynchronously resolves your component
definition. Vue will only trigger the factory function when the
component actually needs to be rendered and will cache the result for
future re-renders.
It can be a bit challenging to setup, so please refer to the dedicated guide in the VueJS doc.

Adding paths to RequireJS configuration on runtime

Ok, I already know that you should configure paths with RequireJS like this
require.config({
paths: {
name: 'value'
}
});
And call it like this.
require(['name'], function() {
/* loaded */
});
But the thing is, I'm working in environment in which I don't have access to the existing call to require.config(...). For those who care, the environment is Azure Mobile Services scheduled job. Microsoft has already included RequireJS in the environment and configured the paths. My question is two-fold.
1. How do I add paths to the existing require.config()?
I know calling require.config() again will destroy the existing configuration. Which is what I do not want to do.
2. How do I get to know which paths have already been configured?
I really wouldn't like to overwrite any existing path name or overwrite any existing library by accident.
Running require.config() again does not override your original config file. It actually extends it and adds your new paths to it. Right now I am using it this way, where configfile is also a require.config({})
<script data-main="configfile" src="require.js"></script>
<script>
require.config({
paths: {
prefix-name: 'path/to/file'
}
});
</script>
One way to avoid name collisions with Azure Mobile paths would be to simply prefix all your custom paths.
Disclaimer: I have never used Azure Mobile, just RequireJs. You may have to implement it a little differently but it is possible.

Resources