broccoli-config-replace does not work with the configuration given - javascript

I'm trying to use broccoli-config-replace unsuccessfully. What I would like to do is replacing a placeholder in my index.html and see it in the browser by executing broccoli serve
The interesting part of my Brocfile.js is this one:
var index_html = new ConfigReplace(app, './', {
// A list of files to parse:
files: [
'index.html',
],
configPath: 'replacements.json',
outputPath: 'production/',
patterns: [{
match: /\{\{SRC_REQUIRE\}\}/g,
replacement: function(config) { return config.SRC_REQUIRE; }
}]
});
module.exports = index_html;
but when I run broccoli serve what I get is this warning and nothing appears by pointing my browser to localhost:4200:
$ broccoli serve
Serving on http://localhost:4200
Warning: failed to stat tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/tmp/config_replace-input_base_path-5qF5n457.tmp/1/node_modules/broccoli-babel-transpiler/node_modules/babel-core/node_modules/regenerator/node_modules/defs/node_modules/yargs/node_modules/cliui/node_modules/center-align/node_modules/align-text/node_modules/kind-of/README.md
Segmentation fault: 11
nice segfault huh? I guess what I've written is not that OK, but the documentation is very lacking. Can anybody suggest me the right configuration to accomplish this simple task? Thank you

I've figured out how to get what I want, but I think the plugin still needs some development. Here is the right configuration:
var index_html = new ConfigReplace(appHtml, 'conf', {
// A list of files to parse:
files: [
'/production/index.html'
],
configPath: 'replacements.json',
patterns: [{
match: /\{\{SRC_REQUIRE\}\}/g,
replacement: function(config) { return config.SRC_REQUIRE; }
}]
});
Some facts I've noted:
The configuration node must be a directory. Root is not allowed, so I had to place my replacements.json in a subfolder (/conf)
The outputPath option seems not to be considered. I omitted it and used a pickFile before in order to create a tree with the right structure I wanted. Then I passed the tree to ConfigReplace (the appHtml you see in the configuration I pasted above)
Lack of documentation is a bad pal for adopting broccoli happily. I'm confident though.

Related

Resolving dynamic module with Webpack and Laravel Mix

Good time of the day,
Recently I've been trying to implement dynamic module loading functionality for my project. However, I'm failing for past few hours. To give you an idea of what I'm trying to achieve, here is the structure of the project
plugins
developer
assets
scss
developer.scss
js
developer.js
themes
theme_name
webpack.mix.js
node_modules/
source
js
application.js
bootstrap.js
scss
application.scss
_variables.scss
So, in order to get the available plugins, I've made the following function
/**
* Get all plugins for specified developer
* which have 'assets' folder
* #param developerPath
* #param plugins
*/
function getDeveloperPlugins(developerPath, plugins) {
if (fs.existsSync(developerPath)) {
fs.readdirSync(developerPath).forEach(entry => {
let pluginPath = path.resolve(developerPath, entry),
assetsPath = path.resolve(pluginPath, 'assets');
if (fs.existsSync(assetsPath))
plugins[entry] = assetsPath;
});
}
}
This function loads all the available plugins for the specified developer, then goes inside and looks for the assets folder, if it exists, then it returns it and we can work with the provided directory later.
The next step is to generate the reference for every plugin (direct path to the developer_name.js file) which later should be 'mixed' into one plugins.bundle.js file.
In order to achieve this, the following piece of code 'emerged'
_.forEach(plugins, (directory, plugin) => {
let jsFolder = path.resolve(directory, 'js'),
scssFolder = path.resolve(directory, 'scss');
if (fs.existsSync(jsFolder)) {
webpackModules.push(jsFolder);
let possibleFile = path.resolve(jsFolder, plugin + '.js');
if (fs.existsSync(possibleFile))
pluginsBundle.js[plugin] = possibleFile;
}
if (fs.existsSync(scssFolder)) {
webpackModules.push(scssFolder);
let possibleFile = path.resolve(scssFolder, plugin + '.scss');
if (fs.existsSync(possibleFile))
pluginsBundle.scss[plugin] = possibleFile;
}
});
And the last step before I'm starting to edit the configuration of the Webpack is to get the folders for both scss and js files for all plugins and all developers:
let jsPluginsBundle = _.values(pluginsBundle.js),
scssPluginsBundle = _.values(pluginsBundle.scss);
And here is where the problems start to appear. I've tried many solutions offered either here on GitHub (in respective repositories), but I've failed so many times.
The only error I'm having now is this one:
ERROR in F:/Web/Projects/TestProject/plugins/developer/testplugin/assets/js/testplugin.js
Module build failed: ReferenceError: Unknown plugin "transform-object-rest-spread" specified in "base" at 0, attempted to resolve relative to "F:\\Web\\Projects\\TestProject\\plugins\\developer\\testplugin\\assets\\js"
Yes, i know that webpack.mix.js file should be in the root folder of the project, however, i'm just developing theme, which uses modules developed by other members of the team.
So, idea was to:
Start build process: npm run dev|prod
Load plugins for all needed developers automatically
Use methods and html tags provided by the plugin (it is a mix of PHP for API routing and Vue.js for Components, etc) as follows: <test-component></test-component>
Any help is really appreciated, i just cant get my head around that error. If you need extra information, i'm ready to help since i myself need help to solve this issue =)
Update: The latest Webpack config used by mix.webpackConfig() (still failing though)
let webpackConfiguration = {
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: require.resolve('babel-loader'),
options: {
presets: [
'babel-preset-env'
].map(require.resolve),
plugins: [
'babel-plugin-transform-object-rest-spread'
].map(require.resolve)
}
}
}]
},
resolve: {
modules: webpackModules
}
};
mix.webpackConfig(webpackConfiguration);
And this is the content of the webpackModules variable:
[
'F:\\Web\\Projects\\TestProject\\themes\\testtheme\\node_modules',
'F:\\Web\\Projects\\TestProject\\themes\\testtheme',
'F:\\Web\\Projects\\TestProject\\plugins\\developer\\testplugin\\assets\\js',
'F:\\Web\\Projects\\TestProject\\plugins\\developer\\testplugin\\assets\\scss'
]
Okay, after 7 hours I've decided to try the most obvious method to solve the problem, to create node_modules folder in the root of the project and install laravel-mix there, and it worked like a charm.
Looks like, if it cant find the module in the directory outside the root scope of the Webpack, it will go up the tree to find the node_modules folder.
Developers should allow us to set the root folder for Webpack to fetch all the modules i guess, but well, problem is solved anyways.

