I'm trying to use the name of the target in a template. Should be simple enough, right?
My scenario is this:
copy:
{
all: {
src: 'commonFiles/**', dest: 'build/<%= grunt.???? =>/common'
},
apple: { ... },
orange:{ ... },
banana:{ ... },
...
}
grunt.registerTask('default', ['apple', 'orange', 'banana']);
grunt.registerTask('apple' , 'copy:all copy:apples ... ... ...');
grunt.registerTask('orange', 'copy:all copy:orange ... ... ...');
grunt.registerTask('banana', 'copy:all copy:banana ... ... ...');
grimt.registerTask(...);
...
many, many more fruit
I've scoured the docs, I've console.log'd grunt but found no string that is the parent task. The closest I found was grunt.task.current.name but that ends up being copy:all.
The goal would be to get a directory structure like this for all my fruit:
build/apple/common/...
build/orange/common/...
build/banana/common/...
build/.../common/...
...
commonFiles/...
I'm sending a fruit basked to whomever can figure this out.
A dynamic alias task would probably be better suited for this use case.
See http://gruntjs.com/frequently-asked-questions#dynamic-alias-tasks
grunt.initConfig({
buildDir: 'all',
copy: {
all: {
src: 'commonFiles/**',
dest: 'build/<%= buildDir =>/common',
},
apple: { ... },
orange:{ ... },
banana:{ ... },
},
});
grunt.registerTask('build', function(target) {
if (target == null) {
return grunt.warn('Build target must be specified, like build:apple.');
}
grunt.config('buildDir', target);
grunt.task.run('copy:' + target);
});
Related
I'm developing a website with Gatsby and I wanted to implement multi-language support.
So I used the gatsby-plugin-react-i18next plugin.
I followed all the steps, but it doesn't work, once I log into my website this error message shows:
error message
Right now, my code is the next one.
gatsby-config.js
module.exports = {
siteMetadata: {
title: "Space",
},
plugins: [
"gatsby-plugin-postcss",
{
resolve: `gatsby-source-filesystem`,
options: {
name: `locale`,
path: `${__dirname}/locales`
}
},
{
resolve: `gatsby-plugin-react-i18next`,
options: {
localeJsonSourceName: `locale`, // name given to `gatsby-source-filesystem` plugin.
languages: [`en`, `es`],
defaultLanguage: `en`,
// if you are using Helmet, you must include siteUrl, and make sure you add http:https
siteUrl: `https://example.com/`,
// you can pass any i18next options
// pass following options to allow message content as a key
},
pages: [
{
matchPath: '/:lang?/blog/:uid',
getLanguageFromPath: true,
excludeLanguages: ['es']
},
{
matchPath: '/preview',
languages: ['en']
}
]
}
],
};
index.js
import * as React from "react"
import { graphql } from "gatsby"
import { useTranslation } from "gatsby-plugin-react-i18next"
export default function IndexPage() {
const { t } = useTranslation();
return (
<h1>{t("Space")}</h1>
)
}
export const query = graphql`
query($language: String!) {
locales: allLocale(filter: {language: {eq: $language}}) {
edges {
node {
ns
data
language
}
}
}
}
`;
And of course I have the translation folders project structure
Im trying this plugin on a new blank project, not on my main project, so I don't understand why the plugin fails.
Any thoughts? Thanks in advice!
Edit: I add the translation.json of the two languages
English
Spanish
Your JSONs looks and the implementation too (couldn't be wrong being that simple). So to me, the issue relies on the configuration. Try something simpler such as:
{
resolve: `gatsby-plugin-react-i18next`,
options: {
localeJsonSourceName: `locale`,
path: `${__dirname}/locales`,
languages: [`en`, `es`],
defaultLanguage: `en`,
i18nextOptions: {
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
keySeparator: false,
nsSeparator: false,
},
},
},
my Configuration file is not able to find the spec file even though it is present in the path that i provided in the cucumberOpts..i tried all the resolutions but none of them is worked.
Config File
const log4js = require('log4js');
var fs=require('fs');
global.screenshots = require('protractor-take-screenshots-on-demand');
global.browser2;
var propertiesReader=require('properties-reader');
var env=require("../../env.js");
const {Given, Then, When, Before} = require('cucumber');
exports.config = {
//seleniumAddress: 'http://localhost:4444/wd/hub',
directConnect:true,
framework: 'custom',
// path relative to the current config file
frameworkPath: require.resolve('protractor-cucumber-framework'),
capabilities: {
'browserName': 'chrome',
metadata: {
browser: {
name: 'chrome',
version: '79'
},
device: 'MacBook Pro 15',
platform: {
name: 'OSX',
version: '10.12.6'
},
disableLog:true,
durationInMS:true,
openReportInBrowser:true
}
},
ignoreUncaughtExceptions:false,
// Spec patterns are relative to this directory.
specs: [
'../../Test_modules/features/'
],
beforeLaunch:function(){
if (fs.existsSync('./logs/ExecutionLog.log')) {
fs.unlink('./logs/ExecutionLog.log')
}
log4js.configure({
appenders: {
out: { type: 'console' },
info:{ type: 'dateFile', filename: "../Reports/logs/info", "pattern":"-dd.log",alwaysIncludePattern:false},
"console" : {
"type": "console",
"category": "console"
},
"file" : {
"category": "test-file-appender",
"type": "file",
"filename": "../../Reports/logs/log_file.log",
"maxLogSize": 10240,
// "backups": 3,
// "pattern": "%d{dd/MM hh:mm} %-5p %m"
}
},
categories: {
"info" :{"appenders": ["console"], "level": "info"},
"default" :{"appenders": ["console", "file"], "level": "DEBUG"},
//"file" : {"appenders": ["file"], "level": "DEBUG"}
}
});
},
cucumberOpts: {
require:['../../Test_modules/utilities/timeOutConfig.js','../../Test_modules/stepDefinition/spec.js'],
tags: false,
profile: false,
format:'json:../../Reports/jsonResult/results.json',
'no-source': true
},
onPrepare: function () {
const logDefault = log4js.getLogger('default');
const logInfo=log4js.getLogger('info');
screenshots.browserNameJoiner = ' - '; //this is the default
//folder of screenshot
screenshots.screenShotDirectory = '../../Screenshots';
global.openNewBrowser=require('../../Test_modules/utilities/newBrowserinstance.js');
global.testData=require('../../TestData/testData.json');
browser.logger = log4js.getLogger('protractorLog4js');
global.firstBrowser=browser;
global.properties=propertiesReader('../../TestData/propertyConfig.properties');
browser.waitForAngularEnabled(false);
browser.manage().window().maximize();
global.facebook=require('../../Test_modules/pages/fbPageObjects.js');
global.utility=require('../../Test_modules/utilities/testFile.js');
},
plugins: [{
package: 'H:/workspace/Proc-UI/node_modules/protractor-multiple-cucumber-html-reporter-plugin',
options:{
// read the options part for more options
automaticallyGenerateReport: true,
removeExistingJsonReportFile: true,
reportPath:'../../Reports/HtmlReports',
reportName:"test.html"
},
customData: {
title: 'Run info',
data: [
{label: 'Project', value: 'Framework Setup'},
{label: 'Release', value: '1.2.3'},
{label: 'Cycle', value: 'Test Cycle'}
]
},
}]
};
Spec File
var utilityInit,page2;//browser2;
page1=new facebook(firstBrowser);
module.exports=function(){
this.Given(/^Open the browser and Load the URL$/,async function(){
await firstBrowser.get(properties.get("url1"));
browser.logger.info("Title of the window is :"+await browser.getTitle());
//screenshots.takesScreenshot("filename");
});
this.When(/^User entered the text in the search box$/,async function(){
firstBrowser.sleep(3000);
await page1.email().sendKeys(testData.Login.CM[0].Username);
browser.sleep(3000);
await page1.password().sendKeys(testData.Login.CM[0].Password);
});
this.Then(/^click on login button$/,async function(){
browser.sleep(3000);
await facebook.submit().click();
});
this.Then(/^User tried to open in new browser instance$/,async function(){
browser2=await openNewBrowser.newBrowserInit(firstBrowser);
utilityInit=new utility(browser2);
utilityInit.ignoreSync(properties.get("url2"));
browser2.manage().window().maximize();
console.log(await utilityInit.title()+" title");
browser2.sleep(5000);
});
this.When(/^User entered the text in the email field$/,async function(){
page2=new facebook(browser2);
console.log(await page2.title()+" browser2");
await page2.search().sendKeys("testing");
browser2.sleep(3000);
page1=new facebook(firstBrowser);
console.log(await page1.title()+" browser1");
await page1.email().sendKeys(testData.Login.CM[0].Username);
screenshots.takeScreenshot("newScreenshot");
firstBrowser.sleep(5000);
});
};
Execution log
1) Scenario: Title of your scenario # ..\features\test.feature:24
? Given Open the browser and Load the URL
Undefined. Implement with the following snippet:
Given('Open the browser and Load the URL', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
? Then User tried to open in new browser instance
Undefined. Implement with the following snippet:
Then('User tried to open in new browser instance', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
? And User entered the text in the email field
Undefined. Implement with the following snippet:
Then('User entered the text in the email field', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
√ After # ..\..\node_modules\protractor-cucumber-framework\lib\resultsCapturer.js:27
1 scenario (1 undefined)
3 steps (3 undefined)
0m00.004s
i tried by adding cucumber dependencies, updating from relative path to absolute path everything i did.. but none it is resolved.. previously it worked fine but in the process of updating it in to public framework file.. i updated the paths from absolute to relative path. that's it i lost my whole framework and it is continuesly saying undefined scenarios.
**For Just made me sure i ran the script by passing wrong spec file name in the cucumber opts and still it giving Undefined and that confirmed me that it is not even considering that spec file that i passed.
Simple installation makes my framework works
npm install cucumber#1.3.3 --save-dev
I am currently trying to resolve an absolute path in yaml file to relative so it can be query using graphql in gatsby. The absolute path are provided from netlify-cms.
When the same path are being placed in md file and uses gatsby-remark-relative-images to convert it to relative path, it has no problem at all, but the same does not apply to yaml.
The image file are placed in static/img/ and the path provided by cms is /img/xxx.jpg
src/data/pages/index.yaml
page: index
slider:
- image: /img/1_new.jpg
url: ""
- image: /img/2_new.jpg
url: ""
- image: /img/3_new.jpg
url: ""
gatsby-config.js
module.exports = {
// ...
plugins: [
// ...
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/src/data`,
name: 'data',
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
path: `${__dirname}/static/img`,
name: 'uploads',
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
path: `${__dirname}/src/pages`,
name: 'pages',
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
path: `${__dirname}/src/assets/images`,
name: 'images',
},
},
{
resolve: 'gatsby-plugin-react-svg',
options: {
rule: {
include: /\.inline\.svg$/,
},
},
},
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
`gatsby-transformer-yaml-plus`,
{
resolve: 'gatsby-transformer-remark',
options: {
plugins: [
{
resolve: 'gatsby-remark-relative-images',
options: {
name: 'uploads',
},
},
{
resolve: 'gatsby-remark-images',
options: {
maxWidth: 2048, // must specify max width container
},
},
{
resolve: `gatsby-remark-responsive-iframe`,
options: {
wrapperStyle: `margin-bottom: 1.0725rem`,
},
},
{
resolve: 'gatsby-remark-copy-linked-files',
options: {
destinationDir: 'static',
},
},
`gatsby-remark-smartypants`,
`gatsby-remark-widows`,
],
},
},
{
resolve: 'gatsby-plugin-netlify-cms',
options: {
modulePath: `${__dirname}/src/cms/cms.js`,
},
},
'gatsby-plugin-netlify', // make sure to keep it last in the array
],
// for avoiding CORS while developing Netlify Functions locally
// read more: https://www.gatsbyjs.org/docs/api-proxy/#advanced-proxying
developMiddleware: app => {
app.use(
'/.netlify/functions/',
proxy({
target: 'http://localhost:9000',
pathRewrite: {
'/.netlify/functions/': ``,
},
})
)
},
}
Also, here is where it convert the absolute path in node into relative path
gatsby-node.js
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
fmImagesToRelative(node) // convert image paths for gatsby images
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
Finally, here is where it define the netlify-cms configuration
static/admin/config.yml
backend:
name: git-gateway
branch: master
media_folder: static/img
public_folder: /img
collections:
- label: "Data"
name: "data"
files:
- name: "index"
label: "Index"
file: "src/data/pages/index.yml"
fields:
- {label: "Page", name: "page", widget: hidden, default: "index"}
- label: "Slider"
name: "slider"
widget: list
fields:
- {label: "Image", name: "image", widget: image}
- {label: "Url", name: "url", widget: string, required: false}
Error Message
ERROR
GraphQL Error Field "image" must not have a selection since type "String" has no subfields.
file: /home/gaara/JS/iconic-starter-netlify-cms/src/pages/index.js
1 |
2 | query IndexPage {
3 | pagesYaml(page: { eq: "index" }) {
4 | id
5 | slider {
6 | desktop {
> 7 | image {
| ^
8 | childImageSharp {
9 | fluid(maxWidth: 2000, quality: 90) {
10 | aspectRatio
11 | presentationWidth
12 | src
13 | srcSet
14 | sizes
15 | }
16 | }
17 | }
⠙ extract queries from components
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
I had already made sure that all the image exists inside the static/img/ folder. I had also made several attempt in restarting the server so to avoid image not loading issue. The image path that given from netlify-cms should stay as /img/xxx.jpg because there is a lot of other markdown files uses it and has no problem in resolving the path.
May I know is there any configuration problem which I did wrong or miss out that causing the gatsby-remark-relative-images not being able to resolve the file path?
gatsby-remark-relative-images is a plugin that only works with markdown files handled by gatsby-transformer-remark.
The recent-ish graphql schema customization update allows new solution that's independent of file types. You can explore the official docs on the topic here: Customize the Graphql Schema (gatsby docs)
Instead modifying the image paths before gatsby gets to it (like with gatsby-remark-relative-images), we'd customize the graphql schema so that the image field (slider.desktop.image in your case) resolves to the image file node instead.
Please note that the node types below are just loose examples & you should go to your graphiql endpoint (i.e. localhost:8000/graphiql) to find the correct type names.
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes, createFieldExtension } = actions
createFieldExtension({
name: 'fileByStaticPath',
extend: () => ({
resolve: (src, args, ctx, info) => {
// look up original string value
const { fieldName } = info
const partialPath = src[fieldName]
// TODOS
// - join path to create the correct image file path
// - query the file node with `context.nodeModel.runQuery`
// - return the file node if exists
}
})
})
const typeDefs = `
type YamlSliderDesktop #infer {
image: File #fileByStaticPath
}
type YamlSlider #infer {
desktop: YamlSliderDesktop
}
type PagesYaml implements Node #infer {
slider: YamlSlider
}
`
createTypes(typeDefs)
}
I found myself doing this pretty often, so I wrote a plugin for it: gatsby-schema-field-absolute-path (github).
I also wrote a bit more in depth about this over here on my blog (byderek.com), but really, nothing that you won't find in the Gatsby official docs, just explained in a different language.
Hope it helps!
Let's say I have 3 target modes for grunt: quick, build and dist
I also have a custom target make-stuff:
grunt.registerTask('make-stuff', [
'someCSStask',
'someUtility',
'somePackage',
'isolatedTask' // More on this below
]);
...that runs in all 3 of the above target modes (quick, build, dist) like so:
grunt.registerTask('quick', [
'some-task1',
'make-stuff'
]);
grunt.registerTask('build', [
'some-task1',
'some-task2',
'make-stuff'
]);
grunt.registerTask('dist', [
'some-task3',
'build' // make-stuff gets ran here since we reference 'build'
]);
I would like to run make-stuff normally in each target mode, except quick, where I want it to ignore isolatedTask
If this is your setup, why not move 'isolatedTask' into build?
grunt.registerTask('build', [
'some-task1',
'some-task2',
'make-stuff',
'isolatedTask'
]);
Otherwise, try something like this
grunt.registerTask(
'isolatedTask',
'Isolated tasks for make-stuff, skip if target mode is quick.',
function() {
var target = this.args[0];
if (target === 'quick') { return; }
// logic here
}
);
grunt.registerTask(
'quick',
function() {
grunt.run.tasks([
...,
'isolatedTask:' + this.nameArgs
]);
}
);
I've got an HTML file with following content:
<html>
<body>
<span>{{ secret }}</span>
</body>
</html>
I'm looking for a grunt task that could take this source file, take a map of values:
grunt.initConfig({
myTask: {
myTarget: {
src: ...
dest: ...
values: {
secret: 'ABC'
}
}
}
})
and generate output file:
<html>
<body>
<span>ABC</span>
</body>
</html>
Is there any task like this? I saw grunt-mustache-html but it forces lots of things to exist which I really don't need and I don't want to use it. I want simply to take a single mustache (or hbs or whatever), fill it with data from grunt-level object and dump the result into another HTML file, that's all.
You could try grunt-template which processed lo-dash templates. Here's a basic setup to solve your problem:
//Gruntfile.js
config.template = {
myTask: {
options: {
data: function () {
return {
secret: 'ABC'
};
}
},
files: {
'output.html: ['template.html.tpl']
}
}
};
//template.html.tpl
<html>
<body>
<span><%= secret %></span>
</body>
</html>
#1. One options is to make use of grunt.template utility (see lagerone's answer). With custom delimiters you can achieve pretty close result to what you want:
grunt.template.addDelimiters('myDelimiters', '{{', '}}');
In this case your template will have to use {{= secret }} tags.
#2. Another option is that you can always write you own simple task. In your case it can look like this:
grunt.initConfig({
myTask: {
options: {
data: {
secret: 'ABC'
},
src: 'index.html',
dest: 'index.output.html'
}
}
});
grunt.registerTask('myTask', function() {
var options = this.options(),
template = grunt.file.read(options.src);
var content = template.replace(/\{\{\s*(.*?)\s*\}\}/g, function(a, b) {
return typeof options.data[b] !== undefined ? options.data[b] : '';
});
grunt.file.write(options.dest, content);
});
grunt.registerTask('default', ['myTask']);
I have used grunt-include-replace in the past. Is easy to use. In your gruntfile you will create a task similar to this one (Example taken from official github repo):
grunt.initConfig({
includereplace: {
your_target: {
options: {
// Task-specific options go here.
},
// Files to perform replacements and includes with
src: '*.html',
// Destination directory to copy files to
dest: 'dist/'
}
}
})