Concatenate js files with webpack - javascript

webpack.config.js
const webpack = require('webpack')
const path = require('path')
const extractCommons = new webpack.optimize.CommonsChunkPlugin({
name: 'commons',
filename: './js/commons.js'
})
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const extractCSS = new ExtractTextPlugin('[name].bundle.css')
const publicJS = [
'./js/bootstrap.js',
'./js/fancybox/source/jquery.fancybox.pack.js',
'./js/flexslider/jquery.flexslider-min.js',
'./js/bxslider/jquery.bxslider.min.js',
'./js/jquery.validate/jquery.validate.min.js',
'./js/jquery.validate/additional-methods.min.js',
'./js/jquery.maskedinput.min.js',
'./js/jquery.formatDateTime.js',
'./js/gpw-public.js'
];
const config = {
devtool: 'eval-source-map',
context: path.resolve(__dirname, ''),
devServer: {
proxy: {
'**': {
target: 'http://www.gdwv2.com',
secure: false,
changeOrigin: true
}
}
},
entry: {
'./js/theme-selector/gpw-theme-selector.min': './js/theme-selector/gpw-theme-selector.js',
'./pub/public.bundle': publicJS,
},
output: {
path: path.resolve(__dirname, ''),
filename: '[name].js'
},
module: {
rules: [{
test: /\.(png|jpg)$/,
include: path.resolve(__dirname, 'style'),
use: [{
loader: 'url-loader',
options: { limit: 10000 } // Convert images < 10k to base64 strings
}]
},
{
//
test: /\.scss$/,
include: path.resolve(__dirname, 'style'),
loader: extractCSS.extract(['css-loader','sass-loader'])
},
{
// Theme selector
test: /\.js$/,
include: path.resolve(__dirname, 'js/theme-selector'),
use: [{
loader: 'babel-loader',
options: { presets: ['es2015', 'react'] }
}]
},
{
test: /\.js$/,
include: path.resolve(__dirname, 'js'),
use: [{
loader: 'babel-loader',
options: { presets: ['es2015', 'react'] }
}]
}
]
},
plugins: [
new webpack.NamedModulesPlugin(),
extractCommons,
extractCSS
]
}
module.exports = config
The publicJS array is a bunch of vender files. This sort of works. Although files are not concatenated in the order they are in the array, which generates some undefined errors. Also getting undefined variable errors in the public.bundle.js file from variables that are defined in scritps that are defined in scripts loaded before this. To be clear:
defined in myscript.js -> var foo = "bar";
public.bundle.js is loaded after myscript.js and tries to use foo but invokes a undefined variable error. Perhaps I don't understand the webpackJsonp(... function webpack scripts are wrapped in.
The second entry is a React app. That is working as desired.

Related

Issue with integrating cortex-js/compute machine in react application

I am trying to use compute machine provided by the cortexjs. https://cortexjs.io/compute-engine
I saved this dependency using
npm i #cortex-js/compute-engine
After I ran npm start, I am getting this error:
ERROR in ./node_modules/#cortex-js/compute-engine/dist/compute-engine.min.js 2:1360
Module parse failed: Unexpected token (2:1360)
You may need an appropriate loader to handle this file type.
Following is my webpack file:
var webpack = require('webpack');
const HtmlWebPackPlugin = require("html-webpack-plugin");
var path = require('path');
module.exports = {
// output: {
// path: path.resolve(__dirname, 'dist'),
// filename: 'main.js',
// publicPath: '/'
// },
mode : 'production',
devServer: {
historyApiFallback: true,
},
devtool: "source-map",
module: {
rules: [
{
test: /\.(png|jpg|woff|woff2|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader"
}
]
},
{
test: /\.css$/,
loader: 'style-loader'
},
{
test: /\.css$/,
loader: 'css-loader',
options: {
import: true,
},
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
})
]
};
Please can someone suggest which loader should I add to webpack.config file to make this work.

How do I access process.env.VAR in Webpack 5?

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?

Webpack can't resolve type from io-ts

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

AngularJS + webpack how to hash template htmls