load-grunt-config not finding target task

I want to split a large gruntfile in smaller pieces and came about these articles:
https://github.com/firstandthird/load-grunt-config
http://ericnish.io/blog/how-to-neatly-separate-grunt-files/
However, it seems I'm missing something obvious. When I issue a "grunt testtask" the task is not found. I'm doing something very wrong, obviously, but I don't get it.
Here's the content of the files, stripped down as much as possible:
gruntfile.js:
module.exports = function(grunt) {
var path = require('path');
require('load-grunt-config')(grunt, {
configPath: path.join(process.cwd(), 'grunt3'),
init: true
});
};
grunt3/testtask.js:
module.exports = {
copy: {
main:
{
files:
[{
src: "test1.txt",
dest: "test2.txt"
}]
}
}
};
I added an aliases file:
module.exports = {
'default': [],
'mytesttask': [
'testtask'
]
};
default is found. For mytesttalk I get "testtask not found".
Shouldn't aliases.js do a registerTask either for the filename (testtask) or for "copy" (I also tried using 'copy' as the target task)?
There is a config object named "testtask" according to --config-debug.
What am I missing here?
Thanks.
Addendum: found this very simple and straight-forward article on the same subject which shows how to simplify even further. Just, again, it's not working. The task specified in aliases is not found. e.g. 'mytesttask': [ 'testtask'] -> testtask is not found, although there is a grunt/testtask.js file that contains the task from the original gruntfile. What am I missing?
With the help of this excellent article http://mattbailey.io/a-beginners-guide-to-grunt-redux.html and one of the authors of that module commenting on github I finally found the flaw in my thinking. The files are not organized by tasks or targets but by grunt modules. So, you have to name them copy.js (from grunt-contrib-copy), cssmin.js (from grunt-contrib-cssmin), concat.js (from grunt-contrib-concat) und put the various targets in these files. Not the other way around (as I thought). Maybe that's clear for others from the documentation, it wasn't for me. That article by Matt Bailey is really great as it shows only what is really necessary. The article by Eric Nishio I referenced above is unnecessarily complex as it doesn't account for the aliases file.

Exclude files from broccoli Ember 2.0

