how to control how wiredep generates bower file path and how to control which files is added/removed - grunt-wiredep

my app has directory as follows
app -> appName -> index.html (js,css)
and for some reason, this appName wrapper folder is messing up wiredire
{ dest: '.tmp/concat/scripts/vendor.js',
src:
[ '../bower_components/es5-shim/es5-shim.js',
'../bower_components/angular/angular.js',
'../bower_components/json3/lib/json3.js',
'../bower_components/angular-resource/angular-resource.js',
'../bower_components/angular-cookies/angular-cookies.js',
'../bower_components/angular-sanitize/angular-sanitize.js',
'../bower_components/angular-animate/angular-animate.js',
'../bower_components/angular-touch/angular-touch.js',
'../bower_components/angular-route/angular-route.js' ] },
this is what would've been produced if directory is as follows
app -> index.html(js,css)
{ dest: '.tmp/concat/scripts/vendor.js',
src:
[ 'bower_components/es5-shim/es5-shim.js',
'bower_components/angular/angular.js',
'bower_components/json3/lib/json3.js',
'bower_components/angular-resource/angular-resource.js',
'bower_components/angular-cookies/angular-cookies.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-touch/angular-touch.js',
'bower_components/angular-route/angular-route.js' ] },
and wiredep does change the index.html's script content and how can I control that flow? sometimes its stripping out angular-sanitize from its script[src]

You Should use the replace option of wiredep:
wiredep(
{
fileTypes: {
html: {
replace: {
js: '<script src="/app/appName/{{filePath}}"></script>'
}
}
}
})
Will generate:
<script src="/app/appName/bower_components/angular/angular.js"></script>