I have migrated our AngularJS application to use webpack - before it used gulp. in the gulp version I have used rev plugin to rev all the files (css,js and html) however in the webpack mode , I cannot find a way to add hash to the html templates - which cause issues as the browser serve old html files. How can it be fixed? below is by webpack conf file
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const OpenBrowserPlugin = require('open-browser-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const RemoteServer = process.env.REMOTE_SERVER;
const appEnv = process.env.NODE_ENV || 'development';
const isProduction = appEnv === 'production';
const patterns = require('../server/src/main/resources/regex.json');
const appPath = path.join(__dirname, 'app');
const buildPath = path.join(__dirname, 'artifacts');
const config = {
entry: [path.join(appPath, 'index.js')],
output: {
path: buildPath,
filename: '[name].[hash].js',
chunkFilename: '[name].[hash].js'
},
resolve: {
modules: ['node_modules', appPath],
alias: {
'ui-select-css': path.resolve('./node_modules/ui-select/dist/select.css'),
fonts: path.resolve(__dirname, 'assets/fonts')
}
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
emitWarning: true,
quiet: true
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'resolve-url-loader'
]
},
{
test: /\.less$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader', options: {
url: false,
sourceMap: true
}
}, {
loader: 'less-loader', options: {
relativeUrls: false,
sourceMap: true
}
}]
},
{
test: /\.(jpe?g|png|gif)(\?.*)?$/i,
use: [{
loader: 'file-loader',
options: {name: '[path][name].[hash].[ext]'}
}]
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'url-loader',
options: {limit: 10000, mimetype: 'application/octet-stream'}
}
]
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader'
}
]
},
{
test: /\.svg$/i,
loader: 'raw-loader'
},
{
test: require.resolve('angular'),
use: [
{loader: 'expose-loader', options: 'angular'},
]
},
{
test: require.resolve('jquery'),
use: [
{loader: 'expose-loader', options: '$'},
{loader: 'expose-loader', options: 'jQuery'},
]
},
{
test: require.resolve('lodash'),
use: [
{loader: 'expose-loader', options: '_'},
]
},
{
test: require.resolve('moment'),
use: [
{loader: 'expose-loader', options: 'moment'},
]
},
{
test: /\.html$/,
use: [{
loader: 'raw-loader',
options: {name: '[path][name].[hash].[ext]'}
}]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(appPath, 'index.html')
}),
new webpack.DefinePlugin({
INJECT_REGEX_HERE: JSON.stringify(patterns)
}),
new CopyWebpackPlugin([
{from: 'app/images', to: 'assets/images'},
{from: 'app/fonts', to: 'assets/fonts'},
{from: 'app/templates', to: 'assets/templates'},
{from: 'app/silent-callback.html', to: 'silent-callback.html'},
{from: 'node_modules/font-awesome/css', to: 'assets/font-awesome/css'},
{from: 'node_modules/font-awesome/fonts', to: 'assets/font-awesome/fonts'},
{from: 'node_modules/angular-ui-grid/fonts', to: 'assets/fonts'},
{from: 'node_modules/d3/d3.min.js', to: 'assets/d3'}
]),
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].[hash].css'
}),
new OpenBrowserPlugin({url: 'http://localhost:1337'})
],
devtool: isProduction ? 'source-map' : 'inline-source-map',
devServer: {
port: 1337
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
};
if (RemoteServer) {
console.log('running with remote server', RemoteServer);
config.devServer.proxy = {
'/occm/*': 'http://' + RemoteServer
};
}
if (isProduction) {
config.plugins.push(
new CleanWebpackPlugin(buildPath)
);
}
module.exports = config;
One of the main benefits of using Webpack is reducing the number of requests a browser has to perform for rendering your application and making your app start faster.
To achieve this, it groups related resources together in "chunks", that get loaded together in one request. Separate loading of required single files like HTML-templates (without a specific reason) could be considered an anti-pattern here.
Best practice is grouping all related JS, HTML and CSS code together in one big bundle that gets loaded once, sometimes (for bigger apps) having a second 'vendor' bundle for the code from node_modules, speeding up development, because this chunk won't change as often.
Alternative solution:
So in your case, if there is no specific reason for keeping things separate (which you didn't write about), I would rather recommend serving HTML together with the controlling code in one chunk instead of loading the HTML files separately.
A good and simple starting point would be to build just two chunks. Replace your whole optimization block by the following code:
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all'
}
}
}
},
That will build two chunks: One main chunk for all of your JS and HTML files and another one, explicitly for everything from the node_modules folder.
That way you won't have to worry about browser caches for HTML files anymore, because they are built in your main chunk, and, as a benefit, your app will start faster.
I did a similar migration a couple of year and I didn't need that type of solution. My goal was encapsulate each component as a module and then lazy load as much as possible.
// webpack config
{
test: /\.html$/,
use: ['html-loader'],
},
Then in each component I just require styles and template like:
require('./_proposal-page.scss');
(function() {
'use strict';
angular.module('component.myComponent', []).component('myComponent', {
template: require('./proposal-page.html'),
controller: MyController,
});
/** #ngInject */
function MyController($log) {
const $ctrl = this;
$ctrl.$onInit = function() {
$log.log('$onInit myComponent');
}
}
})();
if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports === exports) {
module.exports = 'component.myComponent';
}
Webpack detect the requires and export each .html file as a module, it works smoothly.

