Symfony Encore multiple asset manifests - symfony

I have a question regarding Encore in Symfony 3.4 and asset versioning.
In my webpack.config.jsI have two configurations.
First is for JS files, the other one for compiling .less.
Each configuration is reset by Encore.reset()
Output bundles are generating manifest with versioning via .enableVersioning, so I have two manifest.json in
web/js/manifest.json
web/stylesheets/manifest.json
According to docs, to have my assets loaded via manifest I need to declare it in config.yml
assets:
base_path: "%myapp.http.site_assets_suffix%"
stylesheets:
json_manifest_path: "%kernel.project_dir%/web/assets/stylesheets/manifest.json"
If I want to link to style.css generated by webpack, I use
asset("stylesheets/style.css")
But in my application I have two manifests and I think this can't be changed due to two Encore configurations.
I've tried adding something in likes of
packages:
stylesheets:
json_manifest_path: "%kernel.project_dir%/web/assets/stylesheets/manifest.json"
js:
json_manifest_path: "%kernel.project_dir%/web/assets/js/manifest.json"
because I saw that somewhere, but unfortunately this won't work at all.
I've thought about combining two manifests into one in last webpack entry point, but this can be time consuming.
Is there any other solution than combining manfiests or combining js + less compilation into one big Encore task?

I've found a solution
assets:
base_path: 'path%'
packages:
noversion:
version: false
version_format: "%%1$s"
base_path: "path%"
stylesheets:
json_manifest_path: "%kernel.project_dir%/web/assets/stylesheets/manifest.json"
js:
json_manifest_path: "%kernel.project_dir%/web/assets/js/manifest.json"
admin:
json_manifest_path: "%kernel.project_dir%/web/assets/js/admin/manifest.json"
And then in .twig files, you need to call it as
<script src="{{ asset('assets/DIRNAME/WEBPACK_ENTRY_NAME_HERE', ASSET_PACKAGE_NAME_HERE) }}"></script>
In my case
<script src="{{ asset('assets/js/backend.js', 'js') }}"></script>
Where WEBPACK_ENTRY_NAME is the name of the Webpack/Encore bundle from webpack.config.js, in my case
.setOutputPath('./web/assets/js')
.setPublicPath('/assets/js')
.addEntry('backend',
Sorry for delayed answer, but I forgot about it.

Webpack Encore use webpack-manifest-plugin to generate manifest.json file.
According to the doc, you can specify an options.seed when you setup your config.
A cache of key/value pairs to used to seed the manifest. This may include a set of custom key/value pairs to include in your manifest, or may be used to combine manifests across compilations in multi-compiler mode. To combine manifests, pass a shared seed object to each compiler's ManifestPlugin instance.
Encore.configureManifestPlugin(options => {
let seed;
try {
// require your existing manifest content if exists
seed = require(path.join(outputPath, 'manifest.json'));
}
catch (e) {
// fallback if manifest.json is missing
seed = {};
}
// inject your latest config as seed.
// The plugin will update it and rewrite manifest.json with correct values (overwrite existing keys, append news)
options.seed = seed;
// Also i add a trick to avoid "License.txt" entries
options.generate = function(seed, files, entrypoints) {
// trick to avoid generate useless versionned entries like License
const filesWithoutLicense = files.filter(file => {
return file.path.match(/.*LICENSE.*/) === null;
});
const newManifestContent = filesWithoutLicense.reduce(
(newManifestContent, file) => {
newManifestContent[file.name] = file.path;
return newManifestContent;
},
seed
);
return newManifestContent;
}

Related

trouble using next-transpile-modules in #nrwl/nextjs monorepo

My understanding is that I fall into Group 1 as those who are;
running a [nextjs] monorepo and therefore they want to be able to import their other packages from node_modules.
And running into an error similar to this:
../../node_modules/#waweb/base-ui.theme.brand-definition/dist/brand-definition.module.scss
CSS Modules cannot be imported from within node_modules. Read more:
https://nextjs.org/docs/messages/css-modules-npm Location:
../../node_modules/#waweb/base-ui.theme.brand-definition/dist/index.js
The official solution is next-transpile-modules, but as soon as I add any packages to the list of modules, I start getting errors in CSS modules in local source.
../../libs/ui/src/lib/contact.module.css
CSS Modules cannot be imported from within node_modules.
Read more: https://nextjs.org/docs/messages/css-modules-npm
Location: ../../libs/ui/src/lib/learn-more.tsx
Import trace for requested module:
../../libs/ui/src/lib/learn-more.tsx
../../libs/ui/src/lib/home.tsx
./pages/index.tsx
This is repeated for all components that were previously working.
I have prepared a branch in a public repo that has a full ci/cd and gitpod dev env configured that demonstrates the critical change.
Let's assume the sources to the components I am attempting to transpile are located in the correct node_modules dir, and I am using the following next config:
// eslint-disable-next-line #typescript-eslint/no-var-requires
const withNx = require('#nrwl/next/plugins/with-nx');
const withPlugins = require('next-compose-plugins');
const withTM = require('next-transpile-modules')(
[
'#waweb/base-ui.theme.colors',
'#waweb/base-ui.theme.color-definition',
'#waweb/base-ui.theme.size-definition',
'#waweb/base-ui.theme.shadow-definition',
'#waweb/base-ui.theme.brand-definition',
'#waweb/base-ui.theme.theme-provider',
],
{ debug: true }
);
const withPWA = require('next-pwa');
/**
* #type {import('#nrwl/next/plugins/with-nx').WithNxOptions}
**/
const nextConfig = {
nx: {
// Set this to true if you would like to to use SVGR
// See: https://github.com/gregberge/svgr
svgr: true,
},
images: {
domains: [
'www.datocms-assets.com',
'a.storyblok.com',
'images.ctfassets.net',
'images.prismic.io',
'cdn.aglty.io',
'localhost', // For Strapi
],
imageSizes: [24, 64, 300],
},
};
const pwaConfig = {};
const plugins = [[withNx], [withPWA, pwaConfig]];
module.exports = withTM(withPlugins([...plugins], nextConfig));
Any idea what's wrong with my setup here?
Thank you all for any thoughts as to what I'm doing wrong here.
Cheers!
edit
For some additional context, I have tried many different variations, and the one I ended up on (shown above) is what got the module transpilation to actually work, according to the debug statements. Only now do I have the reported errors in modules that are actually source components, not node_modules. The usage of the plugin at all seems to break unrelated functionality.
It looks odd to me that you are wrapping withPuglins inside of withTM...
withTM is a plugin so I would imagine it should be more this format:
module.exports = withPlugins([
withTM
], nextConfig);
This seems to be what's expected when looking at the docs:
https://www.npmjs.com/package/next-transpile-modules
https://www.npmjs.com/package/next-compose-plugins

Stylelint - Ensure class name prefix matches folder name

I am using the "selector-class-pattern" stylelint rule. The pattern I am using is to enforce the ECSS naming standard. The rule looks like this:
"selector-class-pattern": ["^[a-z]([a-z0-9]){1,3}-[A-Z][a-zA-Z0-9]+(_[A-Z][a-zA-Z0-9]+)?(-([a-z0-9-]+)?[a-z0-9])?$", { "resolveNestedSelectors": true }]
An ECSS class name uses 3 parts (module name, component name, element name) and looks something like .mod-Component_Element {} where mod is an abbreviation of the module name.
My SCSS files are kept in component folders, so the folder structure looks like the below, where app is the name of the module.
app
-- component-name
-- component-name.component.js
-- component-name.component.scss
I would like a stylelint rule to ensure that the module and the component part of class names match the folder they are in. So the class names kept in the example component-name.component.scss file would be restricted to .app-ComponentName_ElementName {} where ElementName is optional and can be anything.
I am using Gulp to run stylelint:
gulp.task('css', () => {
let processors = [
// add postcss processors here
];
return gulp.src([
path.join(gconfig.rootDir, 'vars.style.scss'),
path.join(gconfig.rootDir, 'style.scss'),
path.join(gconfig.rootDir, gconfig.rootModule, '**/*.scss'),
])
.pipe(stylelint({
failAfterError: false,
reporters: [ {formatter: 'string', console: true} ]
}))
.pipe(gif( debug, sourcemaps.init() ))
.pipe(cssimport())
.pipe(concat(`${gconfig.projectName}.style.css`))
.pipe(scss().on('error', scss.logError))
.pipe(postcss(processors))
.pipe(gif( debug, sourcemaps.write() ))
.pipe(gulp.dest(path.join(gconfig.outDir, 'css')))
});
I understand I will probably need to write a plugin for this, but wondered if there is already a plugin for something like this out there, or if there are any ways to do it maybe by passing the file name/folder to stylelint from Gulp?
I've not seen anything that does what you're asking out of the box
The closest similar plugins I've seen would be the BEM plugins:
https://github.com/postcss/postcss-bem-linter
https://github.com/davidtheclark/stylelint-selector-bem-pattern
These might work as a base guide on writing some plugins for your ECSS use case

Grunt relative file path globbing

Is it possible to use Globbing partially on a directory in a file path?
I have a grunt-contrib-less task set up, the file path for my task looks something like this:
files: {
"../../application/user/themes/some-theme-5.1.1.5830/css/main.css": "less/base.less",
}
However the version number in the relative path may sometime change, such as:
files: {
"../../application/user/themes/some-theme-5.1.1.5831/css/main.css": "less/base.less",
}
Ideally I'd like to something like this:
files: {
"../../application/user/themes/some-theme-*/css/main.css": "less/base.less",
}
Is there a way of doing this? With the above syntax it stops searching after the asterisk.
One potential solution to achieve this is to utilize grunts --options feature.
When running a grunt task via the command line it is possible to specify an additional options value.
In your scenario you could pass in the version number of the folder name that is going to change. (I.e. In your case the part that you tried to specify using the asterisk character (*) E.g. '5.1.1.5830'
Caveat: For this solution to be of any use it does require knowing what that value, (the version number), of the destination folder is upfront prior to running the task via the command line.
Example Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
themesFolder: {
namePart: '0.0.0.0' // <-- If no option is passed via the CLI this name will be used.
},
less: {
production: {
options: {
// ...
},
files: {
// The destination path below utilizes a grunt template for the part
// of the folder name that will change. E.g. '5.1.1.0'
'../../application/user/themes/some-theme-<%= themesFolder.name %>/css/main.css': 'less/base.less'
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.registerTask('saveFolderNameFromOption', 'Uses the option provided to configure name part.', function(n) {
var themesFolder = grunt.option('themesFolder');
if (themesFolder) {
// Store the option value so it can be referenced in the less task.
grunt.config('themesFolder.namePart', themesFolder);
}
});
grunt.registerTask('processLess', ['saveFolderNameFromOption', 'less:production']);
};
Running the ProcessLess task
Run the task via the command line as follows:
$ grunt processLess --themesFolder=5.1.1.5830
Note: The additional option that is specified. Namely: --themesFolder=5.1.1.5830
When using the above command the .css output will be directed to the following path:
'../../application/user/themes/some-theme-5.1.1.5830/css/main.css': 'less/base.less'
Now, each time you run the task you modify the options accordingly.
Benefits: By providing the version number as an option via the CLI will avoid having to reconfigure your Gruntfile.js each time it is run.

Grunt-complexity on all the files in a directory

I'd like to run Grunt-Complexity on all the files in a directory?
I'd like to get this kind of output.
Is there a way?
My js files are all under a subdirectory called "js".
Here's my gruntfile:
/*global module:false*/
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
// Task configuration.
complexity: {
generic: {
src: ['grunt.js', 'js/*'],
//exclude: ['doNotTest.js'],
options: {
breakOnErrors: false,
jsLintXML: 'report.xml', // create XML JSLint-like report
checkstyleXML: 'checkstyle.xml', // create checkstyle report
pmdXML: 'pmd.xml', // create pmd report
errorsOnly: false, // show only maintainability errors
cyclomatic: [3, 7, 12], // or optionally a single value, like 3
halstead: [8, 13, 20], // or optionally a single value, like 8
maintainability: 100,
hideComplexFunctions: false, // only display maintainability
broadcast: false // broadcast data over event-bus
}
}
}
});
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-complexity');
// Default task.
grunt.registerTask('default', 'complexity');
};
I'm simply calling this by typing
grunt
from the command line.
then if I type this
grunt complexity js/*
I get
Warning: Task "js/AgencyMediaController.js" not found. Use --force to continue.
Aborted due to warnings.
And AgencyMediaController.js is the first file in my js directory. So it's having a look and listing the files, but then it crashes.
Thanx!
example:
for all js file in JS folder:
src: ['js/**/*.js']
for ass .scss files in scss folder:
src: ['scss/**/*.scss']
I suggest for you create a config for your src folder can be easy in future folder changes in future projects:
sample:
var src;
config.src = src = {
sassMain : 'scss/main.scss',
distFolder : 'public/stylesheets/lovelycss.dist.css',
devFolder : 'public/stylesheets/lovelycss.dev.css',
libFolder : 'lib/**/*.js',
sassFolder : 'scss/**/*.scss',
spriteCssFolder : 'scss/helpers/_sprite.scss',
spriteDestImg : 'public/images/sprite/spritesheet.png',
spriteSrc : 'public/images/min/*.{png,jpg,gif}',
imageminCwd : 'public/images/',
imageminDest : 'public/images/min'
};
//grunt Watch ===============================
config.watch = {
scripts: {
files: ["<%= src.libFolder %>", "<%= src.sassFolder %>"]
,tasks: ["dev", "sass:dist"]
//,tasks: ["dev",'sass:dist']
}
}
I hope that helped you.
It's been quite a long while since I asked this question. I just ran into the same issue again and found the answer so here it is:
In the end it turned out to be that one of the files I was trying to analyse was causing the crash. This particular Javascript environment allows for C-like preprocessor directives and the Javascript file had something like this:
var mySettings = {
//#ifdef FOO_CONSTANT
setting : constants.FOO_SETTING
//#endif
//#ifdef BAR_CONSTANT
setting : constants.BAR_SETTING
//#endif
};
I guess the problem is that if this is read as strictly Javascript, the preprocessor directives are just plane comments, and there's a comma missing between the two properties, so Grunt complexity is unable to read this because of a syntax error. Using --force makes no difference BTW.
The annoying part is that this is all the error shows:
$ grunt --force
Running "complexity:generic" (complexity) task
Warning: undefined: Unexpected token, expected , (17570:1) Used --force, continuing.
Done, but with warnings.
So while it does say expected , (175:1) it doesn't say in which of the several Javascript files in this project the problem was found!
Just adding exclude: ['path/to/MyFileWithPreprocessorDirectives.js'] to Gruntfile.js in order to exclude this file from the analysis gets me around the problem.

Grunt specify order of injected files in index.html

I am using a angular-fullstack yeoman generator for one of my projects and if I run grunt build my index.html is overwritten with the injected dependencies that grunt-injector finds. The problem is that I want to specify the loading of some of the modules in a certain order or I just want to ignore a specific folder. How can I do that? Currently some javaScript files are loaded in a wrong order and every time I run grunt build I get an error.
you can use arrays to specify the order, for instance
// Inject application script files into index.html
scriptsVendor: {
options: {
transform: function(filePath) {
filePath = filePath.replace('/app/', '');
return '<script src="' + filePath + '"></script>';
},
starttag: '<!-- injector:js -->',
endtag: '<!-- endinjector -->'
},
files: {
'app/index.html': [
[
'app/lib/js/jquery.js',
'app/lib/js/bootstrap.js',
'app/lib/js/angular.js'
],
[
'app/lib/js/angular-*.js',
'app/lib/js/ui-*.js'
]
}
}
So I load before jquery then bootstrap, angular. In the next block all the angular modules starting with angular- and ui-.
To ignore certain files or folder
!app/lib/js/*.min.js
!app/lib/js/folder_to_ignore/*.js
Even if a bit late I hope it helps :-)
in my case I have several angular modules, with config and run functions, seperated over three files called xyz.module.js, xyz.config.js, xyz.run.js
Gulp searches for all .js files : "**/*.js" and alphabetical order is used when injecting, hence *.module.js is loaded after *.config.js, which delivers errors about lacking xyz module definition.
So the order should be switched. I don't want to use hardcoded arrays, I want to keep using wildcards.
Solution which does it in my case :
https://ww
usage (in gulpfile) :
var angularFilesort = require('gulp-angular-filesort');
gulp.src(['./src/app/**/*.js']).pipe(angularFilesort())
Just to tag on to #felix-at-housecat's answer, I needed to ensure that angular-translate-handler-log.js was rendered after angular-translate.js, but due to alphabetical sorting, it would show up before. To achieve this, I set up the injector as follows:
injector: {
dev: {
files: {
'dist/static/index.html': [
[
'dist/static/js/lib/jquery.js',
'dist/static/js/lib/bootstrap.js',
'dist/static/js/lib/angular.js',
'dist/static/js/lib/angular-*.js',
'dist/static/js/lib/angularjs*.js',
. . .
'!dist/static/js/lib/angular-translate-handler-log.js'
],
[
'dist/static/js/lib/angular-translate-handler-log.js'
]
]
},
. . .
Now, /angular-translate-handler-log.js will be rendered in the file after all of the files in the first array (which includes angular-translate.js).

Resources