Hi im kind of new to ember, im looking for a way to tell broccoli not to include my img/ directory, i want to include some default images there which ill be programatically adding to the app
<img src='{{model.picture}}'/>
And i can see them ok in development but not in production since the name has a hash attaches due to brocolli task, how do i configure my BrocFile to exclude files in the directory i have checked the documentation here
https://github.com/rickharrison/broccoli-asset-rev
but i cant figure out where in my brocfile im expected to add that.
part of my brocfile
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var app = new EmberApp({
modals: {
layout: true,
style: true,
animation: 'scale'
}
});
app.import({
production: 'bower_components/raygun4js/dist/raygun.js'
});
app.import('bower_components/lodash/lodash.js');
Since you are using Ember (and Ember-CLI), just make sure to scroll down far enough in the broccoli-asset-rev documentation that you linked and you will reach the part most relevant to your circumstance. In particular, the provided 'Ember CLI addon usage' example should already be a close match for your case.
Adapting that to your stated problem and provided code, you would perhaps get something along the lines of
var app = new EmberApp({
fingerprint: {
exclude: ['img/']
},
modals: {
layout: true,
style: true,
animation: 'scale'
}
});
The relevant Ember-CLI documentation section also explains fingerprinting in slightly more detail.
Other than using the exclude option, you could
set enabled: false if you don't actually need fingerprinting
not include image extensions in general via something like extensions: ['js', 'css', 'map']
This answer applies for Ember 2.x through at least 3.x.
Another approach is to use an addon that helps you easily exclude files. Installing
ember-cli-funnel and then specifying the file accomplishes this pretty nicely:
// ember-cli-build.js
let app = new EmberApp(defaults, {
funnel: {
exclude: [
`${defaults.project.pkg.name}/routes/style-guide/**/*`,
'addon-tree-output/some-addon/styles/**/*.scss'
]
}
});

Simple solution to share modules loaded via NPM across multiple Browserify or Webpack bundles