file-loader save images per folder e.g. Project/Module/src/img/example.jpg to Project/Module/dist/img/example.jpg

Hi I'm trying to create a Webpack configuration that generates files for each folder within this project. Making a webpack.config for each folder is not an option.
I have an index.html, JS and SASS all processed. The next step is the images, which I'm struggling with.
What currently happens is:
cd /MyProject/ && npm run build
Inside of this folder, there are 'modules', each module is a folder.
src:
/MyProject/MyModule/src/js/app.js
/MyProject/MyModule/src/scss/app.scss
/MyProject/MyModule/src/index.html
/MyProject/MyModule/src/img/example1.jpg
dist:
MyProject/MyModule/dist/(app.css|app.js|index.html|img/example1.jpg)
My Problem
When saving the images, in this current way below,
name: '[path]../../dist/img/[name].[ext]'
My HTML output is this:
<img src="/MyModule/src/img/../dist/img/screenshot.png" alt="Screenshot">
I do understand why this is happening, but I don't know of any better way.
If I remove [path] it of course saves inside of MyProject instead of MyModule, which is what I don't want.
webpack.config.js
const entryPlus = require('webpack-entry-plus');
const glob = require('glob');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const fs = require('fs');
const htmlList_exclusions = [
'node_modules'
]
const htmlList = []
const imgList = []
const files = fs.readdirSync(__dirname)
files.forEach(file => {
var filePath = path.join(__dirname, file);
var isDir = fs.statSync(filePath).isDirectory();
if(isDir && !file.startsWith('.') && !file.startsWith('_') && !htmlList_exclusions.includes(file)) {
htmlList.push(filePath + '/src/index.html')
}
});
const entryFiles = [
{
entryFiles: glob.sync('./*/src/js/app.js'),
outputName(item) {
return item.replace('src/js/', 'dist/').replace('.js', '').replace('./', '');
},
},
];
const plugins = [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
// path: '[folder]tes',
filename: '[name].css',
})
]
for(var i in htmlList) {
plugins.push( new HtmlWebpackPlugin({
template: htmlList[i],
filename: htmlList[i].replace('src/', '/'),
}));
}
module.exports = {
watch: true,
entry: entryPlus(entryFiles),
output: {
path: path.resolve(__dirname, './'),
filename: '[name].js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// you can specify a publicPath here
// by default it use publicPath in webpackOptions.output
// publicPath: '../',
sourceMap: false,
}
},
"css-loader", "sass-loader"
]
},
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
plugins: ['#babel/plugin-proposal-object-rest-spread', '#babel/plugin-transform-runtime']
}
}
},
{
test: /\.html$/,
use: ['html-loader'],
},
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path]../dist/img/[name].[ext]',
outputPath: '',
publicPath: '/',
}
}
]
}
]
},
plugins,
resolve: {
alias: {
globalscss: path.resolve(__dirname, './_global/scss/'),
}
}
}
I will work for a better RegExp, but I used the following solution
{
test: /\.(jpg|png|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
regExp: /([^\0]+)\/([^\0]+)\/([^\0]+)\/([^\0]+)\/([^\0]+)\.(jpg|png|gif|svg)$/,
name: '[2]/dist/img/[name].[ext]',
outputPath: '',
publicPath: '/',
}
}
]
}

Categories