Cannot find node module in rails stimulus controller - javascript

I have a problem with importing an npm package that I have created into my rails application.
I'm unsure if the problem is in the way I have created the node package or with the rails app.
The package is very simple -> https://www.npmjs.com/package/test-release-stuff
Now when I'm trying to import it into rails (I install it vie yarn and then see it's in the node modules) and I try to import it into my stimulus controller it tells me that it can't find the module. The error literally says:
Error: Cannot find module 'test-release'stuff'
How I'm importing the module?
I'm doing import foo from 'test-release-stuff'
One thing to note is that when I tried that in a simple react todo app it was imported without any issues.
I have a feeling that it might be something with the webpacker config in my rails app (below is the config) or that it might be something with the node packaga packgage.json file, there might be something incorrect there.
const { webpackConfig, merge } = require('#rails/webpacker');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const plugins = [];
if (process.env.ANALYZE === 'true') {
plugins.push(new BundleAnalyzerPlugin());
}
const customConfig = {
resolve: {
extensions: ['.css'],
},
plugins: plugins,
};
module.exports = merge(webpackConfig, customConfig);
then in the production/development/test files I have something like this:
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
const webpackConfig = require('./base');
module.exports = webpackConfig;
It's a rails 6 project.

Turns out it was neither rails app fault or the node package fault.
I'm running the project inside the container. Although I installed once the previous version of that node package, when updating it, the changes were not properly reflected inside the container - I assume at some point the actual yarn command was not firing or that there was some caching involved.
After properly bringing the containers down, running docker-compose build and docker-compose up the changes were reflected and I can use the node package.

Related

Problem with the folder structure and dependencies

I have the following initial situation:
Our tests refer to a store that is available in multiple languages via country dropdown.
Depending on the country, the store has different features and therefore also different tests.
I have two problems here. The first is the folder structure
In order not to have a separate repo for each country, we would like to separate the test specs for the stores by folders.
But since the PageObjects are identical, I would like to define them only once, so that the test specs can access them.
However, it does not work as I imagine it.
Here is my idea of the folder structure in Cypress:
cypress-automation
cypress
fixtures
integration
shops
shop_de
sample-tests.spec.js
shop_en
sample-tests.spec.js
shop_es
sample-tests.spec.js
plugins
index.js
support
pageObjects
samplePageObject.js
index.js
commands.js
node_modules
cypress.json
package-lock.json
package.json
However, it doesn't work because Cypress misses the PageObjects. The following error occurs:
Error: webpack compilation error
./cypress/integration/shops/shop_en/sample-tests.spec.js
Module not found: Error: Unable to resolve '../support/pageObjects/samplePageObject.js' in 'C:\users\users\desktop\cypress-automation\cypress\integration\shops\shop_en'.
The second problem concerns the index.js
there I have to add a country switch in the beforeEach method, because the URLs of the stores are identical and the store can only be changed via dropdown.
Unfortunately I don't know how to integrate the index.js into the store folder, so that the sample-tests.spec.js access a specific index.js instead of a global one. Alternatively, I would have to adjust the beforeEach method in each sample-tests.spec.js but with so many test specs I find that impractical.
is that even possible, the way I imagine it?
EDIT:
#Fody
i did it exactly as you said. However, now I get an error:
PageObjects_homePage__WEBPACK_IMPORTED_MODULE_1_.HomePage is not a constructor
here is an example from my code how i included it:
import { HomePage } from "#PageObjects/homePage";
the constructor looks like this
const homePage = new HomePage();
HomePage Class:
class HomePage {
testMethod() {
testcode()
}
}
export default HomePage;
For part one, set up a webpack alias to make it easy to import from anywhere in the intergration folders, any level nesting.
Add the package Cypress Webpack Preprocessor, following their instructions
npm install --save-dev #cypress/webpack-preprocessor
npm install --save-dev #babel/core #babel/preset-env babel-loader webpack - if not already installed
or with yarn
yarn add -D #cypress/webpack-preprocessor
yarn add -D #babel/core #babel/preset-env babel-loader webpack - if not already installed
cypress/plugins.index.js
/// <reference types="cypress" />
const path = require('path');
const webpack = require('#cypress/webpack-preprocessor');
console.log('__dirname', __dirname) // __dirname is cypress/plugins
module.exports = (on) => {
const options = {
webpackOptions: {
resolve: {
alias: {
'#PageObjects': path.resolve(__dirname, '../../cypress/support/pageObjects')
},
},
},
watchOptions: {},
};
on('file:preprocessor', webpack(options));
};
cypress/integration/shops/shop_de/sample-tests.spec.js
// resolves any level of nesting
import {MyPageObject} from '#PageObjects/samplePageObject.js'
...
cypress/integration/shops/shop_de/bavaria/sample-tests.spec.jbs
// same import after move to sub-folder
import {MyPageObject} from '#PageObjects/samplePageObject.js'
...