Pulling my hair out here looking for a simple solution to share code, required via NPM, across multiple Browserify or Webpack bundles. Thinking, is there such a thing as a file "bridge"?
This isn't due to compile time (I'm aware of watchify) but rather the desire to extract out all of my vendor specific libs into vendor.js so to keep my app.js filesize down and to not crash the browser with massive sourcemaps. Plus, I find it way cleaner should the need to view the compiled js arise. And so:
// vendor.js
require('react');
require('lodash');
require('other-npm-module');
require('another-npm-module');
Its very important that the code be loaded from NPM as opposed to Bower, or saved into some 'vendor' directory in order to be imported via a relative path and identified via a shim. I'd like to keep every library reference pulled via NPM except for my actual application source.
In app.js I keep all of my sourcecode, and via the externals array, exclude vendor libraries listed above from compilation:
// app.js
var React = require('react');
var _ = require('lodash');
var Component = React.createClass()
// ...
And then in index.html, I require both files
// index.html
<script src='vendor.js'></script>
<script src='app.js'></script>
Using Browserify or Webpack, how can I make it so that app.js can "see" into those module loaded via npm? I'm aware of creating a bundle with externals and then referencing the direct file (in, say, node_modules) via an alias, but I'm hoping to find a solution that is more automatic and less "Require.js" like.
Basically, I'm wondering if it is possible to bridge the two so that app.js can look inside vendor.js in order to resolve dependencies. This seems like a simple, straightforward operation but I can't seem to find an answer anywhere on this wide, wide web.
Thanks!
Listing all the vendor files/modules and using CommonChunkPlugin is indeed the recommended way. This gets pretty tedious though, and error prone.
Consider these NPM modules: fastclick and mprogress. Since they have not adopted the CommonJS module format, you need to give webpack a hand, like this:
require('imports?define=>false!fastclick')(document.body);
require('mprogress/mprogress.min.css');
var Mprogress = require('mprogress/mprogress.min.js'),
Now assuming you would want both fastclick and mprogress in your vendor chunk, you would probably try this:
module.exports = {
entry: {
app: "./app.js",
vendor: ["fastclick", "mprogress", ...]
Alas, it doesn't work. You need to match the calls to require():
module.exports = {
entry: {
app: "./app.js",
vendor: [
"imports?define=>false!fastclick",
"mprogress/mprogress.min.css",
"mprogress/mprogress.min.js",
...]
It gets old, even with some resolve.alias trickery. Here is my workaround. CommonChunkPlugin lets you specify a callback that will return whether or not you want a module to be included in the vendor chunk. If your own source code is in a specific src directory, and the rest is in the node_modules directory, just reject the modules based on their path:
var node_modules_dir = path.join(__dirname, 'node_modules'),
app_dir = path.join(__dirname, 'src');
module.exports = {
entry: {
app: "./app.js",
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(
/* chunkName= */"vendor",
/* filename= */"vendor.bundle.js"
function (module, count) {
return module.resource && module.resource.indexOf(app_dir) === -1;
}
)
]
};
Where module.resource is the path to the module being considered. You could also do the opposite, and include only the module if it is inside node_modules_dir, i.e.:
return module.resource && module.resource.indexOf(node_modules_dir) === 0;
but in my situation, I'd rather say: "put everything that is not in my source source tree in a vendor chunk".
Hope that helps.
With webpack you'd use multiple entry points and the CommonChunkPlugin.
Taken from the webpack docs:
To split your app into 2 files, say app.js and vendor.js, you can require the vendor files in vendor.js. Then pass this name to the CommonChunkPlugin as shown below.
module.exports = {
entry: {
app: "./app.js",
vendor: ["jquery", "underscore", ...],
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(
/* chunkName= */"vendor",
/* filename= */"vendor.bundle.js"
)
]
};
This will remove all modules in the vendor chunk from the app chunk. The bundle.js will now contain just your app code, without any of it’s dependencies. These are in vendor.bundle.js.
In your HTML page load vendor.bundle.js before bundle.js.
<script src="vendor.bundle.js"></script>
<script src="bundle.js"></script>
// vendor anything coming from node_modules
minChunks: module => /node_modules/.test(module.resource)
Source: https://github.com/webpack/webpack/issues/2372#issuecomment-213149173

Dynamically add version number to dest output files w/ grunt

I have a package.json file with our version number, such as:
{
name: "myproject"
version: "2.0"
}
My goal is to dynamically add the version number from the package.json file into the output files. For example, in the javascript I don't want to manually update the version number, but would like something similar to this to be generated after each grunt build:
/* My Project, v2.0 */
window.myProject = {
version: "2.0"
};
Is there an easy way to do this in my Gruntfile.js configuration?
I implemented: https://github.com/erickrdch/grunt-string-replace
In my source css/js files, I use the text {{ VERSION }} which gets replaced with the version number set in the package.json file. Below is the config I added to Gruntfile.js.
'string-replace': {
version: {
files: {
// the files I did string replacement on
},
options: {
replacements: [{
pattern: /{{ VERSION }}/g,
replacement: '<%= pkg.version %>'
}]
}
}
},
pkg: grunt.file.readJSON('package.json'),
I think that what you only want to do is to put some kind of trick for unable the page to use the cache files that maybe the browser have, and by now, the only way for that cross-browser is putting something on the href urls like "app.v2_2.js" or "app.js?ver=22". So I use this grunt npm package:
https://www.npmjs.org/package/grunt-cache-breaker
By default it only adds a parameter to your javascript and in almost the cases is the thing you need for not using cache, but you can configure even if you change the name of the file in other grunt process. This only change the HTML headers to what you desire.
After you install the grunt-cache-breaker, add this to your GruntFile:
// Append a timestamp to 'app.js', 'controllers.min.js' which are both located in 'index.html'
// resulting in the index the call of : href="~/app.js?rel=1415124174159"...
cachebreaker: {
dev: {
options: {
match: ['app.js', 'styles.css']
},
files: {
src: ['dist/index.html']
}
}
},
Then where you load the modules:
grunt.loadNpmTasks('grunt-cache-breaker');
Add on the task you want to:
grunt.registerTask('deploy', [
'clean:app',
'copy:views',
'copy:imgs',
'copy:css',
'uglify:app',
'cssmin:app',
'cachebreaker:dev'
]);
And finally run the grunt action on the console/command prompt
> grunt deploy
I would suggest using the banner feature in grunt-contrib-concat
this can be done as well with the banner option of https://github.com/gruntjs/grunt-contrib-uglify - which takes also care of the minifiaction of the javascript files.
filerev provides this option now. Use process to manipulate the filename that will be otherwise suffixed with md5 hash of the file content. You can use this to insert your version to every file you want.
Ref: https://github.com/yeoman/grunt-filerev
create something like package.json in the root of your project
it should read that or you can do something like
pkg: grunt.file.readJSON('package.json'),
in that you'll have a version declaration which would obviously correspond to <%= pkg.version %> so have that string in your json output and then run grunt.config.process to do the variable replacement
do something similar for the comment header

Categories

Resources