I've never used Webpack before and I'm working on a project that's just vanilla JS and HTML. I'm having an issue accessing the values I set in .env. Here's my config.
const path = require("path");
const dotenv = require('dotenv');
var webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const Dotenv = require('dotenv-webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = () => {
env = dotenv.config().parsed;
const envKeys = Object.keys(env).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
return prev;
}, {});
return {
entry: {
main: './src/index.js'
},
output: {
path: path.join(__dirname, '../build'),
filename: '[name].bundle.js'
},
mode: 'development',
devServer: {
contentBase: "./src/",
publicPath: "./src/",
compress: true,
port: 9000,
overlay: true,
disableHostCheck: true
},
devtool: 'inline-source-map',
resolve: {
alias: {
process: "process/browser"
}},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'assets/'
}
}
]
},
{
test: /\.html$/,
use: {
loader: 'html-loader',
options: {
//attributes: ['img:src', ':data-src'],
minimize: true
}
}
}
]
},
plugins: [
new webpack.ProvidePlugin({
process: 'process/browser',
}),
new Dotenv(),
new webpack.DefinePlugin(envKeys),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html'
}),
]
}
};
As you can see, I'm using dotEnv, definePlugin, and even the dotEnv-webpack plugin. Unfortunately, none of these solutions seem to allow me to access process.env.originURL.
originURL=https://localhost:3000
I'm not importing or requiring anything in my javascript file, index.js. I'm assuming this should work, but the console tells me that process is undefined.
console.log(process.env.originURL);
How can I access process.env.originURL in my index.js?
It should work. Maybe you could try this version:
new Dotenv({ systemvars: true })
If it still doesn't work, please show your package.json, as well as you .env file (randomize the values of course). Is .env at the root of you app?
Related
I'm currently using TS + React to make a simple application with some API requests to a server. When I try to use io-ts to decode the response, webpack responds with Module not found: Error: Can't resolve '../shared/Response' - if I remove the usage of io-ts to decode the response, I don't get that error.
My folder structure is
src
client
PlayerTimer.tsx
<skipped>
server
<skipped>
shared
Phase.d.ts
Response.d.ts
Phase.d.ts contains the following:
import * as t from 'io-ts';
export const PhaseDecode = t.union([
t.literal(1),
t.literal(2),
t.literal(3),
t.literal(4),
t.literal(5),
]);
export type Phase = t.TypeOf<typeof PhaseDecode>
Response.d.ts contains the following:
import * as t from 'io-ts';
import { DateFromISOString as IoDate } from 'io-ts-types/DateFromISOString';
import { PhaseDecode } from './Phase';
const ApiResponseDecode = t.type({
turnNumber: t.number,
phase: PhaseDecode,
breakingNews: t.union([t.string, t.null]),
active: t.boolean,
phaseEnd: IoDate
});
type ApiResponse = t.TypeOf<typeof ApiResponseDecode>
export { ApiResponseDecode, ApiResponse as default };
PlayerTimer.tsx contains a bunch of React components, but this is reproducible with just the following code at the top
import { ApiResponseDecode } from '../shared/Response';
const temp = {};
if (ApiResponseDecode.is(temp)) {
console.log('Webpack fails');
}
My webpack config is:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const outputDirectory = 'dist';
module.exports = {
entry: ['babel-polyfill', './src/client/index.tsx'],
output: {
path: path.join(__dirname, outputDirectory),
filename: './js/[name].bundle.js'
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
enforce: 'pre',
test: /\.js$/,
loader: 'source-map-loader'
},
{
test: /\.less$/,
use: [
{ loader: 'style-loader' },
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: './Less',
hmr: process.env.NODE_ENV === 'development',
},
},
{ loader: 'css-loader' },
{
loader: 'less-loader',
options: {
strictMath: true,
noIeCompat: true,
}
},
]
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
],
},
{
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000'
},
]
},
resolve: {
extensions: ['*', '.ts', '.tsx', '.js', '.jsx', '.json', '.less']
},
devServer: {
port: 3000,
open: true,
hot: true,
historyApiFallback: true,
proxy: {
'/api/**': {
target: 'http://localhost:8050',
secure: false,
changeOrigin: true
}
}
},
plugins: [
new CleanWebpackPlugin([outputDirectory]),
new HtmlWebpackPlugin({
template: './public/index.html',
favicon: './public/favicon.ico',
title: 'Test application',
}),
new MiniCssExtractPlugin({
filename: './css/[name].css',
chunkFilename: './css/[id].css',
}),
new CopyPlugin([
{ from: './src/client/Assets', to: 'assets' },
])
],
};
I fixed this by moving the type definitions and the io-ts definitions into separate files. I don't really understand why that works but I'll add this incase someone else finds this
I've got webpack up and running and can't quite figure our how to get .scss file compiled to be used with custom styling such as colors etc. Bootstrap is otherwise loaded fine.
Here's my webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = (env = {}, argv = {}) => {
const isProd = argv.mode === 'production';
const config = {
mode: argv.mode || 'development', // we default to development when no 'mode' arg is passed
optimization: {
minimize: true
},
entry: {
main: './src/main.js'
},
output: {
filename: isProd ? 'bundle-[chunkHash].js' : '[name].js',
path: path.resolve(__dirname, '../wwwroot/dist'),
publicPath: "/dist/"
},
plugins: [
new MiniCssExtractPlugin({
filename: isProd ? 'style-[contenthash].css' : 'style.css'
}),
new CompressionPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$|\.eot?.+$|\.ttf?.+$|\.woff?.+$|\.svg?.+$/,
threshold: 10240,
minRatio: 0.8
}),
new HtmlWebpackPlugin({
template: '_LayoutTemplate.cshtml',
filename: '../../Views/Shared/_Layout.cshtml', //the output root here is /wwwroot/dist so we ../../
inject: false
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
},
{
test: /\.(png|jpg|gif|woff|woff2|eot|ttf|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'assets/'
}
}
]
}
};
return config;
};
I have node-sass installed which I think compiles it? Just not sure how to get it going.
Thanks,
You need to import your CSS into your entrypoint. So in main.js, import your scss file like this...
import './path-to/file.scss
I have a simple HMR setup for reloading typescript files and postcss files. And they work perfectly well and modules reload without a page refresh. But when I change my HTML files, the website doesn't reload on it's own and the HTML content is not being hot-reloaded in.
This is my webpack config file:
const { resolve } = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: resolve(__dirname, 'src/main.ts'),
output: {
path: resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'awesome-typescript-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
}
]
}
]
},
devtool: 'source-map',
mode: 'development',
plugins: [
new HtmlWebpackPlugin({
template: resolve(__dirname, './src/index.html'),
}),
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(resolve(__dirname, 'dist'))
],
devServer: {
contentBase: resolve(__dirname, 'dist'),
port: 9000,
hot: true,
open: true,
progress: true,
}
}
With webpack 5,this setting is work for me:
devServer: {
hot:true,
open:true,
watchFiles: ['src/**/*']
},
webpack-dev-server github issue #3881
Problem is that html-webpack-plugin doesn't react to change and doesn't trigger the hmr.
In order to achieve that you could try something like this:
const { resolve } = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
let devServer; // set below in devserver part
function reloadHtml() {
this.plugin('compilation',
thing => thing.plugin('html-webpack-plugin-after-emit', trigger));
const cache = {};
function trigger(data, callback) {
const orig = cache[data.outputName];
const html = data.html.source();
if (orig && orig !== html)
devServer.sockWrite(devServer.sockets, 'content-changed');
cache[data.outputName] = html;
callback();
}
}
module.exports = {
entry: resolve(__dirname, 'src/main.ts'),
output: {
path: resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'awesome-typescript-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
}
]
}
]
},
devtool: 'source-map',
mode: 'development',
plugins: [
reloadHtml,
new HtmlWebpackPlugin({
template: resolve(__dirname, './src/index.html'),
}),
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(resolve(__dirname, 'dist'))
],
devServer: {
before(app, server) {
devServer = server;
},
contentBase: resolve(__dirname, 'dist'),
port: 9000,
hot: true,
open: true,
progress: true,
}
}
If you get :
DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
You can change reloadHtml to this:
function reloadHtml() {
const cache = {}
const plugin = {name: 'CustomHtmlReloadPlugin'}
this.hooks.compilation.tap(plugin, compilation => {
compilation.hooks.htmlWebpackPluginAfterEmit.tap(plugin, data => {
const orig = cache[data.outputName]
const html = data.html.source()
if (orig && orig !== html) {
devServer.sockWrite(devServer.sockets, 'content-changed')
}
cache[data.outputName] = html
})
})
}
Not sure if this is the case, but if you only want to extend your current HMR config to do a browser reload when your outer html/view files changed, then you can do it with a few extra lines using chokidar.
Maybe you already have it, because webpack-dev-server is using chokidar internally, but if not found then install it first with npm or yarn:
npm install chokidar --save
yarn add -D chokidar
Then require it in your webpack config:
const chokidar = require('chokidar');
Then in your devServer config:
devServer: {
before(app, server) {
chokidar.watch([
'./src/views/**/*.html'
]).on('all', function() {
server.sockWrite(server.sockets, 'content-changed');
})
},
Also check the API for more options.
I'm using it with Webpack4. Don't know if it works with earlier versions...
Hope it helps you or others looking for this situation.
I have posted my Webpack configs below for a production environment. I am attempting to use background-image: url(../img/chevron-thin-right.svg); in one of my SCSS files but it is being resolved to background-image: url([object Module]) and therefore not working. I am trying to port a purely SCSS and HTML project into a react app being bundled by Webpack so this above approach used to work. Any fixes would be greatly appreciated.
webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const outputDirectory = 'dist';
module.exports = {
entry: './src/client/index.js',
output: {
path: path.join(__dirname, outputDirectory),
filename: 'bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Production',
template: './public/index.html',
favicon: './public/favicon.ico',
hash: true,
filename: 'index.html'
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.(jpg|png|woff|woff2|eot|ttf)$/,
use: {
loader: 'file-loader?limit=100000&name=images/[name].[ext]'
}
},
{
test: /\.svg$/,
use: [
"babel-loader",
{
loader: "react-svg-loader",
options: {
svgo: {
plugins: [
{
removeTitle: true,
removeComments: true
}
],
floatPrecision: 2
}
}
}
]
}
]
}
};
webpack.prod.js
const merge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const common = require('./webpack.common.js');
const path = require('path');
const autoprefixer = require('autoprefixer');
module.exports = {};
module.exports = merge(common, {
mode: 'production',
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
}
}
}
},
plugins: [
new CleanWebpackPlugin(['dist']),
new MiniCssExtractPlugin({
filename: '[name].css'
})
],
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
root: path.resolve(__dirname),
},
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
autoprefixer({
'browsers': ['last 2 versions', 'ie >= 10'],
}),
],
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
outputStyle: 'compressed',
sourceMap: true,
includePaths: [
'./src/client/style/scss',
],
},
}
]
}
]
}
});
In case anybody else is looking for an answer I was able to solve it. It was due to not loading the associated SVG through the url-loader. Another problem arose when adding svg back in because my inline SVGs I wanted to use as React components were running into errors as they were now going through the url-loader instead of my react-svg-loader.
Below is the working webpack.common.js and webpack.prod.js stayed the same. The solution was to differentiate my inline and external SVGs by turning all inline extensions from .svg to .inline.svg and adjusting webpack config accordingly
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const outputDirectory = 'dist';
module.exports = {
entry: './src/client/index.js',
output: {
path: path.join(__dirname, outputDirectory),
filename: 'bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Production',
template: './public/index.html',
favicon: './public/favicon.ico',
hash: true,
filename: 'index.html'
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
exclude: /\.inline.svg$/,
use: {
loader: 'url-loader?limit=1000&name=images/[name].[ext]'
}
},
{
test: /\.inline.svg$/,
use: [
"babel-loader",
{
loader: "react-svg-loader",
options: {
svgo: {
plugins: [
{
removeTitle: true,
removeComments: true
}
],
floatPrecision: 2
}
}
}
]
}
]
}
};
I'm trying to introduce Sass-loader to an existing project so as to be able to use Sass in my React components. I've set this up successfully before in my own boiler plates and had no issues but for some reason with the current configuration it doesn't seem to play. It doesn't give any errors but rather doesn't do anything with my .scss file i'm trying to import.
I can see that there is some loaders in the cssLoaders config for Webpack which could be the culprit but I am only targeting .scss/ .sass files with the rule
test: /\.s(a|c)ss$/
so I wouldn't have thought this would affect it at all.
I have webpack setup with a common file and one for development. Here are both those files:
webpack.common.js
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const ErrorOverlayPlugin = require('error-overlay-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
require('babel-polyfill');
const Dotenv = require('dotenv-webpack');
module.exports = {
entry: {
main: ['babel-polyfill', './src/index.js']
},
output: {
filename: '[name].[hash].js',
path: path.resolve('./dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: ['node_modules'],
use: [{ loader: 'babel-loader' }]
},
{
test: /\.s(a|c)ss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.(png|jpg|gif|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
outputPath: 'images/'
}
}
]
},
{
test: /\.(woff(2)?|ttf|eot|otf)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
]
}
]
},
plugins: [
new ErrorOverlayPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebPackPlugin({
template: 'index.html'
}),
new Dotenv(),
new CleanWebpackPlugin(['dist'])
]
};
And here is webpack.dev.js
const path = require('path');
const webpack = require('webpack');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const paths = require('../paths');
module.exports = require('./webpack.config.base')({
bail: false,
devtool: 'cheap-module-eval-source-map',
stats: 'errors-only',
performance: {
hints: false
},
entry: {
main: [
require.resolve('react-dev-utils/webpackHotDevClient'),
paths.appPolyfillsJs,
require.resolve('react-error-overlay'),
paths.appIndexJs
]
},
output: {
pathinfo: true,
filename: 'static/js/[name].js',
chunkFilename: 'static/js/[name].chunk.js',
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath)
},
// Load the CSS in a style tag in development
cssLoaders: [
{
loader: require.resolve('style-loader'),
options: {
sourceMap: true
}
},
{
loader: require.resolve('css-loader'),
options: {
modules: false,
sourceMap: true,
importLoaders: 1
}
},
{
loader: require.resolve('postcss-loader'),
options: { sourceMap: true }
}
],
babelQuery: {
cacheDirectory: true
},
plugins: [].concat([
new ProgressBarPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new CircularDependencyPlugin({
exclude: /a\.js|node_modules/,
failOnError: true
})
])
});
The part that I have added to the configuration is in webpack.common:
{
test: /\.s(a|c)ss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
}
]
},
I then just import it in the module like so:
import React, { PureComponent } from 'react';
import './test.scss';
...
Can anyone spot why the configuration is wrong?
The sass-loader requires node-sass and webpack as peerDependency.
Make sure node-sass is installed and edit the loader webpack.dev.js like so:
{
loader: "sass-loader",
options: {
includePaths: ["absolute/path/a", "absolute/path/b"]
}
}