I have the following task that build my application:
const app = new Metalsmith(config.styleguide.path.root);
app.use(
msDefine({
production: false,
rootPath: '/'
})
);
app.use(
msIf(
gutil.env.config === 'release',
msDefine({
production: true,
rootPath: '/styleguide/'
})
)
);
app.build(...);
I need to access the rootPath from within the application, eg:
import stuff from 'stuff';
export class IconCtrl ...
...
_getIconPath(name: string, size: string): string {
switch (this.version) {
case 'current':
return `${stuff.rootPath()}/current/icn-${name}-${size}.svg`;
default:
return `${stuff.rootPath()}/legacy/${name}.svg`;
}
}
...
I haven't found a clean way to do it so far. I am not sure how to access the application configuration at build time from within the app.
you could use something like gulp-inject-scripts.
https://www.npmjs.com/package/gulp-inject-scripts
Example
var gulp = require('gulp');
var injectScripts = require('gulp-inject-scripts');
gulp.task('inject:script', function(){
return gulp.src('./demo/src/*.html')
.pipe(injectScripts({
baseDir "./demo/dist" // SET BASE DIRECTORY
}))
.pipe(gulp.dest('./demo/dist'));
});
Related
Strapi Version: 4.3.0
Operating System: Ubuntu 20.04
Database: SQLite
Node Version: 16.16
NPM Version: 8.11.0
Yarn Version: 1.22.19
I have created Preview button for an article collection type. I'm using the Strapi blog template. I managed to make the Preview button appear in the Content Manager. I hard coded the link to be opened when you click the Preview button and it works. Now, I want the plugin to use a link with environment variables instead of a hard coded link. I don't know how I can access the environment variables in the source code for the plugin.
My objective:
I want to replace
href={`http://localhost:3000?secret=abc&slug=${initialData.slug}`}
with
href={${CLIENT_FRONTEND_URL}?secret=${CLIENT_SECRET}&slug=${initialData.slug}`}
in ./src/plugins/previewbtn/admin/src/components/PreviewLink/index.js
where CLIENT_FRONTEND_URL and CLIENT_SECRET are environment variables declared like so in .env:
CLIENT_FRONTEND_URL=http://localhost:3000
CLIENT_PREVIEW_SECRET=abc
Here's a rundown of the code I used:
First, I created a strapi app using the blog template, then created a plugin.
// Create strapi app named backend with a blog template
$ yarn create strapi-app backend --quickstart --template #strapi/template-blog#1.0.0 blog && cd backend
// Create plugin
$ yarn strapi generate
Next, I created a PreviewLink file to provide a link for the Preview button
// ./src/plugins/previewbtn/admin/src/components/PreviewLink/index.js
import React from 'react';
import { useCMEditViewDataManager } from '#strapi/helper-plugin';
import Eye from '#strapi/icons/Eye';
import { LinkButton } from '#strapi/design-system/LinkButton';
const PreviewLink = () => {
const {initialData} = useCMEditViewDataManager();
if (!initialData.slug) {
return null;
}
return (
<LinkButton
size="S"
startIcon={<Eye/>}
style={{width: '100%'}}
href={`http://localhost:3000?secret=abc&slug=${initialData.slug}`}
variant="secondary"
target="_blank"
rel="noopener noreferrer"
title="page preview"
>Preview
</LinkButton>
);
};
export default PreviewLink;
Then I edited this pregenerated file in the bootstrap(app) { ... } section only
// ./src/plugins/previewbtn/admin/src/index.js
import { prefixPluginTranslations } from '#strapi/helper-plugin';
import pluginPkg from '../../package.json';
import pluginId from './pluginId';
import Initializer from './components/Initializer';
import PreviewLink from './components/PreviewLink';
import PluginIcon from './components/PluginIcon';
const name = pluginPkg.strapi.name;
export default {
register(app) {
app.addMenuLink({
to: `/plugins/${pluginId}`,
icon: PluginIcon,
intlLabel: {
id: `${pluginId}.plugin.name`,
defaultMessage: name,
},
Component: async () => {
const component = await import(/* webpackChunkName: "[request]" */ './pages/App');
return component;
},
permissions: [
// Uncomment to set the permissions of the plugin here
// {
// action: '', // the action name should be plugin::plugin-name.actionType
// subject: null,
// },
],
});
app.registerPlugin({
id: pluginId,
initializer: Initializer,
isReady: false,
name,
});
},
bootstrap(app) {
app.injectContentManagerComponent('editView', 'right-links', {
name: 'preview-link',
Component: PreviewLink
});
},
async registerTrads({ locales }) {
const importedTrads = await Promise.all(
locales.map(locale => {
return import(
/* webpackChunkName: "translation-[request]" */ `./translations/${locale}.json`
)
.then(({ default: data }) => {
return {
data: prefixPluginTranslations(data, pluginId),
locale,
};
})
.catch(() => {
return {
data: {},
locale,
};
});
})
);
return Promise.resolve(importedTrads);
},
};
And lastly this created this file to enable the plugin Reference
// ./config/plugins.js
module.exports = {
// ...
'preview-btn': {
enabled: true,
resolve: './src/plugins/previewbtn' // path to plugin folder
},
// ...
}
I solved this by adding a custom webpack configuration to enable Strapi's admin frontend to access the environment variables as global variables.
I renamed ./src/admin/webpack.example.config.js to ./src/admin/webpack.config.js. Refer to the v4 code migration: Updating the webpack configuration from the Official Strapi v4 Documentation.
I then inserted the following code, with help from Official webpack docs: DefinePlugin | webpack :
// ./src/admin/webpack.config.js
'use strict';
/* eslint-disable no-unused-vars */
module.exports = (config, webpack) => {
// Note: we provide webpack above so you should not `require` it
// Perform customizations to webpack config
// Important: return the modified config
config.plugins.push(
new webpack.DefinePlugin({
CLIENT_FRONTEND_URL: JSON.stringify(process.env.CLIENT_FRONTEND_URL),
CLIENT_PREVIEW_SECRET: JSON.stringify(process.env.CLIENT_PREVIEW_SECRET),
})
)
return config;
};
I rebuilt my app afterwards and it worked.
You shouldn't have to change the webpack config just find .env file in the root directory
add
AWS_ACCESS_KEY_ID = your key here
then just import by
accessKeyId: env('AWS_ACCESS_KEY_ID')
I am new to Ember, and am trying to use a global variable in the config / environment file to then import it into several adapters and models. I need this to change the variable in one place, instead of editing each file.
In this case, the global variable is a string with the address of the api server. The variable is named apiRoot. I tried to use the following configuration, but it does not work. Please tell me what needs to be done, if this is possible in the Ember, or maybe there is another way? Thanks for any help!
Environment File:
'use strict';
module.exports = function(environment) {
let ENV = {
modulePrefix: 'front',
environment,
rootURL: '/',
locationType: 'auto',
EmberENV: {
FEATURES: {
},
EXTEND_PROTOTYPES: {
Date: false
}
},
APP: {
}
};
if (environment === 'development') {
}
if (environment === 'test') {
ENV.locationType = 'none';
ENV.APP.LOG_ACTIVE_GENERATION = false;
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false;
}
if (environment === 'production') {
}
ENV.apiRoot = 'http://localhost:5555/api';
return ENV;
};
Adapter:
import RESTAdapter from '#ember-data/adapter/rest';
import ENV from '../../config/environment';
export default RESTAdapter.extend({
host: ENV.apiRoot,
pathForType() {
return "posts";
}
});
The problem is that your relative path probably refers to the /config/environment file outside of your appfolder. But it should refer to config/environment inside your app folder, a file that does not exist in your filesystem!
The reason for that is that you are not importing the config/environment file from the file system. Because that file does not exist in the browser. Instead ember-cli will execute that file during build time and send only the resulting JSON to your browser an make it avaliable at config/environment. But for all path in the browser the app folder is the root of your project. You can not import something outside the app folder.
And so your config/environment JSON that ember-cli produced will be basically moved into the app folder.
I use Laravel 5.4 with Vue.js 2.6. I have problem to see sourceMap of *.vue component file in console. I configure Laravel mix with this script:
let mix = require('laravel-mix');
mix.webpackConfig({
devtool: 'eval-source-map'
});
mix.js([
'resources/assets/js/app.js'
], 'public/js')
.sourceMaps()
.version();
For example I have vue component like this:
<template>
<div class="Example" #click="add()">
{{ name }}
</div>
</template>
<script>
export default {
data(){
return {
name: 'John'
}
},
methods:{
add(){
console.log('example click')
}
}
};
</script>
but when Laravel mix compile it, I see like this in source tab of chrome:
var render = function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c(
"div",
{
staticClass: "Example",
on: {
click: function($event) {
return _vm.add()
}
}
},
[_vm._v("\n " + _vm._s(_vm.name) + "\n")]
)
}
var staticRenderFns = []
render._withStripped = true
module.exports = { render: render, staticRenderFns: staticRenderFns }
if (module.hot) {
module.hot.accept()
if (module.hot.data) {
require("vue-hot-reload-api") .rerender("data-v-650f2efa", module.exports)
}
}
//////////////////
// WEBPACK FOOTER
// ./node_modules/vue-loader/lib/template-compiler?{"id":"data-v-650f2efa","hasScoped":false,"buble":{"transforms":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0!./resources/assets/js/components/Example.vue
// module id = ./node_modules/vue-loader/lib/template-compiler/index.js?{"id":"data-v-650f2efa","hasScoped":false,"buble":{"transforms":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0!./resources/assets/js/components/Example.vue
// module chunks = 0
What should I do to see real and pure Example vue.js component in source tab?
Are you in the correct source location in the browser? You should look under webpack:// branch and not the top branch. If it help, my webpack mix has devtool: 'source-map' instead of devtool: 'eval-source-map' and I get the following - see screenshot below:
I can view and debug all the sources under webpack:// fine.
I want to add custom template functions for Pug views.
For simplicity I've created a demo file with one custom function uppercase:
const Koa = require("koa")
const views = require("koa-views")
const app = new Koa()
app.use(
views(__dirname + "/views", {
extension: "pug",
options: {
helpers: {
uppercase: str => str.toUpperCase()
}
}
})
)
app.use(ctx => ctx.render("index", { name: "Name1" }))
app.listen(3000)
Here is a mega simple template views/index.pug:
h1= uppercase(name)
But it doesn't work, it prints such error:
TypeError: /Users/max7z/projects/test/t24__test__koa-views_pug/views/index.pug:1
> 1| h1= uppercase(name)
2|
uppercase is not a function
Not using Koa, but I solved a similar issue recently using Eleventy.js with Pug. The Pug documentation is not great on this, so it took a while to figure out.
I had to make the function a global, then use the globals property when rendering the template.
e.g.
global.uppercase = function(str){
return str.toUpperCase();
}
app.use(
views(__dirname + "/views", {
extension: "pug",
options: {
globals: ["uppercase"]
}
})
)
I am using the vue-webpack template and I have created a settings.json file to store environment variables that should be changed when installing the script.
My settings.json (just store the absolute path to the API server):
{
"apiURL": "//localhost/app/server/API"
}
How can I keep the file from being minified/bundled in the production version such that I can change it and the updated file will be used next time the app is accessed (without having to build it again) ?
In my app I use this file via require:
const SETTINGS = require('../settings.json');
I understand that by requireing it webpack will bundle it as a module, but how can I include it in my app such that the settings file will still be a separated file in the production build that I can edit.
Is there a better format/way to store those settings (so that they can be edited in production without re-building) ?
You can define those settings in an object that can be referenced in the externals configuration in webpack.config.js.
The externals configuration option provides a way of excluding
dependencies from the output bundles. Instead, the created bundle
relies on that dependency to be present in the consumer's environment.
Example:
externals: {
appSettings: "appSettings",
"window.appSettings": "appSettings"
}
Where appSettings is a global variable containing the environment variables you want to manipulate.
Alternatively, if you do not like that method that exposes the settings in the global object, you can do the following:
Export a variable with the default settings, which will be included in webpack bundle.
export var appSettings = {
currentSettings: "",
settings: {},
getString: function(strName) {
var sett = this.currentSettings ?
this.settings[this.currentSettings] :
appDefaultStrings;
if (!sett || !sett[strName]) sett = appDefaultStrings;
return sett[strName];
},
getSettings: function() { //Gets all available settings
var res = [];
res.push("");
for (var key in this.settings) {
res.push(key);
}
res.sort();
return res;
}
};
export var appDefaultStrings = {
apiURL: "//localhost/app/server/API"
//...
}
appSettings.settings["default"] = appDefaultStrings;
You can then require or import this variable and use it like so:
import appSettings from "../path/to/appSettings";
appSettings.getString("apiURL"); //"//localhost/app/server/API"
Now that you have your default settings up and running, we will create another file containing the custom settings.
import appSettings from "../path/to/appSettings";
export var appProductionSettings = {
apiUrl: "http://example.com"
//...
}
appSettings.settings["production"] = appProductionSettings;
The last thing you need to do is handle which settings you want to use. I have not used vue.js yet, but hopefully this will lead you in the right direction:
import appSettings from "../path/to/appSettings";
export class MyApp {
constructor() {
this.settingsValue = "";
}
get settings() {
return this.settingsValue;
}
set settings(value) {
this.settingsValue = value;
appSettings.currentSettings = value;
}
}
Change the settings:
import "../path/to/productionSettings";
var app = new MyApp();
app.settings = "production";
With this method you can create and use as many settings files as you want.