Grunt-webpack wildcard on 'entry' - javascript

I'm using Grunt to compile page level JS assets.
webpack: {
build: {
entry: {
// Add your page JS here!
home: "./assets/scripts/tmp/Pages/home.js",
events: "./assets/scripts/tmp/Pages/events.js"
},
output: {
path: "./public/scripts"
}
}
}
This is how I'm currently doing it, but I'd like to do something like:
webpack: {
build: {
entry: "./assets/scripts/tmp/Pages/*",
output: {
path: "./public/scripts"
}
}
}
However this fails with an "ERROR in Entry module not found:" error.
I've tried SRC and DEST options instead but they didn't seem to even compile the files :S
Thanks in advance

The entry option doesn't support wildcards, but grunt does. You can use grunts wildcard support to construct an object for the entry option:
var pagesBase = path.resolve("assets/scripts/tmp/Pages");
build: {
entry: grunt.file.expand({ cwd: pagesBase }, "*").reduce(function(map, page) {
map[path.basename(page)] = path.join(pagesBase, page);
return map;
}, {}),
output: {
path: "./public/scripts",
filename: "[name].js" // You also need this to name the output file
}
}
grunt.file.expand just returns an array of all matching files in the pages directory. Array.prototype.reduce is used to convert the array into an object.
Note: To make your example complete you also need to include [name] in the output.filename option.

To anyone else looking for a simple fact... this is what I used:
webpack: {
build: {
entry: {
"home-page": "./" + path + "scripts/tmp/Pages/home-page.js",
"event-page": "./" + path + "scripts/tmp/Pages/event-page.js",
"performer-page": "./" + path + "scripts/tmp/Pages/performer-page.js",
"order-page": "./" + path + "scripts/tmp/Pages/order-page.js",
"support-page": "./" + path + "scripts/tmp/Pages/support-page.js"
},
output: {
path: "public/scripts",
filename: "[name].js"
}
}
}

Similar to Tobias K. answer but with a working example :
var config = {
...
webpackFiles: {}
};
//Dynamically create list of files in a folder to bundle for webpack
grunt.file.expand({ cwd: 'my/folder/' }, "*").forEach(function(item){
config.webpackFiles[item.substr(0,item.indexOf('.js'))] = './my/folder/' + item;
});
And then in your grunt task use it like this:
webpack: {
build: {
entry: config.webpackFiles,
output: {
path: "<%= config.jsDest %>/",
filename: "[name].js"
},
module: {
...
}
}
},
The only downside is that if you want to add specific file to this build (for example bundle app.js) , you will have to add this to the webpackFiles variable like so
//Dynamically create list of view to bundle for webpack
config.webpackFiles.App = './' + config.jsSrc + '/App.js';
grunt.file.expand({ cwd: 'Static/js/src/views/' }, "*").forEach(function(item){
config.webpackFiles[item.substr(0,item.indexOf('.js'))] = './Static/js/src/views/' + item;
});

Related

Webpack different names for entries

How i can specify different filename for different entry output?
For example:
module.exports = {
context: path.resolve(__dirname, 'assets'),
entry: {
vendor: ['react', 'react-dom', 'lodash', 'redux'],
app: './src/app.js'
}
output: {
path: path.resolve(__dirname, (isDevelopment) ? 'demo' : 'build'),
filename: (isDevelopment) ? '[name].js' : '[name][chunkhash:12].js'
}
}
To receive output like this
build
-- index.html
-- app.2394035ufas0ue34.js
-- vendor.js
So browser will cache vendor.js with all libraries. Since i don't plan to migrate to any major new release anytime soon and often.
And still being able to break cache for app.js with every update required.
is there some kind of option to set output as
output: {
app: {
...
},
vendor: {
...
},
}
Here is working code:
entry: {
'./build/app': './src/app.js',
'./build/vendor': VENDOR_LIBS // or path to your vendor.js
},
output: {
path: __dirname,
filename: '[name].[chunkhash].js'
},
Add this code into your webpack plugins array as last element of an array.
plugins: [
... // place our new plugin here
]
function() {
this.plugin("done", function(stats) {
const buildDir = __dirname + '/build/';
const fs = require('fs');
var vendorTempFileName = '';
new Promise(function(resolve, reject) {
fs.readdir(buildDir, (err, files) => {
files.forEach(file => {
if (file.substr(0,6) === 'vendor') {
resolve(file);
}
});
});
}).then(function(file) {
fs.rename( buildDir + file, buildDir + 'vendor.js', function(err) {
if ( err ) console.log('ERROR: ' + err);
});
});
});
}
Output should be as follows:
It is considered bad practice to leave your files without chunkhashes, due to browser caching.
For Webpack 4 I added a quick-and-dirty done hook to rename my service worker script:
// Plugin to rename sw-[chunkhash].js back to sw.js
class SwNamePlugin {
apply(compiler) {
compiler.hooks.done.tap("SW Name Plugin", (stats) => {
const swChunk = stats.compilation.chunks.find((c) => c.name === "sw");
fs.rename(path.resolve(outDir, swChunk.files[0]), `${outDir}/sw.js`);
});
}
}
plugins.push(new SwNamePlugin());
This obviates the warning DeprecationWarning: Tapable.plugin is deprecated. Use new API on .hooks instead you'd see following loelsonk's answer.

Can not bundle two files with webpack