Vue.js environment variables without vue-cli

What is the best way to load environment variables for Vue.js app without using vue-cli? In vue-cli way you just update the .env files and those variables should be available in Vue.js app like this: https://cli.vuejs.org/guide/mode-and-env.html#example-staging-mode
I am using Symfony Webpack Encore and have no vue-cli installed, how could I pass my environment variables into entire Vue application?
just create a .env file and create you variable like this VUE_APP_XXXXX
you notice the VUE_APP make sure all variable has the VUE_APP prefix like.
VUE_APP_API_URL
for development .env.development.
for production .env.production
Currently this looks like a decent way to load the configs: https://github.com/symfony/webpack-encore/issues/567
First install the dotenv package and then use this on my webpack.config.js:
const dotenv = require('dotenv');
.configureDefinePlugin(options => {
const dotenvOptions = {};
const envConfigPath = `.env.${process.env.NODE_ENV}`;
if (fs.existsSync(envConfigPath)) dotenvOptions.path = envConfigPath;
const env = dotenv.config(dotenvOptions);
if (env.error) {
throw env.error;
}
options['process.env'].PMP_API_BASE_URI = JSON.stringify(env.parsed.PMP_API_BASE_URI);
})
If .env.dev.local is needed then provide NODE_ENV=dev.local while running npm run build command.

Mocking external imports in development environment using Webpack and React

In my React Application I am using an API which is provided at runtime as a global variable by the Browser in which the application runs.
To make the Webpack compilation process work I have added this into the webpack config:
externals: {
overwolf : 'overwolf'
}
It is then imported like this
import overwolf from 'overwolf'
This works fine when I built my production application and run it inside the Browser.
However for the webpack development server, as well as my tests I want to be able to run them from a standard browser where the external will not be available. I am not quite sure how to make this work as the dev server will always complain about the import and my attempts to make conditional imports did not work out so far.
What I would like to achieve is to mock the overwolf variable, so that webpack dev server will compile and let me run my code with the mocked version.
My attempt was like this
import overwolf from 'overwolf'
export function overwolfWrapper() {
if(process.env.NODE_ENV !== 'production') {
return false;
}
else {
return overwolf;
}
}
Which results in the following error on the webpack development server
ReferenceError: overwolf is not defined
overwolf
C:/Users/jakob/Documents/private/projects/koreanbuilds-overwolf2/external "overwolf":1
One possible solution is to keep using the overwolf defined as an external (read more here), and use a polyfill for other browsers:
In your index.html include an overwolf.js script which will provide the mock object to use.
Example using HtmlWebpackPlugin and html-webpack-template to generate the index.html as part of the build process. Include in your plugins array:
new HtmlWebpackPlugin({
template: './node_modules/html-webpack-template/index.ejs',
inject: false,
scripts: ['/overwolf.js']
})
And this is an example for the included overwolf.js previously:
if (!window.overwolf) {
window.overwolf = {
foo() {
console.info('overwolf now has foo function!');
}
};
}
Hope this helps!
Check also this webpack-demo project. I think it would help you with some configurations.
I also found a rather simple solution on my own.
Instead of importing the external this also works:
const overwolf = process.env.NODE_ENV === 'production' ? require('overwolf') : new MockedOverwolf();
Webpack will not complain about this in the dev environment and in production require will still give me the real API.

Define globals when bundling to umd or commonjs

