inside my grunt configuration if have a variable which defines a directory which contains a css file. Now I would like to configure a grunt task which insert the value of this variable into a html file.
For example, I can imagine that I have an index.html file as follows
<!doctype html>
<head>
<link rel="stylesheet" href="<% pathToCss %>/styles.css">
...
But I cannot find a task which can do that for me. Any suggestions which grunt taks can do this for me ?
I just found out that it can be done with grunt.template as follows:
template: {
options: {
data: {
pathToCss: './css'
}
},
demo: {
files: [
{ '<%= ./output/index.html': ['<%= ./input/template.html'] }
]
}
},
And in the input file (template.html) you define 'pathToCss' as follows:
<link rel="stylesheet" href="../../<%- pathToCss %>/styles.css">
However, if I look at the documentation, I don't see where this is documentated!
I think the grunt-replace package is what you're looking for. You can read an external file and use its value in the patterns definitions like so:
replace: {
dist: {
options: {
patterns: [
{
match: '<% pathToCss %>',
replacement: '<%= grunt.file.read("conf/assets-dir.txt") %>'
}
]
}
}
}
Related
I am loading a local html file as the src for a NativeScript WebView component. Contained within the html file are script tags which reference javascript files that are also local resources (bundled within the app). The html file loads into the WebView just fine, but the referenced script file (mylib.js) does not.
I suspect a pathing problem but I have tried almost every variation I can think of to no avail.
My project is actually a NativeScript-Vue project and is as follows:
App.vue
<template>
<Page #loaded="onPageLoaded">
<ActionBar title="Welcome to WebView"/>
<GridLayout>
<WebView ref="myWebView" row="0" col="0"
:src="filePath" #loadFinished="onWebViewLoaded" />
</GridLayout>
</Page>
</template>
<script>
import * as fs from "tns-core-modules/file-system"
import * as utils from "utils/utils"
export default {
data() {
return {
filePath: ''
}
},
methods: {
onPageLoaded () {
this.setLocalIndexFilePath()
},
onWebViewLoaded (event) {
if (event.error) {
console.log(error)
} else {
console.log('webview loaded')
}
},
setLocalIndexFilePath () {
const deviceName =
utils.ios.getter(UIDevice, UIDevice.currentDevice).name
// iPhone 6 is the name of my simulator
if (deviceName == 'iPhone 6') {
const webViewSRC =
encodeURI(`${fs.knownFolders.currentApp().path}/www/index.html`)
this.filePath = webViewSRC
console.log(webViewSRC)
} else {
this.filePath = "~/www/index.html"
}
}
}
}
</script>
index.html
<!doctype html>
<head>
<script src="./mylib.js" type="text/javascript"></script>
<script type="text/javascript">
function onBodyLoaded() {
var msg = document.getElementById('msg');
msg.insertAdjacentHTML('beforeend', '<br />body loaded!');
}
function onLocalButtonClicked() {
var msg = document.getElementById('msg');
msg.insertAdjacentHTML('beforeend', '<br />local: You clicked button!');
}
</script>
</head>
<html>
<body onload="onBodyLoaded()">
<Button onclick="onLocalButtonClicked()">Click Me</Button>
<Button onclick="onButtonClicked()">Click Me to test external js</Button>
<p id="msg">Debug:</p>
</body>
</html>
mylib.js
// This function never gets called
function onButtonClicked() {
var msg = document.getElementById('msg');
msg.insertAdjacentHTML('beforeend', '<br />external js file: You clicked button!');
}
webpack.config.sys
...
// Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: "fonts/**" },
{ from: "**/*.+(jpg|png)" },
{ from: "assets/**/*" },
{ from: "www/**/*" },
...
This is a known issue with iOS. There is a patch work you could try, I had implemented the same in Playground for a similar issue, its applicable for Vue too.
I have an ASP.NET MVC application that is using Angular 4. In my layout I have a base tag that looks like this:
<base href="/src/">
I am setting everything up and I just added Angular Routing. Now right after my base component loads my URL is appended with 'src'.
Here is my routes file:
import { Routes } from '#angular/router';
import { HomeComponent } from './Components/Home/home.component';
export const AppRouting: Routes = [
{ path: '', component: HomeComponent }
];
I did not see this prior to adding the routing.
The key purpose of the base tag is for routing. This is from the docs:
Most routing applications should add a element to the
index.html as the first child in the tag to tell the router how
to compose navigation URLs.
If the app folder is the application root, as it is for the sample
application, set the href value exactly as shown here.
https://angular.io/guide/router#base-href
At development time, it is most often set to "/" so the routes will run from root. At deployment, you change it to the folder on the server containing your application.
I was able to fix this. For reference, my app folder is under a src directory, not in the root of my project. Here is what I did.
Change the base tag to:
<base href="/">
Update my main.js call from:
<script>
System.import('main.js').catch(function (err) { console.error(err); });
</script>
to:
<script>
System.import('src/main.js').catch(function (err) { console.error(err); });
</script>
Then in my systemjs.config.js I had to change these lines:
map: {
//app is within the app folder
'app': 'app',
to:
map: {
//app is within the app folder
'app': 'src/app',
and I also had to change:
packages: {
app: {
defaultExtension: 'js',
meta: {
'./*.js': {
loader: 'systemjs-angular-loader.js'
}
}
},
to:
packages: {
app: {
defaultExtension: 'js',
meta: {
'./*.js': {
loader: 'src/systemjs-angular-loader.js'
}
}
},
Here is my Razor page code:
#using System.Web.Optimization;
#{ BundleTable.Bundles.Add(
new ScriptBundle("~/Scripts/Vuejs")
.Include("~/Static/Scripts/Vuejs/vue.min.js")); }
#section Scripts {
#Scripts.Render("~/Static/vue/assets/bundle.js")
#Scripts.Render("~/Scripts/Vuejs")
}
<div id="app_container">
{{text}}
</div>
and here is the entry of the webpack javascript:
import Vue from 'vue';
const v = new Vue({
el: '#app_container',
data: { text: 'abcdefg' }
});
Webpack config:
export default {
entry: [
'babel-polyfill',
'./src/index.js'
],
output: {
filename: 'bundle.js',
path: 'C:/WebSandbox/Static/vue/assets',
publicPath: '/vue/assets/'
},
devtool: 'source-map',
module: {
loaders: [
{ test: /\.vue$/, loader: 'vue' },
{ test: /\.js/, loader: 'babel', exclude: /node_modules/ },
{ test: /\.json$/, loader: 'json' },
{ test: /\.txt/, loader: 'raw' }
]
},
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
APP_ENV: JSON.stringify('browser')
}
})
]
};
All the javascript files are in place and when open the page I can see the mapped code from Developer Tools of Chrome. And if I make a break point in the javascript code, it will be hit.
But the text displayed is "{{text}}", not "abcdefg".
If I added following code after the div:
<script>
const v = new Vue({ el: "#app_container", data: { text: "abcdefg" } });
</script>
or add following code and remove the javascript file from #section Scripts part
<script src='~/Static/vue/assets/bundle.js'></script>
It works.
So how can I make my webpack bundle work with the #Scripts.Render in Razor page?
OK, now I found why the bundle not working:
Because the #RenderSection("Scripts", false) was written in the header of _Layout.cshtml. So the bundle JavaScript file will be referenced in the header. But when I switch to the raw reference (script tag), it will be after my div tag where it should be.
When I change the bundle part to:
#section ScriptBlock {
#Scripts.Render("~/Static/vue/assets/bundle.js")
}
It works.
The #RenderSection("ScriptBlock", false) was written in the bottom of the _Layout.cshtml right after the closing tag of body.
I use vuejs with asp.net with browserify rather than webpack.
And the packing should be an independent build step.
I setup a gulp task to take my vue code and bundle it up and place it in the scripts folder of asp.net.
I think you need to do something similar here.
According to the polymer documentation for app-localize-behavior
Each element that displays content to be localized should add Polymer.AppLocalizeBehavior. All of these elements share a common localization cache, so you only need to load translations once.
In the following snippet (adapted from this answer) does not find the shared resources in the tag
Maybe I missed something ?
<!DOCTYPE html>
<html>
<head>
<base href="https://polygit.org/polymer+:master/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="https://rawgit.com/yahoo/intl-messageformat/d361003/dist/intl-messageformat.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="app-localize-behavior/app-localize-behavior.html">
</head>
<body>
<x-local-translate></x-local-translate>
<dom-module id="x-local-translate">
<template>
<div>
<span title="english">🇬🇧</span>
<paper-toggle-button on-change="_toggle" id="switch"></paper-toggle-button>
<span title="french">🇫🇷</span>
</div>
<div>
<h4>Outside Repeater</h4>
<div>
<div>{{localize('greeting')}}</div>
</div>
<h4>Template Repeater Items</h4>
<template is="dom-repeat" items="{{things}}">
<div>{{localize('greeting')}}</div>
</template>
<x-local-test></x-local-test>
</div>
</template>
<script>
Polymer({
is: "x-local-translate",
behaviors: [
Polymer.AppLocalizeBehavior
],
properties: {
things: {
type: Array,
value: function() {
return [1, 2, 3];
}
},
/* Overriden from AppLocalizeBehavior */
language: {
value: 'en',
type: String
},
/* Overriden from AppLocalizeBehavior */
resources: {
type: Object,
value: function() {
return {
'en': {
'greeting': 'Hello!'
},
'fr': {
'greeting': 'Bonjour!'
}
};
}
}
},
_toggle: function() {
this.language = this.$.switch.checked ? 'fr' : 'en';
}
});
</script>
</dom-module>
<dom-module id="x-local-test">
<template>
<h4>Inside x-local-test</h4>
<div>{{localize('greeting')}}</div>
</template>
<script>
Polymer({
is: "x-local-test",
behaviors: [
Polymer.AppLocalizeBehavior
],
properties: {
things: {
type: Array,
value: function() {
return [1, 2, 3];
}
}
},
});
</script>
</dom-module>
</body>
</html>
Now in the following fiddle, I made it work by passing the resources and language object as x-local-test properties.
https://jsfiddle.net/g4evcxzn/2/
But it should work without that
According the ideas of Jose A. and Jean-Rémi here some example code for copy/paste:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/app-localize-behavior/app-localize-behavior.html">
<script>
MyLocalizeBehaviorImpl = {
properties: {
language: {
value: 'de'
}
},
attached: function() {
this.loadResources(this.resolveUrl('locales.json'));
}
};
MyLocalizeBehavior = [MyLocalizeBehaviorImpl, Polymer.AppLocalizeBehavior];
</script>
Include the behavior file in all your custom components and add the behavior:
<link rel="import" href="./my-localize-behavior.html">
......
behaviors: [
MyLocalizeBehavior
],
I took a look at AppLocaleBehavior's demo and if you actually look at the repo, they use two elements for it, one that loads the resources from an external json and one more that has them locally defined and in the demo, the don't seem to be sharing a cache, just as what's happening to you.
This struck me as odd seeing that they do mention the cache, so I took a look at the behavior's code and found out something interesting, the cache actually exists but it seems its purpose is to prevent loading the same external resource multiple times rather than sharing the resources property.
So, if you want to share localization resources on multiple elements the way to go would be having a common resource (let's say we call it locales.json) and call the loadResources function on every one of them (Since the request is cached you don't need to worry about loading the file multiple times). You could do it on the attached callback like this:
attached: function () {
this.loadResources(this.resolveUrl('locales.json'));
}
Now I wrote a template very easily:
Hello, my name is {name}, I'm {age}.
And then open this website: http://linkedin.github.io/dustjs/test/test.html, do some pasting and the template js codes are generated below:
(function() {
dust.register("demo", body_0);
function body_0(chk, ctx) {
return chk.write("Hello, my name is ").reference(ctx._get(false, ["name"]), ctx, "h").write(", I'm ").reference(ctx._get(false, ["age"]), ctx, "h").write(".");
}
return body_0;
})();
Then I created a js file and copy all the js codes generated above and refer this into my app:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>DustDemo</title>
<script src="jsfiles/dust.js"></script>
<script src="jsfiles/staticpagetemplate.js"></script>
<script>
function Demo1() {
dust.render("demo", { name: "test", age: 13 }, function (err, out) {
alert(out);
});
}
</script>
</head>
<body onload="Demo1()">
<h1>Demo 1——Static Page</h1>
<div id="divDemo1">
</div>
</body>
</html>
Question is that if I use like this, it reports me "_get" cannot be found. Later I found the problem in dust.js:
Context.prototype.get = function (key) {
var ctx = this.stack, value;
while (ctx) {
if (ctx.isObject) {
value = ctx.head[key];
if (!(value === undefined)) {
return value;
}
}
ctx = ctx.tail;
}
return this.global ? this.global[key] : undefined;
};
So no "_get" but "get" instead!
Why this MISMATCHES the translator online?? Anyone can help me??
You are likely using an old version of Dust in jsfiles/dust.js. As of Dust 2.2.0 get has been replaced with _get. The compiler on http://linkedin.github.io/dustjs/test/test.html uses the new version of Dust, so it compiles the template using _get instead of get.
You have compiled your template with a new version of Dust, but you are trying to render it with an old version of Dust, and the two are not compatible.