I have the following webpack configuration file, where I'm trying to make two bundle files for two separate projects:
var webpack = require('webpack');
var path = require('path');
var INDEX_BUILD_DIR = path.resolve(__dirname, 'src/client/app/public');
var INDEX_APP_DIR = path.resolve(__dirname, 'src/client/app/');
var RESULTS_BUILD_DIR = path.resolve(__dirname, 'src/client/results/public');
var RESULTS_APP_DIR = path.resolve(__dirname, 'src/client/results/');
var config = {
entry: {
INDEX_BUILD_DIR: INDEX_APP_DIR,
RESULTS_BUILD_DIR: RESULTS_APP_DIR
},
output: {
path: './',
filename: '[name].js'
},
module : {
loaders : [
{
test : /\.jsx?/,
include : [INDEX_APP_DIR, RESULTS_APP_DIR],
loader : 'babel'
}
]
}
};
module.exports = config;
I made this structure after looking here:
https://github.com/webpack/webpack/issues/1189
However, I am getting this issue:
ERROR in Entry module not found: Error: Cannot resolve 'file' or 'directory' path/to/project/src/client/app in /path/to/project
I can't understand where the issue originates from.
Also, only one file is created named "RESULTS_BUILD_DIR.js" which means that a variable is interpreted literally.
What causes these problems?
There are 2 things:
Error in entry: you're pointing a path to module, so you have to have an index.js file in path/to/project/src/client/app as well as in src/client/results/
RESULTS_BUILD_DIR.js yes, this notation filename: '[name].js' says "put the name of the entry and add dot and js - and this would be a result filename"

Output filename for gulp/webpack task

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'));
});

How to use Webpack with Angular + templateCache?

I'm learning Webpack. I made an App with Angular and I use templateCache to generate all my html views in one js file than require in App. It works cool. But then the Webpack job:
entry: {
app: ["bootstrap-webpack!./bootstrap.config.js", './app/app.js'],
vendor: ['angular', 'bootstrap', 'angular-ui-router', 'oclazyload']
},
output: {
path: path.join(__dirname, "dist"),
filename: '/bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(
/* chunkName= */ "vendor", /* filename= */ "/vendor.bundle.js"),
That was the part of my webpack config. As the result I get directory "dist" with "bundle.js" && "vendor.bundle.js" and index.html. After that I start server and my App says that it can't GET views. Why? :( As I understand all my views have to be bundled and should be available in the "dist" directory.
I do not use the templateCache at all. Since Angular directives also accept a template as string, I just require() the template with the html-loader.
function MyDirective() {
return {
restrict: "E",
replace: true,
template: require("./MyDirective.html")
};
}
// in your webpack.config.js
module.exports = {
module: {
loaders: [
{ test: /\.html$/, loaders: ["html"] }
]
}
}
Its late but might as well share this. If you really want to use html fragments maybe for
<div ng-include="'file.tplc.html'"></div>
here is how I made it work
var appMod = angular.module('app');
appMod.run(function($templateCache) {
function requireAll(requireContext) {
return requireContext.keys().map(function(val){
return {
// tpl will hold the value of your html string because thanks to wepbpack "raw-loader" **important**
tpl:requireContext(val),
//name is just the filename
name : val.split('/').pop()
}
});
}
// here "../" is my app folder root
// tplc is the naming convention of the templates
let modules = requireAll(require.context("../", true, /\.tplc\.html$/));
modules.map(function (val) {
$templateCache.put(val.name, val.tpl);
})
});

In webpack, how can I have different output directories for multiple entry points?

I have the following webpack configuration with multiple entry points...
module.exports = {
entry: {
somePage: "./scripts/someDir/somePage.js",
anotherPage: "./scripts/someDir/someSubDir/anotherPage.js"
},
output: {
path: path.resolve(__dirname, 'out'),
filename: '[name].js'
},
...
Is it possible to set a different output path for each entry?
Instead of getting an output of...
/out/somePage.js
/out/anotherPage.js
I want...
/out/someDir/somePage.js
/out/someDir/someSubDir/anotherPage.js
The ideal solution for me would be for output.path to accept a function. For example...
...
output: {
path: function (name, hash) {
return path.resolve(__dirname, myMapOfFilenamesToDirs[name]);
},
filename: '[name].js'
},
Does anyone know if this is possible or if there is an existing plugin that can accomplish this?
EDIT I don't want to use multiple config entries (multi-compiler) because I won't be able to create a shared file among the entry points with CommonsChunkPlugin anymore
A bit hacky, but this should do the trick.
module.exports = {
entry: {
"somePage": "./scripts/someDir/somePage.js",
"someSubDir/anotherPage": "./scripts/someDir/someSubDir/anotherPage.js"
},
output: {
path: path.resolve(__dirname, 'out/someDir'),
filename: '[name].js'
},
// Etc.
}
You cannot set the path to a function, webpack won't call it for you.
You can return an array of configurations for webpack to execute. I think that will give you enough control over the output path to achieve what you need.
I had the same issue today, adding on to the answer from #quentin-roy, https://stackoverflow.com/a/33086806/6552940
You can also create the output path mappings for input files using glob and the following callback. Adjust your glob pattern according to your needs. The following pattern and callback if applied on the directory structure
- src
- file01.ts
lib
- file02.ts
will result in
- dist
- file01.js
lib
- file02.js
config = {
entry: () => {
const entries = {};
glob.sync("./src/**/*.ts").forEach(filePath => {
entries[
path
.relative("./src", filePath)
.replace(path.extname(filePath), "")
] = filePath;
});
console.debug(
`Entries created:\n${JSON.stringify(entries, undefined, 4)}`,
);
return entries;
},
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
},
}
After some evaluations I'm using the Webpack-watched-glob-entries-plugin for some time, because it is small, does what we need and works also in watch mode.
If you need even more ideas take a look here Wildcards in entry points.

Categories

Resources