This is my gulp setup (same principle apply to Grunt, just pass the same options to it).
gulp.task('wiredep' , function()
{
return gulp.src('./app/index.html')
.pipe(wiredep({
'ignorePath': '../'
}))
.pipe(gulp.dest('./app'));
});
You can look at the wiredep source code in the lib/inject-dependencies.js (line:80~85)
map(function (filePath) {
return $.path.join(
$.path.relative($.path.dirname(file), $.path.dirname(filePath)),
$.path.basename(filePath)
).replace(/\\/g, '/').replace(ignorePath, '');
}).
It just replace the bit you supply (or not if you don't give it one).
Hope that helps.

Have you tried adding cwd to the options block?
Ex:
// Automatically inject Bower components into the app
wiredep: {
options: {
cwd: 'app/appName'
}
....
}

Related

Rollup.js code splitting - Prevent extra bundle to be created

I'm trying to generate two bundles (only two) using Rollup.js:
commonBundle.js
bundle2.js
bundle2.js depends on commonBundle.js.
The current result of rollup -c is actually 3 files instead of the 2 I want:
commonBundle.js
bundle2.js
commonDep-6c053814.js
Yes, commonDep.ts is indeed used by both commonBundle.ts and bundle2.ts. But since bundle2.ts depends on commonBundle.ts I was expecting the common dependency (commonDep.ts) to be included in the resulting commonBundle.js, not to be a separate bundle!
Is there a way to make all shared dependencies to be bundled inside a single bundle that needs to be imported by the others?
rollup.config.mjs :
export default {
input: {
commonBundle: "./src/commonBundle.ts",
bundle2: "./src/bundle2.ts"
},
output: {
dir: "./public",
format: "es"
},
plugins: [resolve({ browser: true }), commonjs(), typescript()]
};
commonBundle.ts :
import { sayHello } from "./commonDep";
export * from "./commonDep"; // export all common dependencies!
export function commonBundleFunction() {
sayHello("from common bundle");
}
bundle2.ts :
import "./commonBundle"; // depends on the common bundle!!!
import { sayHello } from "./commonDep";
export function bundle2Function() {
sayHello("from bundle2");
}
commonDep.ts :
export function sayHello(name: string) {
console.log("Hello " + name);
}

Copy all files but change the name of some automatically in yeoman

I am trying to create a yeoman generator where I have to copy from templatePath to destinationPath some files and folders, but I would want to have some of this files with a variable that yeoman could change by one of the user's inputs.
like: "<%=name%>-plugin.php" -> "hello-plugin.php"
I saw some references that this can be done but I can't find how.
I am doing right now:
//Copy the configuration files
app: function () {
this.fs.copyTpl(
this.templatePath('**'),
this.destinationPath(),
{
name: this.props.pluginName,
name_function: this.props.pluginName.replace('-', '_'),
name_class: this.props.className,
description: this.props.pluginDescription
}
);
}
I thought that with that code my <%=name%> would magically changed on copyTpl but it doesn't work
I've just found the solution:
Use this.registerTransformStream(); to pipe all files through some node.js script.
var rename = require("gulp-rename");
//other dependecies...
module.exports = yeoman.Base.extend({
//some other things generator do...
writing: function() {
var THAT = this;
this.registerTransformStream(rename(function(path) {
path.basename = path.basename.replace(/(666replacethat666)/g, THAT.props.appName);
path.dirname = path.dirname.replace(/(666replacethat666)/g, THAT.props.appName);
}));
this.fs.copyTpl(
this.templatePath(),
this.destinationPath(), {
appName: this.props.appName
});
}
});
I'm using here gulp-rename to change file names to something else.
Assuming that this.props.appName == "myFirstApp", this:
666replacethat666-controller.html
will change its name to
myFirstApp-controller.html
Following #piotrek answer, I made a function to replace all props with some pattern (like ejs does) -> $$[your prop name]$$. warning: ES6 inside
var rename = require("gulp-rename");
//other dependecies...
module.exports = yeoman.Base.extend({
//some other things generator do...
writing: function() {
this.registerTransformStream(rename((path) => {
for (let prop in this.props) {
let regexp = new RegExp('\\$\\$' + prop + '\\$\\$', 'g')
path.basename = path.basename.replace(regexp, this.props[prop]);
path.dirname = path.dirname.replace(regexp, this.props[prop]);
}
}));
this.fs.copyTpl(
this.templatePath(),
this.destinationPath(), {
appName: this.props.appName
});
}
});
Example:
Let's assume you have this.props.appname = MyApp and this.props.AnotherProps = Test and you want to rename file or folder.
Name your file or folder MyFile$$appname$$.js -> MyFileMyApp.js
Name your file or folder $$appname$$.js -> MyApp.js
Name your file or folder $$AnotherProps$$.js -> Test.js
This is not possible anymore. The feature was bloated and was removed at some point in 2015.
For now, just rename the file:
this.fs.copy('name.js', 'new-name.js')

How to create multiple output paths in Webpack config

Does anyone know how to create multiple output paths in a webpack.config.js file? I'm using bootstrap-sass which comes with a few different font files, etc. For webpack to process these i've included file-loader which is working correctly, however the files it outputs are being saved to the output path i specified for the rest of my files:
output: {
path: __dirname + "/js",
filename: "scripts.min.js"
}
I'd like to achieve something where I can maybe look at the extension types for whatever webpack is outputting and for things ending in .woff .eot, etc, have them diverted to a different output path. Is this possible?
I did a little googling and came across this *issue on github where a couple of solutions are offered, edit:
but it looks as if you need to know the entry point in able to specify an output using the hash method
eg:
var entryPointsPathPrefix = './src/javascripts/pages';
var WebpackConfig = {
entry : {
a: entryPointsPathPrefix + '/a.jsx',
b: entryPointsPathPrefix + '/b.jsx',
c: entryPointsPathPrefix + '/c.jsx',
d: entryPointsPathPrefix + '/d.jsx'
},
// send to distribution
output: {
path: './dist/js',
filename: '[name].js'
}
}
*https://github.com/webpack/webpack/issues/1189
however in my case, as far as the font files are concerned, the input process is kind of abstracted away and all i know is the output. in the case of my other files undergoing transformations, there's a known point where i'm requiring them in to be then handled by my loaders. if there was a way of finding out where this step was happening, i could then use the hash method to customize output paths, but i don't know where these files are being required in.
Webpack does support multiple output paths.
Set the output paths as the entry key. And use the name as output template.
webpack config:
entry: {
'module/a/index': 'module/a/index.js',
'module/b/index': 'module/b/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
generated:
└── module
├── a
│   └── index.js
└── b
└── index.js
I'm not sure if we have the same problem since webpack only support one output per configuration as of Jun 2016. I guess you already seen the issue on Github.
But I separate the output path by using the multi-compiler. (i.e. separating the configuration object of webpack.config.js).
var config = {
// TODO: Add common Configuration
module: {},
};
var fooConfig = Object.assign({}, config, {
name: "a",
entry: "./a/app",
output: {
path: "./a",
filename: "bundle.js"
},
});
var barConfig = Object.assign({}, config,{
name: "b",
entry: "./b/app",
output: {
path: "./b",
filename: "bundle.js"
},
});
// Return Array of Configurations
module.exports = [
fooConfig, barConfig,
];
If you have common configuration among them, you could use the extend library or Object.assign in ES6 or {...} spread operator in ES7.
You can now (as of Webpack v5.0.0) specify a unique output path for each entry using the new "descriptor" syntax (https://webpack.js.org/configuration/entry-context/#entry-descriptor) –
module.exports = {
entry: {
home: { import: './home.js', filename: 'unique/path/1/[name][ext]' },
about: { import: './about.js', filename: 'unique/path/2/[name][ext]' }
}
};
If you can live with multiple output paths having the same level of depth and folder structure there is a way to do this in webpack 2 (have yet to test with webpack 1.x)
Basically you don't follow the doc rules and you provide a path for the filename.
module.exports = {
entry: {
foo: 'foo.js',
bar: 'bar.js'
},
output: {
path: path.join(__dirname, 'components'),
filename: '[name]/dist/[name].bundle.js', // Hacky way to force webpack to have multiple output folders vs multiple files per one path
}
};
That will take this folder structure
/-
foo.js
bar.js
And turn it into
/-
foo.js
bar.js
components/foo/dist/foo.js
components/bar/dist/bar.js
Please don't use any workaround because it will impact build performance.
Webpack File Manager Plugin
Easy to install copy this tag on top of the webpack.config.js
const FileManagerPlugin = require('filemanager-webpack-plugin');
Install
npm install filemanager-webpack-plugin --save-dev
Add the plugin
module.exports = {
plugins: [
new FileManagerPlugin({
onEnd: {
copy: [
{source: 'www', destination: './vinod test 1/'},
{source: 'www', destination: './vinod testing 2/'},
{source: 'www', destination: './vinod testing 3/'},
],
},
}),
],
};
Screenshot
If it's not obvious after all the answers you can also output to a completely different directories (for example a directory outside your standard dist folder). You can do that by using your root as a path (because you only have one path) and by moving the full "directory part" of your path to the entry option (because you can have multiple entries):
entry: {
'dist/main': './src/index.js',
'docs/main': './src/index.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, './'),
}
This config results in the ./dist/main.js and ./docs/main.js being created.
In my case I had this scenario
const config = {
entry: {
moduleA: './modules/moduleA/index.js',
moduleB: './modules/moduleB/index.js',
moduleC: './modules/moduleB/v1/index.js',
moduleC: './modules/moduleB/v2/index.js',
},
}
And I solve it like this (webpack4)
const config = {
entry: {
moduleA: './modules/moduleA/index.js',
moduleB: './modules/moduleB/index.js',
'moduleC/v1/moduleC': './modules/moduleB/v1/index.js',
'moduleC/v2/MoculeC': './modules/moduleB/v2/index.js',
},
}
You definitely can return array of configurations from your webpack.config file. But it's not an optimal solution if you just want a copy of artifacts to be in the folder of your project's documentation, since it makes webpack build your code twice doubling the overall time to build.
In this case I'd recommend to use the FileManagerWebpackPlugin plugin instead:
const FileManagerPlugin = require('filemanager-webpack-plugin');
// ...
plugins: [
// ...
new FileManagerPlugin({
onEnd: {
copy: [{
source: './dist/*.*',
destination: './public/',
}],
},
}),
],
You can only have one output path.
from the docs https://github.com/webpack/docs/wiki/configuration#output
Options affecting the output of the compilation. output options tell Webpack how to write the compiled files to disk. Note, that while there can be multiple entry points, only one output configuration is specified.
If you use any hashing ([hash] or [chunkhash]) make sure to have a consistent ordering of modules. Use the OccurenceOrderPlugin or recordsPath.
I wrote a plugin that can hopefully do what you want, you can specify known or unknown entry points (using glob) and specify exact outputs or dynamically generate them using the entry file path and name. https://www.npmjs.com/package/webpack-entry-plus
I actually wound up just going into index.js in the file-loader module and changing where the contents were emitted to. This is probably not the optimal solution, but until there's some other way, this is fine since I know exactly what's being handled by this loader, which is just fonts.
//index.js
var loaderUtils = require("loader-utils");
module.exports = function(content) {
this.cacheable && this.cacheable();
if(!this.emitFile) throw new Error("emitFile is required from module system");
var query = loaderUtils.parseQuery(this.query);
var url = loaderUtils.interpolateName(this, query.name || "[hash].[ext]", {
context: query.context || this.options.context,
content: content,
regExp: query.regExp
});
this.emitFile("fonts/"+ url, content);//changed path to emit contents to "fonts" folder rather than project root
return "module.exports = __webpack_public_path__ + " + JSON.stringify( url) + ";";
}
module.exports.raw = true;
u can do lik
var config = {
// TODO: Add common Configuration
module: {},
};
var x= Object.assign({}, config, {
name: "x",
entry: "./public/x/js/x.js",
output: {
path: __dirname+"/public/x/jsbuild",
filename: "xbundle.js"
},
});
var y= Object.assign({}, config, {
name: "y",
entry: "./public/y/js/FBRscript.js",
output: {
path: __dirname+"/public/fbr/jsbuild",
filename: "ybundle.js"
},
});
let list=[x,y];
for(item of list){
module.exports =item;
}
The problem is already in the language:
entry (which is a object (key/value) and is used to define the inputs*)
output (which is a object (key/value) and is used to define outputs*)
The idea to differentiate the output based on limited placeholder like '[name]' defines limitations.
I like the core functionality of webpack, but the usage requires a rewrite with abstract definitions which are based on logic and simplicity... the hardest thing in software-development... logic and simplicity.
All this could be solved by just providing a list of input/output definitions... A LIST INPUT/OUTPUT DEFINITIONS.
Vinod Kumar's good workaround is:
module.exports = {
plugins: [
new FileManagerPlugin({
events: {
onEnd: {
copy: [
{source: 'www', destination: './vinod test 1/'},
{source: 'www', destination: './vinod testing 2/'},
{source: 'www', destination: './vinod testing 3/'},
],
},
}
}),
],
};

including devdependencies in package.json

I'd like to generate my devDependencies based on need. For this I have an array in my generator and some operations like this:
var FiddleGenerator = generator.Base.extend({
init: function() {
this.devDependencies = [];
},
//...excluded for brevity
gruntConfigure: function() {
this.devDepedencies = [
'grunt',
'grunt-contrib-watch',
'grunt-contrib-connect'
];
},
installStuff: {
if(this.option('skip-install')) return;
this.npmInstall(this.devDependencies, { saveDev: true });
}
});
The issue here is when the user opts to skip the npm installation and later does it manually (i.e. npm install) nothing gets installed.
However, I cannot simply write a package.json file like that...what versions do I put against each package in order to have them look like the following:
"devDependencies": {
"grunt": "~0.4.2",
"grunt-contrib-watch": "~0.5.3",
"grunt-contrib-connect": "^0.7.0"
}
Just write the devDependencies to the package.json file manually inside the JS code (this.fs.writeJSON). No need to use npmInstall() for that.
You can see this being done here: https://github.com/yeoman/generator-node/blob/master/generators/gulp/index.js#L38-L69

Disable LiveReload with Yeoman

When testing in IE8, LiveReload throws errors since web sockets is not supported. Is there a way to configure yeoman to disable LiveReload?
IE8 isn't supported by Yeoman, for good reason.
However, you could do what Allan describes, or you could override the server task, by putting this in your Gruntfile:
grunt.registerTask('server', 'yeoman-server');
Try to use <!--[if !IE]><!--></body><!--<![endif]--><!--[if IE]></body><!--<![endif]--> instead of </body>.
Generator would try to replace first </body> element and add livereload snippet before it, so code would be placed in invisible for IE space.
P.S. It`s dirty hack so use this carefuly
Put this in your Gruntfile:
grunt.registerHelper('reload:inject', function () {
return function inject(req, res, next) {
return next();
}});
Yes there is one I know.
Go to your project folder and find the file Gruntfile.js
Open the file in a editor
Remove the reload: in watch:
It will look something like this:
// default watch configuration
watch: {
coffee: {
files: 'app/scripts/**/*.coffee',
tasks: 'coffee reload'
},
compass: {
files: [
'app/styles/**/*.{scss,sass}'
],
tasks: 'compass reload'
},
reload: {
files: [
'app/*.html',
'app/styles/**/*.css',
'app/scripts/**/*.js',
'app/images/**/*'
],
tasks: 'reload'
}
}
And after you have removed it something like this:
// default watch configuration
watch: {
coffee: {
files: 'app/scripts/**/*.coffee',
tasks: 'coffee reload'
},
compass: {
files: [
'app/styles/**/*.{scss,sass}'
],
tasks: 'compass reload'
}
}
I think i have seen a commandline flag, but I was unable to find it.
Yeoman Livereload consists of two parts: the middleware that inserts the livereload snippet, and the livereload target in the watch task. To disable livereload, remove both:
Livereload snippet at the top of the Gruntfile:
// Generated on ...
'use strict';
var LIVERELOAD_PORT = 35729; // <- Delete this
var lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT}); // <- Delete this
var mountFolder = function (connect, dir) {
return connect.static(require('path').resolve(dir));
};
Livereload task in Watch:
watch: {
// Delete this target
livereload: {
options: {
livereload: LIVERELOAD_PORT
},
files: [
//...
]
}
}
And the middleware that inserts the snippet:
connect: {
options: {
port: 9000,
hostname: 'localhost'
},
livereload: {
options: {
middleware: function (connect) {
return [
lrSnippet, // <- Delete this middleware
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app)
];
}
}
For updates on fixing the livereload-connect issues in Yeoman, track this issue: https://github.com/yeoman/generator-webapp/issues/63

Resources