How to generate single css and multiple chunks of the same css in Webpack 4? - webpack-4

I want to generate CSS like this:
In normal chunks used by my web application.
main.css 1.chunk.css 2.chunk.css .... etc
And a single file
server.css
Because I use server.css in backend
I tried to use this https://webpack.js.org/plugins/mini-css-extract-plugin/#extracting-all-css-in-a-single-file but always get one css emitted.

Finally I use a script in node to merge the css and not change the default configuration in webpack. And also use npm-run-all to integrate the script in build process in package.json
const fs = require('fs');
fs.readdir('build/static/css', function (err,files){
if(err){
console.log(err)
}
files
.filter((file) => {
return file.match(/.*\.css$/)
})
.sort((a, b) => {
if (a.startsWith("main") || b.startsWith("main")) {
return -1;
} else {
return a.localeCompare(b);
}
})
.map(file => {
const data = fs.readFileSync(`build/static/css/${file}`, 'utf8');
fs.appendFileSync('build/static/css/server.css', data+'\n')
});
})

Related

Updating admin/staticfiles with Django

I am having trouble with updating the css, img, fonts, and js admin files when I upgrade Django. I first noticed this when I upgraded to Django 2.0 (see here), and now the problem is worsening as I upgrade to 4.0.
The backend functionality is working perfectly well. But now when I access the admin console, the homepage remains on the top of the browser page, even when I navigate to different models.
I noticed that none of the /static/admin/ files (css, js, img, fonts) were updated on my local machine when upgrading from Django 2.2.24 to 4.0. Should I have expected these files to update along with Django? Am I missing a step to ensure that the admin static files are updated to reflect the newest version of Django?
Attempted Fixes
I have run collectstatic, but it looks like that is simply copying my local static/admin files to AWS S3, where I normally store static files. Should I not have static/admin files on my local machine?
I copied the static/admin files from Django.contrib cp -a /Users/username/.virtualenvs/rs/lib/python3.9/site-packages/django/contrib/admin/. /Users/username/Documents/myproject/static/. This actually worked, but seems a bit hacky. I must not be doing something right for these files to not update upon Django upgrade.
I should note that I am using gulp.js. Could this be a problem when I run collectstatic? Here is my gulpfile:
const gulp = require('gulp');
const util = require('gulp-util');
const plumber = require('gulp-plumber');
const tap = require('gulp-tap');
const del = require('del');
const sass = require('gulp-sass');
const cssnano = require('gulp-cssnano');
const autoprefixr = require('gulp-autoprefixer');
const buffer = require('vinyl-buffer');
const uglify = require('gulp-uglify');
const babelify = require('babelify');
const browserify = require('browserify');
const concat = require('gulp-concat');
const runSequence = require('run-sequence');
const gulpif = require('gulp-if');
gulp.task('clean', function () {
return del([
'static/img/**/*',
'static/css/**/*',
'static/js/**/*'
]);
});
gulp.task('sass', function () {
const config = {
src: ['./assets/styles/myproject.scss', './assets/styles/myproject-dashboard.scss'],
dest: './static/css',
sass: {
includePaths: [
'node_modules/bootstrap-sass/assets/stylesheets'
]
},
autoprefixr: {
browsers: ['last 4 versions'],
cascade: false
}
};
return gulp.src(config.src)
.pipe(plumber())
.pipe(sass(config.sass))
.pipe(autoprefixr(config.autoprefixr))
.pipe(gulpif(util.env.production, cssnano()))
.pipe(plumber.stop())
.pipe(gulp.dest(config.dest));
});
gulp.task('images', function () {
return gulp.src('./assets/images/**/*')
.pipe(gulp.dest('./static/img'));
});
gulp.task('vendor-scripts', function () {
const config = {
src: [
'./node_modules/jquery/dist/jquery.min.js',
'./node_modules/bootstrap-sass/assets/javascripts/bootstrap.min.js',
'./node_modules/responsive-toolkit/dist/bootstrap-toolkit.min.js',
'./node_modules/jquery-circle-progress/dist/circle-progress.min.js',
],
dest: './static/js/vendor'
};
return gulp.src(config.src)
// .pipe(concat('vendor.js'))
.pipe(gulp.dest(config.dest));
});
gulp.task('scripts', function () {
const config = {
src: './assets/scripts/**/*.js',
dest: './static/js/'
};
return gulp.src(config.src, { read: false }) // no need of reading file because browserify does.
.pipe(plumber())
// transform file objects using gulp-tap plugin
.pipe(tap(function (file) {
// replace file contents with browserify's bundle stream
file.contents = browserify({
entries: file.path,
transform: [babelify],
paths: [
'./node_modules/'
]
}).bundle();
}))
// transform streaming contents into buffer contents
.pipe(buffer())
.pipe(gulpif(util.env.production, uglify()))
.pipe(plumber.stop())
.pipe(gulp.dest(config.dest));
});
gulp.task('build', ['sass', 'vendor-scripts', 'scripts', 'images']);
gulp.task('default', ['watch']);
gulp.task('watch', ['sass', 'vendor-scripts', 'scripts', 'images'], function () {
gulp.watch('./assets/styles/**/*.scss', ['sass']);
gulp.watch('./assets/images/**/*', ['images']);
gulp.watch('./assets/scripts/**/*.js', ['scripts']);
});

