I am calling webpack programmatically. At the time that I call it, I have a settings object that I would like to include as a module in webpack. Is this possible?
I'm looking for something similar to the DefinePlugin, but I would like to define a module, not free variables.
My app code,app.js, looks like this:
var settings = require('settings');
console.log('Build number is', settings.buildNumber);
My webpack runner, webpack-runner.js:
var settings = {
buildNumber: 100
};
// Can I pass settings into webpack config such that
// app.js will be able to access it with require('settings')?
var config = {
entry: "./app.js",
output: {
path: __dirname,
filename: "build.js"
}
};
webpack(config, function(err, stats) {
console.log(stats.toString());
});
Currently, the only way I have found to do this is to save my settings to a file, and then set an alias to the path of the file. But I would like to avoid saving a file only to have webpack open it a moment later.
Yes, just require in your settings file. Example below.
// settings.js
module.exports = {
buildNumber: 100
};
// webpack.config.js
var settings = require('./settings'); // settings.buildNumber => 100
var config = {
entry: './entry.js',
output: {
path: __dirname,
filename: 'build.js'
}
};
webpack(config, function( err, stats ) {
console.log(stats.toString({
colors: true,
modules: true,
chunkModules: true
}));
});
Related
I have 3 config JavaScript files like config.local.js, config.dev.js, config.prod.js. An example of one of these files.
// config.dev.js
function Config(){
return{
apiUrl: "https://myapi.dev.com/"
}
}
module.exports = Config;
Now I have an entry file that requires this config file. For instance:
// register.js
function Register(){
const config = require("../config");
// rest of the code to use that config
}
My web pack config looks like this.
module.exports = {
entry: {
register: "./app/src/register.js",
},
output: {
filename: "[name].js",
path: __dirname + "/app/dist",
},
};
I would like that when I run web pack for production (web pack --mode=production), it would bundle the config.prod.js file.
Is this possible?
See this page: https://webpack.js.org/guides/dependency-management/
require('../config.' + process.env.NODE_ENV)
I'm using webpack with watch=true to compile handlebars files into HTML files in a /dist folder.
The HandlebarsWebpackPlugin runs when .hbs files are modified, but I also want it to run when JSON files are modified. The JSON files contain data that is passed to the handlebars templates when they are compiled into HTML.
I added a plugin called webpack-watch-files-plugin thinking that it would watch the JSON files and re-run the whole build when a change is detected, but it doesn't.
Can somebody please explain how does webpack work in this regard? How can I make all the plugins re-run (or at least the handlebars to HTML compilation) when I change a JSON file?
webpack.config.js
const webpack = require('webpack');
const glob = require("glob");
const path = require("path");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HandlebarsPlugin = require("handlebars-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const ImageminPlugin = require("imagemin-webpack-plugin").default;
const WatchFilesPlugin = require('webpack-watch-files-plugin').default;
const mergeJSON = require("./src/utils/mergeJSON");
const handlebarsHelpers = require("handlebars-helpers");
const lang = process.env.npm_config_lang; // lang variable passed as argument to script
const webpackConfig = {
watch: true,
watchOptions: {
ignored: ['node_modules/**', 'dist']
},
entry: path.join(__dirname, 'src'),
plugins: [
new CleanWebpackPlugin(),
new HandlebarsPlugin({
// path to hbs entry file(s). Also supports nested directories if write path.join(process.cwd(), "app", "src", "**", "*.hbs"),
entry: path.join(__dirname, "src", "emails", "**/*.hbs"),
// output path and filename(s). This should lie within the webpacks output-folder
// if ommited, the input filepath stripped of its extension will be used
output: path.join(__dirname, "dist", "[path]", "[name].html"),
// you can also add a [path] variable, which will emit the files with their relative path, like
// output: path.join(process.cwd(), "build", [path], "[name].html"),
// data passed to main hbs template: `main-template(data)`
data: mergeJSON(path.join(__dirname, 'src/emails/**/*.json')),
// globbed path to partials, where folder/filename is unique
partials: [
path.join(__dirname, "src", "partials", "*.hbs")
],
// register custom helpers. May be either a function or a glob-pattern
helpers: {
projectHelpers: handlebarsHelpers()
},
// hooks
// getTargetFilepath: function (filepath, outputTemplate) {},
// getPartialId: function (filePath) {}
onBeforeSetup: function (Handlebars) {},
onBeforeAddPartials: function (Handlebars, partialsMap) {},
onBeforeCompile: function (Handlebars, templateContent) {},
onBeforeRender: function (Handlebars, data, filePath) {
const mergedData = mergeJSON(path.join(__dirname, 'src/emails/**/*.json'));
const filePathArray = filePath.split('/');
const fileName = filePathArray[filePathArray.length-1].split('.hbs')[0];
if(mergedData[fileName]) {
// only json specific to this file and language will be used as data for this file
return {...mergedData[fileName].config, ...mergedData[fileName][lang]};
} else if(!lang) {
const errorText = `The language code is required to build the emails. Pass it as an argument with this format "--lang=en-US".`;
console.log('\n', '\x1b[41m\x1b[37m', errorText, '\x1b[0m');
throw new Error(errorText);
}
},
onBeforeSave: function (Handlebars, resultHtml, filename) {},
onDone: function (Handlebars, filename) {}
}),
new CopyWebpackPlugin([{
from: path.join(__dirname, "src/emails/**/imgs/*"),
to: "[1]/[2].[ext]", // [1] and [2] are groups matched by the regex below
test: /emails\/([^/]+)\/(.+)\.(jpe?g|png|gif|svg|)$/,
}]),
new ImageminPlugin({test: /\.(jpe?g|png|gif|svg)$/i}),
new WatchFilesPlugin({
files: [
path.join(__dirname, "src", "emails", "**/data/*.json")
],
verbose: true
})
]
};
module.exports = webpackConfig;
I have a rather large React application built with webpack 2. The application is embedded into a Drupal site as a SPA within the existing site. The Drupal site has a complex gulp build setup and I can't replicate it with webpack, so I decided to keep it.
I have split my React application into multiple parts using the DllPlugin / DllReferencePlugin combo which is shipped out of the box in webpack 2. This works great, and I get a nice vendor-bundle when building with webpack.
The problem is when I try to run my webpack configuration in gulp, I get an error. I might be doing it wrong, as I have not been able to find much documentation on this approach, but nevertheless, it's not working for me.
It looks like it's trying to include the the manifest file from my vendor-bundle before creating it.
Whenever I run one of my defined gulp tasks, like gulp react-vendor I get an error, saying that it cannot resolve the vendor-manifest.json file.
If I on other hand run webpack --config=webpack.dll.js in my terminal, webpack compiles just fine and with no errors.
I have included what I think is the relevant files. Any help on this is appreciated.
webpack.config.js
// Use node.js built-in path module to avoid path issues across platforms.
const path = require('path');
const webpack = require('webpack');
// Set environment variable.
const production = process.env.NODE_ENV === "production";
const appSource = path.join(__dirname, 'react/src/');
const buildPath = path.join(__dirname, 'react/build/');
const ReactConfig = {
entry: [
'./react/src/index.jsx'
],
output: {
path: buildPath,
publicPath: buildPath,
filename: 'app.js'
},
module: {
rules: [
{
exclude: /(node_modules)/,
use: {
loader: "babel-loader?cacheDirectory=true",
options: {
presets: ["react", "es2015", "stage-0"]
},
},
},
],
},
resolve: {
modules: [
path.join(__dirname, 'node_modules'),
'./react/src/'
],
extensions: ['.js', '.jsx', '.es6'],
},
context: __dirname,
devServer: {
historyApiFallback: true,
contentBase: appSource
},
// TODO: Split plugins based on prod and dev builds.
plugins: [
new webpack.DllReferencePlugin({
context: path.join(__dirname, "react", "src"),
manifest: require(path.join(__dirname, "react", "vendors", "vendor-manifest.json"))
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
filename: 'webpack-loader.js'
}),
]
};
// Add environment specific configuration.
if (production) {
ReactConfig.plugins.push(
new webpack.optimize.UglifyJsPlugin()
);
}
module.exports = [ReactConfig];
webpack.dll.js
const path = require("path");
const webpack = require("webpack");
const production = process.env.NODE_ENV === "production";
const DllConfig = {
entry: {
vendor: [path.join(__dirname, "react", "vendors", "vendors.js")]
},
output: {
path: path.join(__dirname, "react", "vendors"),
filename: "dll.[name].js",
library: "[name]"
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, "react", "vendors", "[name]-manifest.json"),
name: "[name]",
context: path.resolve(__dirname, "react", "src")
}),
// Resolve warning message related to the 'fetch' node_module.
new webpack.IgnorePlugin(/\/iconv-loader$/),
],
resolve: {
modules: [
path.join(__dirname, 'node_modules'),
],
extensions: ['.js', '.jsx', '.es6'],
},
// Added to resolve a dependency issue in this build #https://github.com/hapijs/joi/issues/665
node: {
net: 'empty',
tls: 'empty',
dns: 'empty'
}
};
if (production) {
DllConfig.plugins.push(
new webpack.optimize.UglifyJsPlugin()
);
}
module.exports = [DllConfig];
vendors.js (to determine what to add to the Dll)
require("react");
require("react-bootstrap");
require("react-dom");
require("react-redux");
require("react-router-dom");
require("redux");
require("redux-form");
require("redux-promise");
require("redux-thunk");
require("classnames");
require("whatwg-fetch");
require("fetch");
require("prop-types");
require("url");
require("validator");
gulpfile.js
'use strict';
const gulp = require('gulp');
const webpack = require ('webpack');
const reactConfig = require('./webpack.config.js');
const vendorConfig = require('./webpack.dll.js');
// React webpack source build.
gulp.task('react-src', function (callback) {
webpack(reactConfig, function (err, stats) {
callback();
})
});
// React webpack vendor build.
gulp.task('react-vendor', function (callback) {
webpack(vendorConfig, function (err, stats) {
callback();
})
});
// Full webpack react build.
gulp.task('react-full', ['react-vendor', 'react-src']);
NOTE:
If I build my vendor-bundle with the terminal with webpack --config=webpack.dll.js first and it creates the vendor-manifest.json file, I can then subsequently successfully run my gulp tasks with no issues.
This is not very helpful though, as this still will not allow me to use webpack with gulp, as I intend to clean the build before new builds run.
I ended up using the solution mentioned in the end of my question. I build my DLL file first and then I can successfully run my gulp webpack tasks.
One change that can make it easier to debug the issue, is to use the Gulp utility module (gulp-util) to show any webpack errors that might show up during build of webpack, using gulp.
My final gulp setup ended up looking like this:
gulpfile.js
'use strict';
const gulp = require('gulp');
const gutil = require('gulp-util');
const webpack = require('webpack');
const reactConfig = require('./webpack.config.js');
const vendorConfig = require('./webpack.dll.js');
// React webpack source build.
gulp.task('react', function (callback) {
webpack(reactConfig, function (err, stats) {
if (err) {
throw new gutil.PluginError('webpack', err);
}
else {
gutil.log('[webpack]', stats.toString());
}
callback();
});
});
// React webpack vendor build.
gulp.task('react-vendor', function (callback) {
webpack(vendorConfig, function (err, stats) {
if (err) {
throw new gutil.PluginError('webpack', err);
}
else {
gutil.log('[webpack]', stats.toString());
}
callback();
});
});
// React: Rebuilds both source and vendor in the right order.
gulp.task('react-full', ['react-vendor'], function () {
gulp.start('react');
});
I hope this might help someone in a similar situation.
Whenever I run one of my defined gulp tasks, like gulp react-vendor I get an error, saying that it cannot resolve the vendor-manifest.json file.
Your gulpfile.js contains this:
const reactConfig = require('./webpack.config.js');
const vendorConfig = require('./webpack.dll.js');
And webpack.config.js contains this:
new webpack.DllReferencePlugin({
context: path.join(__dirname, "react", "src"),
manifest: require(path.join(__dirname, "react", "vendors", "vendor-manifest.json"))
}),
The require() calls are currently all executed immediately. Whenever you run Gulp, it will evaluate both Webpack configuration files. As currently configured, Node runs the code in webpack.config.js at startup, and from there it sees the require() used in your creation of the DllReferencePlugin, so it will also try to read manifest.json at that time and turn it into an object...which is before it has been built.
You can solve this in one of two ways:
The DllReferencePlugin's manifest option supports either an object (which is what you are currently providing), or else a string containing the path of the manifest file. In other words, it should work if you remove the require() from around your path.join(...) call.
Alternatively, you can also defer the loading of the Webpack config files. Moving your const reactConfig = require('./webpack.config.js'); from the top of the file directly into the gulp task function should be sufficient, assuming that this function is not invoked until after the manifest has been built.
I am modifying a purchased stencil-based theme for a client. When I modify javascript files, bundle.js does not update and I do not see a file change in the CLI. I am unable to see my changes on the local site. However, as a test, I was able to modify bundle.js directly and saw my change take place.
I have looked through the BC docs and have asked questions in other forums, but still no solution. I am not getting any errors in the CLI when I start stencil or run the bundle command. I can also upload my theme to the store without error.
Any ideas?
**Edit:
Here are the contents of my stencil.conf.js file:
var path = require('path');
var webpack = require('webpack');
var webpackConfig = require('./webpack.conf.js');
webpackConfig.context = __dirname;
webpackConfig.entry = path.resolve(__dirname, 'assets/js/app.js');
webpackConfig.output = {
path: path.resolve(__dirname, 'assets/js'),
filename: 'bundle.js'
};
/**
* Watch options for the core watcher
* #type {{files: string[], ignored: string[]}}
*/
var watchOptions = {
// If files in these directories change, reload the page.
files: [
'/assets',
'/templates',
'/lang'
],
//Do not watch files in these directories
ignored: [
'/assets/scss',
'/assets/css',
]
};
/**
* Hook into the stencil-cli browsersync instance for rapid development of themes.
* Watch any custom files and trigger a rebuild
* #param {Object} Bs
*/
function development(Bs) {
var compiler = webpack(webpackConfig);
// Rebuild the bundle once at bootup
compiler.watch({}, function(err, stats) {
if (err) {
console.error(err)
}
Bs.reload();
});
}
/**
*/
/**
* Hook into the `stencil bundle` command and build your files before they are packaged as a .zip
* Be sure to call the `done()` callback when finished
* #param {function} done
*/
function production(done) {
var compiler;
webpackConfig.devtool = false;
webpackConfig.plugins.push(new webpack.optimize.DedupePlugin());
webpackConfig.plugins.push(new webpack.optimize.UglifyJsPlugin({
comments: false
}));
compiler = webpack(webpackConfig);
compiler.run(function(err, stats) {
if (err) {
throw err;
}
done();
});
}
module.exports = {
watchOptions: watchOptions,
development: development,
production: production,
};
Here are the contents of my webpack.conf.js file:
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval-cheap-module-source-map',
bail: false,
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
include: [
path.resolve(__dirname, 'assets/js'),
path.resolve(__dirname, 'node_modules/#bigcommerce/stencil-utils'),
],
query: {
compact: false,
cacheDirectory: true,
presets: [ ['es2015', {loose: true}] ]
}
}
]
},
plugins: [],
watch: false
};
I'm using webpack-stream to integrate webpack into a gulp task, as below:
var gulp = require("gulp");
// var webpack = require('gulp-webpack');
var webpack = require('webpack-stream');
gulp.task("min:webpack",
function () {
return gulp.src('./App/App.js')
.pipe(webpack({
// watch: true,
module: {
entry: './App/App.js',
output: {
filename: 'App.bundle.js'
},
devtool: 'source-map'
}
}))
.pipe(gulp.dest('./App'));
});
Everything seems to be working as expected, except that the output file is always something like 6f7af85206d7f2f6536d.js instead of the expected App.bundle.js. In other similar questions (e.g., How to use gulp webpack-stream to generate a proper named file?), I've read that it was fixed effectively by specifying output: { filename: 'something'} in the configuration, but you can see that I'm doing that.
Any suggestions? Anything I'm overlooking?
OK, dumb mistake on my part. I had the configuration specified incorrectly. This config works as expected:
gulp.task("min:webpack",
function () {
return gulp.src('./App/App.js')
.pipe(webpack({
// watch: true,
entry: './App/App.js',
output: {
filename: 'App.bundle.js'
},
devtool: 'source-map'
}))
.pipe(gulp.dest('./App'));
});