Given I have an environment variable $KEY
I am running
KEY=$KEY babel-node build.js //with webpack I make a bundle of my code
My problem is that in js files that webpack bundles there is import to a config.js file.
the config.js looks like this:
export default {
key: process.env.KEY;
};
When the value is used in the bundle the key is undefined.
How can I achieve this kind of behaviour. (something like actually overwriting the value config.js with the environment variables and then bundle them with webpack) ?
You can achieve that by using the DefinePlugin which exposes for the bundle the specified env variables.
new webpack.DefinePlugin({
KEY: JSON.stringify('process.env.KEY')
});
Related
When i do npm install react-slick, i get the following in my node_modules folder:
Now in my react application in a src/index.js file, when i do the following:
import Slider from "react-slick";
How does webpack know where to pick slider from ? will it at all look for some clue or definition inside node_modules/react-slick/package.json at all ?
Edit :- so here is the package.json file for webpack, when i import Slider from 'react-slick' , does it resolve to dist or lib ? and which file does it pick then and why ?
Well, the simple walkthrough of it will be as below:
Simple Walkthrough
If you carefully look at the node_modules/react-slick/package.json there is a property named main. Something like this:
{
"name": "react-slick",
"main": "index.js"
}
It will tell the Webpack which file is the entry file of the whole package (It's usually referred to index.js). All the necessary exports for the package lies in this file, so Webpack will only look for those exports and will import what you looking for. In this particular case, there should be a default export for the Slider that you using right now. So the index.js is probably something like this:
// index.js
var slider = require('./lib/slider'); // Usually all the main modules are lies under lib folder.
// other imports ...
module.exports = slider;
Difference between lib and dist
Usually, the dist folder is for shipping a UMD that a user can use if they aren't using package management. The lib folder is what package.json, main property points to, and users that install your package using npm will consume that directly. The only use of the lib as opposed to src is to transform your source using babel and Webpack to be more generally compatible since most build processes don't run babel transforms on packages in node_modules.
Webpack uses aliases to target node_modules using a shorthand.
Example #1:
import 'xyz'
/abc/node_modules/xyz/index.js
Example #2:
import 'xyz/file.js'
/abc/node_modules/xyz/file.js
Once it targets the correct folder in node_modules, it follows the rules written in the package itself (manifest, package.json)
You can also define your own aliases as such:
webpack.config.js
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
xyz$: path.resolve(__dirname, 'path/to/file.js')
}
}
};
And then can be used as import xyz from $xyz
I am having trouble declaring globals in Typescript, using Webpack's DefinePlugin. I was hoping to get some input on what I am doing wrong.
I created an environment variable in my .bash_profile:
export API_KEY_GOOGLE_MAPS=xxxxxxxxxxxxxxxx
In my webpack.config.js, I have the following lines:
...
plugins: [
new webpack.DefinePlugin({
API_KEY_GOOGLE_MAPS: JSON.stringify(process.env.API_KEY_GOOGLE_MAPS),
}),
],
...
Inside index.tsx (I am using React), I do the following:
declare var API_KEY_GOOGLE_MAPS: string;
console.log(API_KEY_GOOGLE_MAPS)
This produces the following error, at the line containing console.log:
ReferenceError: API_KEY_GOOGLE_MAPS is not defined
Does anybody have any leads?
The other answers require create-react-app so I will offer mine.
First, add the plugin to your Webpack configuration:
const webpack = require("webpack");
module.exports = {
// ...
plugins: [
new webpack.DefinePlugin({
MY_ENV_VAR: JSON.stringify(true),
}),
],
};
Next, declare the variable in TypeScript:
declare var MY_ENV_VAR : string | undefined;
Finally, you can access the variable in your code:
console.log(MY_ENV_VAR);
create-react-app environment variables should be prefixed with REACT_APP_:
Note: You must create custom environment variables beginning with REACT_APP_. Any other variables except NODE_ENV will be ignored to avoid accidentally exposing a private key on the machine that could have the same name. Changing any environment variables will require you to restart the development server if it is running.
from the "Adding Custom Environment Variables" documentation.
You should be adding these environment variables to your .env file(s) in place of adding these to your .bash_profile file. The appropriate file will be picked up depending on the build (i.e. start or build), and the application will be easier to share and deploy.
The way I do it is to have a .env file(add it to .gitignore) in the root of my project files.
Within that file I define my project environment variables(additional variables can be separated by adding each to it's own line):
NODE_ENV=development
Then using the dotenv npm module I can access the values in any webpack file(or server side expressJS file for example).
// in the command line
$ npm install --save dotenv
// at the top of the webpack config file
require('dotenv').config();
// in the plugins of the webpack config
plugins: [
new webpack.DefinePlugin({
'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
],
Now I can reference it within my app being transpiled by webpack:
console.log(NODE_ENV); // development
Answering my own question: my project was generated using create-react-app, and according to its documentation, environment variables are accessed this way:
console.log(process.env.API_KEY_GOOGLE_MAPS)
webpack.DefinePlugin() is not required.
OK so I have an interesting situation in setting up my Node.js TypeScript project. I want to be able to refer to my local modules using a non-relative require reference. The way TypeScript and Node.js look up modules is to look for a node_modules directory in the current directory and then each parent directory until they find such a directory containing the reference. So let's say I have a module I want to reference in the following directory structure:
/node_modules <-- Main NPM modules dir
/...
/package.json
/src
/node_modules <-- My local modules dir
/modules
/myModule.ts
/scripts
/init.ts
... and in init.ts I reference myModule like this:
import myModule from "modules/myModule";
As I understand it, I want TypeScript to transpile my node_modules directory over to the output dist directory along with all my other .ts file directories, so that the dist directory looks like this:
/node_modules <-- Main NPM modules dir
/...
/package.json
/dist
/node_modules <-- My local modules dir
/modules
/myModule.js
/scripts
/init.js
Then, when Node.js looks for the module it will find it at dist/node_modules/modules/myModule.js. So in this case I actually do want TypeScript to include the node_modules directory in its input files. I seem to be missing something fundamental, though, because TypeScript actually ignores this directory by default.
Is my scenario a legitimate one for including the node_modules directory, and if so, how can I make TypeScript include it in the transpilation when I just run tsc (and therefore it will use my tsconfig.json file)?
UPDATE:
I have found that I can make it include my node_modules directory by explicitly putting it in the include directive in the .tsconfig.json like so:
"include": [
"./src/node_modules/**/*",
"./src/**/*"
]
The question remains; am I getting something fundamentally wrong here, because I am having to override something TypeScript excludes by default? I've tested this and when I make it transpile node_modules, it does indeed find my local modules correctly.
That's not correct to include node_modules for transpilation. Because node_modules contains javascript and doesn't requires second transpilation in case of ts libraries, they should have declarations in .d.ts.
If you have custom types, or you want to add types to some libraries that don't have them, you need to use own declarations or #types/* packages.
in your tsconfig.json you can define type roots (where to load declarations from).
{
"compilerOptions": {
"typeRoots": ["./declarations", "./node_modules/#types"],
"types": ["node"],
}
}
then you can install npm i --save-dev #types/node#^12 for example to get declarations of nodejs v12.
and define your own declarations in declarations for express for example: ./declarations/express/index.d.ts
import * as express from 'express';
declare module 'express' {
export interface Request {
user?: {
id: string;
name: string;
}
}
}
I created a project using ng.
I called ng eject to get a webpack.config.js.
I added pug to the webpack.
I want to pass the data from src/environments/environment.ts to pug but I can't figure out how to require the typescript file from a normal javascript file.
I can always change environment.ts to a json file or javascript file but would like to leave it the way it is.
Here is the environment.ts file
export const environment = {
production: false,
title: 'My App DEV'
};
As long as it is actually valid JavaScript (not TypeScript), as your example is, then yes. You'll just need to include/require it including the extensions:
require('./environment.ts');
// or
import environment from './environment.ts';
If it were to contain TypeScript code, you'd need to transpile it to regular JavaScript at some point. Where/when/how you do that would be up to your build pipeline.
I wrote a library written in typescript and I use webpack to bundle it into a single, minified js file that exports the library as one global variable. I want to distribute these typings for the developers on my team. They are not typescript users so they would be importing the library itself via a <script src="..."> tag and they would import the typings using the triple slash reference directive /// <reference path="..." /> or typings or something similar.
The question is then:
How do I enable typings (i.e., the intellisense) for my library for the js developers that use vs code? How do I declare that there is one global variable that exports the values that my entry point does?
I have enabled the declarationDir and declartion compiler options to create create the declaration files (*.d.ts) for all my typescript source files but these declarations don't declare that there is a global variable available with the methods.
I've tried manually creating a index.d.ts declaration in the same folder where the bundle and minified index.js file is but I can't get it to work.
Here is what I tried:
import * as myModule from './typings/src/';
declare module TheGlobalVariable {
// how do I declare that `TheGlobalVariable` has the same methods
// as `myModule` exports?
export = myModule; // doesn't work
}
where ./typings/src/index.d.ts is the generated declaration file for the entry point of this library and TheGlobalVariable is the name of the global variables webpack exports.
Any ideas?
Oh I figured it out.
In the same folder where my bundled js library file is (index.js), I added a file index.d.ts. Here is that file:
export * from './src';
export as namespace OntologyStore;
The key enabler is the export as ....
Refer to this module template and this documentation on library structures.
Also change the webpack libraryTarget to 'umd'. UMD modules check to see if there is a module loader and if there isn't it will export to a global. Also I didn't have to use the declaration or declarationDir compiler options.
Use this structure, https://github.com/botika/typescript-package.
Only follow a README.md