How to use CodeceptJS to unit-test a JS function

I've set up CodeceptJS for a project and use it to test various end-to-end scenarios.
Now I want to extend the tests-suite to also run unit-tests to verify functionality of custom JS functions.
For example: I have a global object App that has a version attribute. As a first test, I want to confirm that App.version is present and has a value.
My first attempt is a test.js file with the following code:
Feature('Unit Tests');
Scenario('Test App presence', ({ I }) => {
I.amOnPage('/');
I.executeScript(function() {return App.version})
.then(function(value) { I.say(value) } );
});
Problems with this code
The major issue: How can I assert that the App.version is present?
My script can display the value but does not fail if it's missing
My code is very complex for such a simple test.
I'm sure there's a cleaner/faster way to perform that test, right?
Here is a solution that works for me:
Read data from the browser:
I created a custom helper via npx codecept gh and named it BrowserAccess.
The helper function getBrowserData uses this.helpers['Puppeteer'].page.evaluate() to run and return custom code from the browser scope. Documentation for .evaluate()
Custom assertions:
Install the codeceptjs-assert package, e.g. npm i codeceptjs-assert
Add the AssertWrapper-helper to the codecept-config file. This enables checks like I.assert(a, b)
Full Code
codecept.conf.js
exports.config = {
helpers: {
AssertWrapper: {
require: "codeceptjs-assert"
},
BrowserAccess: {
require: './browseraccess_helper.js'
},
...
},
...
}
browseraccess_helper.js
const Helper = require('#codeceptjs/helper');
class BrowserAccess extends Helper {
async getBrowserData(symbolName) {
const currentPage = this.helpers['Puppeteer'].page;
let res;
try {
res = await currentPage.evaluate((evalVar) => {
let res;
try {
res = eval(evalVar);
} catch (e) {
}
return Promise.resolve(res);
}, symbolName);
} catch (err) {
res = null;
}
return res;
}
}
jsapp_test.js (the test is now async)
Feature('Unit Tests');
Scenario('Test App presence', async ({ I }) => {
I.amOnPage('/');
const version = await I.getBrowserData('App.version');
I.assertOk(version);
});

Append new test results to an existing newman report

I am using the following code snippet to run all collections in a folder using POSTMAN's npm module:
#!/usr/bin/env node
/**
* #fileOverview Read all collection files within a directory and run them
* in parallel.
*/
var newman = require('../'), // require('newman')
fs = require('fs');
fs.readdir('./examples', function (err, files) {
if (err) { throw err; }
//Filter all files with JSON file extension
files = files.filter(function (file) {
return (/^((?!(package(-lock)?))|.+)\.json/).test(file);
});
//Iterate on each file name and call newman.run using each file name
files.forEach(function (file) {
newman.run({
collection: require(`${__dirname}/${file}`)
}, function (err) {
// finally, when the collection executes, print the status
console.info(`${file}: ${err ? err.name : 'ok'}!`);
});
});
});
If I try using
{
collection: require(`${__dirname}/${file}`),
reporters: 'html',
reporter: { html: { export: './result/htmlResults.html', template: './templates/htmlTemplate.hbs' } }
}
instead of
{
collection: require(`${__dirname}/${file}`)
}
Every new collection run by newman.run will overwrite the report file htmlResults.html. I am looking for a way to append test data from new collections to the existing report. Is there a way to achieve this?
Note: I do not wish to create multiple report files(individual reports for each collection)