I have a client-side application which makes use of some browser global properties like Element or document.
I'd like to run my application in node.js as well and currently I am overriding those globals with the domino dom implementation in my server like so:
const domino = require("domino");
const domimpl = domino.createDOMImplementation();
const document = domimpl.createHTMLDocument();
Object.assign(global, Element: domino.impl.Element, document};
const myApp = require('my-app');
I am currently using rollup to bundle different versions of my-app, how can I have rollup do this for me automatically for the _server version of my-app so consumers of my-app don't have to do that?
I was thinking of writing my own rollup plugin but I feel like overriding globals seems like a common practice.
TLDR; Use separate entry file instead of a rollup plugin.
Simply add the following instead of a rollup plugin
if (typeof window ==== "undefined") {
const domino = require("domino");
const domimpl = domino.createDOMImplementation();
const document = domimpl.createHTMLDocument();
Object.assign(global, Element: domino.impl.Element, document};
}
// my-app code
You might be worried about domino entering client side code. To fix this, use separate bundles for server and client, wrap the above mocking code in a separate file and use the following in your my-app’s main file meant for the server bundle, an approach similar to how React ships production and development bundles - conditional imports.
Server main file
require(‘./globals-mocking’);
// my-app client code
Client main file
// my-app client code only
package’s main file
if (SERVER_ONLY) {
module.exports = require('./my-app-server.js');
} else {
module.exports = require('./my-app-client.js');
}
Use rollup's replace plugin and define SERVER_ONLY (https://github.com/rollup/rollup-plugin-replace#usage) for server entry only. If you use UglifyJS or simlilar tool that eliminates dead code, you wont have domino and duplicated server code.
EDIT: Noticed a minor issue. Condition should be if (SERVER_ONLY) {. Use the following definition along with it for the server entry file.
plugins: [
replace({
SERVER_ONLY: JSON.stringify(true)
})
]

Is it possible to use dotenv in a react project?

I am trying to set some environment variables (for making API calls to dev/prod endpoints, keys depending on dev/prod, etc.) and I'm wondering if using dotenv will work.
I've installed dotenv, and I am using webpack.
My webpack entry is main.js, so in this file I've put require('dotenv').config()
Then, in my webpack config, I've put this:
new webpack.EnvironmentPlugin([
'NODE_ENV',
'__DEV_BASE_URL__' //base url for dev api endpoints
])
However, it is still undefined. How can I do this correctly?
Sorry for picking up old question, but
react-scripts actually uses dotenv library under the hood.
With react-scripts#0.2.3 and higher, you can work with environment variables this way:
create .env file in the root of the project
set environment variables starting with REACT_APP_ there
access it by process.env.REACT_APP_... in components
.env
REACT_APP_BASE_URL=http://localhost:3000
App.js
const BASE_URL = process.env.REACT_APP_BASE_URL;
See docs for more details.
The short answer is no. A browser cannot access local or server environment variables so dotenv has nothing to look for. Instead, you specify ordinary variables in your React application, usually in a settings module.
Webpack can be made to take environment variables from the build machine and bake them into your settings files. However, it works be actually replacing strings at build-time, not run-time. So each build of your application will have the values hard-coded into it. These values would then be accessible through the process.env object.
var nodeEnv = process.env.NODE_ENV;
Additionally, you could use the DefinePlugin for webpack which lets you explicitly specify different values depending on your build target (dev, prod, etc.). Note that you have to JSON.stringify all values passed into it.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
This is fine for any sort of public details but should never be used for any sort of private keys, passwords or API secrets. This is because any values baked in are publicly accessible and could be used maliciously if they contain sensitive details. For those sorts of things, you need to write some server-side code and build a simple API which can authenticate with the 3rd party API using the secrets, then pass the relevant details along to your client-side application. Your server-side API acts as an intermediary, protecting your secrets while still getting the data you need.
Create .env file
API_URL=http://localhost:8000
Install dotenv npm package
$ npm install --save-dev dotenv
Config webpack to add env variables
const webpack = require('webpack');
const dotenv = require('dotenv');
module.exports = () => {
// call dotenv and it will return an Object with a parsed key
const env = dotenv.config().parsed;
// reduce it to a nice object, the same as before
const envKeys = Object.keys(env).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
return prev;
}, {});
return {
plugins: [
new webpack.DefinePlugin(envKeys)
]
};
Great job! Enjoy React and dotenv.
Actually, you can use dotenv in your React app with webpack. Moreover, there are several ways of doing it. However, keep in mind that it's still a build-time configuration.
A similar way to the answer above. You import dotenv in your webpack config and use DefinePlugin to pass the variables to your React app. More complete guide on how you can inject your .env files depending on current configuration could be found in this blog.
Using a dotenv-webpack plugin. I personally find it really convenient. Let's say you have environments: dev, staging and prod. You create .env file for each environment (.env.dev, .env.staging, etc). In your webpack configuration you need to pick a correct file for the environment:
const Dotenv = require('dotenv-webpack');
module.exports = (env, argv) => {
const envPath = env.ENVIRONMENT ? `.env.${env.ENVIRONMENT}` : '.env';
const config = {
...
plugins: [
new Dotenv({
path: envPath
})
]
};
return config;
};
When you build the app for a particular environment, just pass the environment name to webpack:
webpack --config webpack.config.js --env.ENVIRONMENT=dev
I Just created a config.json in the source folder:
{
"api_url" : "http://localhost:8080/"
}
then required it in the file I needed it
const config = require('./config.json');
and used config.api_url

Categories