Modify how ember-i18n localizations are loaded, split localization strings from main app.js

I am trying to modify the way ember-i18n localizations are loaded. What I want to do is have the localizations in a separate file from the main app javascript file.
Ideally, the structure would remain the same as now. So I would have app/locales/fr/translations.js and app/locales/de/translations.js , each having content similar to this:
export default {
key: "value"
}
So I thought I need to write a custom addon, which would alter the build process. This addon would need to:
Ignore app/locales from final build
Compile all the translation files into one
Transpile the new file with babel
Copy the file in dist/assets/translations.js
The combined translation file would look something like this:
export default {
fr: {
key: "value"
},
de: {
key: "value"
}
This way, I would be able to use and instance initializer and simply import and use this module:
import Translations from 'my-translations';
export function initialize(instance) {
const i18n = instance.lookup('service:i18n');
for(let lang in Translations) {
if(Translations.hasOwnProperty(tag)) {
i18n.addTranslations(tag, Translations[tag]);
}
}
}
Also, index.html would be:
<script src="assets/vendor.js"></script>
<script src="assets/translations.js"></script>
<script src="assets/my-app.js"></script>
Well, I started writing the custom addon, but I got stuck. I managed to ignore the locales, and I wrote code that parses all the localizations, but I do not know how to write the new translations file in dist. What hook do I neeed to use, to be able to write into dist? Any help? Thank you so much.
Here is the code I wrote:
Stuff I use
var Funnel = require('broccoli-funnel');
var stew = require('broccoli-stew');
var fs = require('fs');
var writeFile = require('broccoli-file-creator');
var mergeTrees = require('broccoli-merge-trees');
preprocessTree: function(type, tree) {
if(type !== 'js') {return tree;}
var treeWithoutLocales = new Funnel(tree, {
exclude: ['**/locales/*/translations.js']
});
var translations = {};
var files = fs.readdirSync('app/locales');
files.forEach((tag) => {
if(tag !== 'fr') {return;}
let contents = fs.readFileSync('app/locales/' + tag + '/translations.js', 'utf8');
contents = contents.replace(/^export default /, '');
contents = contents.replace(/;$/, '');
contents = JSON.parse(contents);
translations[tag] = contents;
});
// Should do something with this .. how to write in dist? and when? I need it compiled with babel
var fileTree = writeFile('/my-app/locales/translations.js', 'export default ' + JSON.stringify(translations) + ';');
return treeWithoutLocales;
}
I am not sure if you actually asked a question; but here goes some kind of answer.
Why complicate? Just use James Rosen's i18n addon used by a lot of projects.

Extend all views with custom data and filters in Sails.js

I'm developing a Sails.js application and I want to extend all views with custom data and functions.
What would be the best course of action to do so?
I've tried to create a policy to do so, but policies are only applied to routes with controllers.
Custom data
You can use a custom hook in order to achieve that.
Create a file at the specified path: api/hooks/viewsGlobals/index.js with the following content:
module.exports = function viewsGlobals (sails) {
return {
routes: {
before: {
// This middleware will be executed for every request.
'*': function (req, res, next) {
// Using condition to filter out static file requests.
if (req.accepted.some(function (type) {
return type.value === 'text/html';
})) {
res.locals.someData = {
// Place your custom data here.
};
}
return next();
}
}
}
}
};
Custom filters
Create a file at the following path: config/view-filters/toUpper.js and the following content:
// Replace this with templating engine that you use.
var swig = require('swig');
// Use the API of your templating engine to add custom filter.
swig.setFilter('toUpper', function (value) {
return value.toUpperCase();
});