Brunch with SugarSS (PostCSS parser) - brunch

How can I start using SugarSS parser with Brunch?
Here is the plugins part of my current config:
exports.config = {
...
plugins: {
babel: {
ignore: [/web\/static\/vendor/]
},
postcss: {
processors: [
require("postcss-cssnext")(["last 3 versions"]),
require("precss"),
require("lost")
]
},
cssnano: {
autoprefixer: {
add: false
}
}
}
...
};
And my package.json:
{
"repository": {},
"dependencies": {
"babel-brunch": "~6.0.0",
"brunch": "~2.1.3",
"css-brunch": "~1.7.0",
"cssnano": "^3.5.2",
"cssnano-brunch": "^1.1.5",
"javascript-brunch": "~1.8.0",
"lost": "^6.7.2",
"phoenix": "file:deps/phoenix",
"phoenix_html": "file:deps/phoenix_html",
"postcss-brunch": "^0.5.0",
"postcss-cssnext": "^2.5.1",
"postcss-scss": "^0.1.7",
"precss": "^1.4.0",
"sugarss": "^0.1.2",
"uglify-js-brunch": "~1.7.0"
}
}

The way PostCSS plugin for brunch works is, it's invoked after all the stylesheets were compiled and concatenated into a single file. (Brunch calls that an optimizer plugin)
Support of SugarSS or similar, however, will require creating of a custom compiler plugin, that will only transform sss into normal css.
It's actually easier than it sounds :) Use plugins.md as a plugin API reference. If it helps, take a look at stylus-brunch — https://github.com/brunch/stylus-brunch/blob/master/index.js.
What you'll basically need to change is:
compile() method, to invoke PostCSS with SugarSS parser and return a promise that resolves to an object with at least the data key (which in your case will be a string css)
change prototype.extension to be the extension you want to handle, sss in this case
you probably won't need stylus' constructor() and might not need the css modules support
you can release it so that other people looking to use SugarSS with Brunch won't have do this themselves. Sharing is caring, right? :)
(If you do go that route, it's customary to name brunch plugins with a suffix, like sugarss-brunch. You can also then include it in our list of plugins https://github.com/brunch/brunch.github.io/blob/master/plugins.json)
Hope this clears things up a bit. If you encounter any issues, feel free to either comment there or open an issue on our GitHub http://github.com/brunch/brunch

Related

Jest and Babel transpilation - SyntaxError: Cannot use import statement outside a module

I struggle to use JEST for some cases where running the tests I get
Test suite failed to run
...node_modules\p-retry\index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import retry from 'retry';
^^^^^^
SyntaxError: Cannot use import statement outside a module
> 1 | import pRetry from 'p-retry';
| ^
2 |
3 | export function Retry(tries: number) {
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
at Object.<anonymous> (src/common/Retry.ts:1:1)
Meanwhile my webpack build works nice with typescript and babel. I tried a lot of stuff (see below to get it working but no success so far - and haven't really been able to understand whats going on. From my pov - though the transpilation stuff is kind of a black area so far for me I tried to enable Jest to use ESModules andprovide code as such as well as tried providing commonJS module code.
So I am looking for alternative options and ways to investigate further. Particularly one thing strikes me as strange:
the Retry.ts file from the error is one of my files which imports the pRetry (a node_module written in ESModule style) which in its code does the import retry from 'retry' (another node-module written in commonJS style)from the very first line of the error.
So what seems to happen to me is that the pRetry is not transformed from it's ESModule Code (the source of pRetry starts with import retry from 'retry';) and just wrapped in some commonJS code instead if I interpret the syntax correctly.
So my next steps would likely be investigate what babel-jest really generates and check what's up there and try to deduct furhter. Does anybody know how to achieve this (especially understand what babel-jest generates) or has another idea?
Things I tried - all failed (sometimes slightly different errors)
using plugins: ["#babel/plugin-transform-runtime"] in babel.config.js
changing target and module in tsconfig.json to es5
introducing below in jest.config.ts transformIgnorePatterns: ["node_modules/?!(p-retry)"]
using the following in jest.config.ts
preset: "ts-jest",
transform: {
'^.+\.(ts|tsx)?$': 'ts-jest',
"^.+\.(js|jsx)$": "babel-jest"}
or alternatively with ts-jest for both or babel-jest for both
migrating from .babelrc file to babel.config.js as suggested by one post
AllowJS : true in tscfonfig.json and transformIgnorePatterns in jest in combination
adding ["#babel/plugin-transform-runtime",{"regenerator": true}] to babel.config
Using
preset: "ts-jest",
testEnvironment: "node",
transform: {"node_modules/p-retry/.+\.(j|t)sx?$": "ts-jest"},
transformIgnorePatterns: ["node_modules/(?!p-retry/.*)"]
in jest.config
using "transform-es2015-modules-commonjs" in babel.config
using #babel/plugin-transform-modules-commonjs in babel.config
Applying the following steps as suggest by https://stackoverflow.com/questions/35756479/does-jest-support-es6-import-export#:~:text=Jest%20will%20enable%20compilation%20from,json%20.&text=If%20you%20don't%20want%20to%20pollute%20your%20project%20with%20
Make sure you don't transform away import statements by setting
transform: {} in config file
Run node#^12.16.0 || >=13.2.0 with --experimental-vm-modules flag
Run your test with jest-environment-node or jest-environment-jsdom-sixteen.
playing with testenvironment like jest-environment-node, node or jsdom in jest.config.ts
jest-config.ts:
const tsconfig = require("./tsconfig.json");
const moduleNameMapper = require("tsconfig-paths-jest")(tsconfig)
export default {
collectCoverage: true,
coverageDirectory: "analysis/coverage",
coveragePathIgnorePatterns: ["/node_modules/"],
collectCoverageFrom: ["src/**/*.{js,jsx,ts}"],
coverageReporters: ["json", "lcov", "text", "clover"],
coverageThreshold: {
global: {
branches: 0,
functions: 0,
lines: 0,
statements: 0
},
},
clearMocks: true,
coverageProvider: "babel",
moduleNameMapper,
roots: ["<rootDir>/src/", "<rootDir>/test/"],
testEnvironment: 'jest-environment-node',
testPathIgnorePatterns: [
"\\\\node_modules\\\\"
],
"transform": {
"^.+\\.(js|ts|jsx)$": "babel-jest"
}
};
babel.config.js:
module.exports = {
presets: ['#babel/preset-typescript',
['#babel/preset-env', {
targets: { node: "current" }
}],
'#babel/preset-flow',
],
plugins: [["#babel/plugin-transform-modules-commonjs"], ["#babel/plugin-proposal-decorators", { "legacy": true }], ["#babel/plugin-proposal-class-properties"]]
}
Extract from package.json
"#babel/core": "^7.16.12",
"#babel/plugin-proposal-decorators": "^7.16.5",
"#babel/plugin-transform-modules-commonjs": "^7.16.8",
"#babel/plugin-transform-runtime": "^7.16.10",
"#babel/preset-env": "^7.14.4",
"#babel/preset-flow": "^7.16.7",
"#babel/preset-typescript": "^7.13.0",
"#babel/runtime": "^7.16.7",
"babel-jest": "^27.4.6",
"babel-plugin-transform-regenerator": "^6.26.0",
"jest": "^27.0.4",
"jest-config": "^27.4.5",
"jest-esm-transformer": "^1.0.0",
"ts-jest": "^27.1.3",
"tsconfig-paths-jest": "^0.0.1",
"core-js": "^3.20.0",
Turns out I was close.
With a change of babel.config.ts by adding esmodules: false it is done :-)
module.exports = {
presets: ['#babel/preset-typescript',
['#babel/preset-env', {
targets: { esmodules: false, node: "current" }
}],
'#babel/preset-flow',
],
plugins: [["#babel/plugin-transform-modules-commonjs"], ["#babel/plugin-proposal-decorators", { "legacy": true }], ["#babel/plugin-proposal-class-properties"]]
}
My solution with "jest": "^28.1.0":
In package.json
under devDependencies add:
"#babel/preset-env": "^7.18.10"
and,
"jest": {
"transform": {
"^.+\\.[t|j]sx?$": "babel-jest"
}
},
In babel.config.json add:
{
"presets": ["#babel/preset-env"]
}
You can let Jest do not ignore transforming p-retry by adding this in your jest. config.js, it works for me.
"transformIgnorePatterns": [
"node_modules/(?!(p-retry)/)",
],
In my case I had to add specific module mappings as detailed here: https://stackoverflow.com/a/65250052/285549
This forces Jest to load the CommonJS version of the module since the tests are running in Node even though the eventual target is the browser.

How to configure .babelrc to support ES6 module imports and async/await?

Desired Behaviour
I am trying to import code from one file into another with:
lib.js
// generate unique id
export const guid = () => {
const s4 = () => {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
// get current date as ISO string
export const currentDateTimeISOString = () => {
var iso_string = new Date().toISOString();
return iso_string;
}
// convert boolean string to boolean
export const stringToBoolean = (val) => {
var a = {
'true': true,
'false': false
};
return a[val];
}
app_es6.js
import { guid, currentDateTimeISOString, stringToBoolean } from './src/js/lib';
Actual Behaviour
After build I get the error:
export const guid = () => {
^^^^^^
SyntaxError: Unexpected token export
What I've Tried
I've googled this error and come across various solutions.
The most up to date approach seems to be:
npm install babel-register babel-preset-env --save-dev
source
I currently have the following babel related dev dependencies in package.json:
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.7.0",
"babel-preset-stage-0": "^6.24.1",
And .babelrc is:
{
"presets": [
[
"env",
{
"targets":
{
"node": "current"
}
}
]
]
}
I recently changed .babelrc to the above in order to handle async/await usage, it used to be:
{
"presets": [
"env",
"stage-0"
]
}
My build script in package.json is:
"build-server-file": "babel app_es6.js --out-file app.js",
I'm concerned about implementing a solution that is outdated or breaks functionality with another part of the codebase (ie, if i revert to my previous version of .babelrc then async/await will throw errors). I've also read that stage-x is depreciated.
Question
What is the most up to date way to import/export modules in ES6 in a Node.js environment whilst still supporting the .babelrc requirements for async/await?
Notice that the SyntaxError is being thrown from within lib.js and not app.js --this is almost certainly the result of that file not being transformed.
The babel command you're using, babel app_es6.js --out-file app.js is processing app_es6.js; however, lib.js is untouched and that's likely why you still see ESM export syntax when require()ing the file.
I set up a minimal gist with updates to what I know about your current setup to make this work the way (I think) you intended: https://gist.github.com/knksmith57/a554defde2d3d7cf64c4f453565352a0
The trick is to process the entire source directory and not just your entrypoint file.
tl;dr:
process the entire source directory, not just the entrypoint
tell preset-env to use cjs (alias for commonjs) as the target module type
enable a plugin to transform async functions to generator functions (in babel 7.x, that's #babel/plugin-transform-async-to-generator)
look at that gist for a complete working example
If you run into trouble backporting my example to babel 6.x, let me know and I can make some time to follow up.
Hope this helps!
which version of node are you using?
you can easily update your node to version >= 10v to use official ES6 features support.
Actually, I had the same problem and I fix it by a babel plugin that name is transform-runtime, and my .babelrc the file became like below:
{
"presets": [
"es2015",
"es2016",
"es2017",
"react",
"env",
"stage-0"
],
"plugins": [
"transform-class-properties",
"transform-object-rest-spread",
[
"transform-runtime",
{
"helpers": true,
"polyfill": true,
"regenerator": true
}
]
],
"env": {
"development": {
"compact": false
}
}
}
For more information about this plugin read this link.
It looks like you're trying to run a node.js "server".
npm install --save-dev #babel/core #babel/cli #babel/preset-env #babel/node #babel/plugin-transform-async-to-generator
Using the #babel/ namespace will upgrade you from babel 6 to babel 7, the current latest version. The plugin does the async transformation
Setup a .babelrc or now with 7, especially if you're using node_modules with their own babel configurations, you can use a babel.config.js like this:
module.exports = {
presets: [ '#babel/preset-env'],
plugins: [
'#babel/plugin-transform-async-to-generator'
]
};
Update your package.json build scripts to something more like this:
"scripts": {
"build": "babel src --out-dir dist",
"start": "node dist/app_es6.js"
}
You want to compile your /lib/ folder into a /dist/ one. This is the most common pattern you'll see in the community.
As you are looking to make an es6 web-app, I would not recommend actually compiling everything to commonjs (cjs), as that will break webpack (via the babel-loader) from performing tree-shaking. It only works when you use import/exports and setting babel to cjs instead of the default ems will make everything require/module.exports.

grunt bowercopy task not found

I can't figure out my configuration problem. When I try to run 'grunt bowercopy', I get this error message:
Warning: Task "bowercopy" not found. Use --force to continue.
If I run 'grunt jshint', jshint works fine.
Here is my package.json:
{
"name": "treblebull",
"version": "0.0.1",
"private": true,
"dependencies": {
"express": "~3.2.6",
"jade": "~0.31.2",
"underscore": "~1.5.2",
"pg": "~2.11.1"
},
"devDependencies": {
"grunt": "~0.4.2",
"grunt-bowercopy": "~0.7.1",
"grunt-contrib-jshint": "~0.8.0",
"load-grunt-tasks": "~0.2.1"
}
}
and here is my gruntfile:
'use strict';
module.exports = function(grunt) {
grunt.initConfig({
jshint: {
options: {
jshintrc: '.jshintrc'
},
gruntfile: {
src: 'Gruntfile.js'
},
lib: {
src: ['lib/**/*.js']
},
test: {
src: ['test/**/*.js']
}
},
bowercopy: {
options: {
clean: true
//srcPrefix: 'bower_components'
},
libs: {
options: {
// destPrefix: 'public/js/lib'
},
files: {
'angular.js': 'angular/angular.js'
//'underscore.js': 'underscore/underscore.js',
//'underscore.string.js': 'underscore.string/underscore.string.js'
}
}
}
});
grunt.loadNpmTasks('grunt-bowercopy');
grunt.loadNpmTasks('grunt-contrib-jshint');
};
Run bower init to give yourself a bower.json file for the bowercopy task to read. Also if you already have installed everything via bower, set runBower to false in your options hash.
If you're ever having Grunt failures, it's worth running with the --v (verbose) flag to see exactly what it's failing on. Running this myself I saw it looking for a bower.json, and once I supplied one the task succeeded.
You're missing task registration, You need to register a task that you want to explicity run in grunt, so you need this
grunt.registerTask('bowercopy', ['bowercopy']);
Then you can run
grunt bowercopy
Since I can't comment on #dcodesmith's answer due to points, I have to leave an answer. I ran into the problem in that actually adding grunt.registerTask('bowercopy', ['bowercopy']);
called bowercopy's task, but it doesn't actually work. Removing it actually allowed bowercopy to copy files.

Zappa Error unable to find view (jade template)

I am trying a zappa node application and am unable to get it working beyond a trivial example.
I have application.coffee
require('zappajs') ->
#set views: "#{__dirname}/views"
#set 'view engine': 'jade'
#use 'bodyParser', 'methodOverride', #app.router, 'static'
#configure
development: => #use errorHandler: {dumpExceptions: on}
production: => #use 'errorHandler'
#get '/': -> #render 'index'
and i am getting an error. Zappa seems to be prepending a guid to the file name.
example/app/views/7b16eeab-de6f-41b0-b196-8f23f4b7237d/index.jade
Here is the complete trace
Error: ENOENT, no such file or directory '/Users/irfn/project/example/app/views/7b16eeab-de6f-41b0-b196-8f23f4b7237d/index.jade'
at Object.fs.openSync (fs.js:338:18)
at Object.fs.readFileSync (fs.js:182:15)
at Object.rethrow (/Users/irfn/project/example/node_modules/jade/lib/runtime.js:155:27)
at parse (/Users/irfn/project/example/node_modules/jade/lib/jade.js:116:13)
at Object.exports.compile (/Users/irfn/project/example/node_modules/jade/lib/jade.js:163:9)
at Function.exports.compile (/Users/irfn/project/example/node_modules/zappajs/node_modules/express/lib/view.js:68:33)
at ServerResponse.res._render (/Users/irfn/project/example/node_modules/zappajs/node_modules/express/lib/view.js:417:18)
at ServerResponse.res.render (/Users/irfn/project/example/node_modules/zappajs/node_modules/express/lib/view.js:318:17)
at Object.zappa.app.app.(anonymous function).apply.concat.render (/Users/irfn/project/example/node_modules/zappajs/lib/zappa.js:593:33)
at Object.zappa.app.app.(anonymous function).apply.concat.ctx.render (/Users/irfn/project/example/node_modules/zappajs/lib/zappa.js:545:31)
Here is how my package json dependencies are setup
"dependencies": {
"coffee-script": "1.3.3",
"underscore": ">= 1.3.3",
"stylus": ">= 0.28.2",
"zappajs": ">= 0.3.10",
"jade": ">= 0.18.0"
},
"devDependencies": {
"watchr": "*",
"mocha": "*",
"chai": "*",
"request": "*"
},
Came across this myself - did not have the time to track down the cause but there is an easy workaround:
instead of
#get / : ->
#render index: {key:value}
use the more old school connect-style
#app.get '/', (req,res) ->
res.render 'index', {key:value}
Hope this helps you get over the hump.
PS:
Come to think of it, I assume it might have something to do with the way zappa evaluates coffee(k/c)up templates by default. In this case it might be trying to apply that logic to jade which breaks.

requirejs no longer loads cdn scripts after optimization

I'm struggling to get requirejs to work after optimizing with r.js
It works fine pre optimization
I'm following the docs for configuring main.js and the build profile using empty:
However after optimization, CDN scripts are no longer loaded.
public/index.html
<script data-main="editor/js/main" src="editor/js/vendor/require.js"></script>
public/editor/js/main.js
requirejs.config({
baseUrl: "/editor/js",
paths: {
"jquery": "http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min",
"order": "vendor/require_order",
"underscore": "vendor/underscore",
"handlebars": "vendor/handlebars-1.0.0.beta.4",
"jquery.mobile.router": "vendor/jquery.mobile.router",
"jquery.mobile": "http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min"
}
});
require(["order!jquery", "order!underscore", "order!handlebars", "order!jam", "order!jquery.mobile"], function () {
//loaded
});
config/build.js
({
baseUrl: "../public/editor/js",
name: "main",
out: "../public/editor/js/main-built.js",
paths: {
"order": "vendor/require_order",
"underscore": "vendor/underscore",
"handlebars": "vendor/handlebars-1.0.0.beta.4",
"jquery.mobile.router": "vendor/jquery.mobile.router",
"jquery": "empty:",
"jquery.mobile": "empty:"
}
})
When I run r.js node config/r.js -o config/build.js
main-built.js is built successfully.
Is there a particular reason why you are loading everything using the order plugin?
Were you having load order problems in your built javascript?
If you load jQuery mobile normally (without the plugin) your "empty" configuration should take effect.
require(["jquery", "underscore", "handlebars", "jam", "jquery.mobile"], function () {
http://requirejs.org/docs/optimization.html#empty
You will also need to define the dependency chain for jQuery.mobile.router
requirejs.config({
paths: {
"jquery": "http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min",
"order": "vendor/require_order",
"underscore": "vendor/underscore",
"handlebars": "vendor/handlebars-1.0.0.beta.4",
"jquery.mobile.router": "vendor/jquery.mobile.router",
"jquery.mobile": "http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min"
},
shim: {
"router": {
"deps" : ["jquery.mobile"]
},
"jquery.mobile" : {
"deps" : [ "jquery.mobile.router"],
"exports": "$.mobile"
},
"jquery.mobile.router": {
"exports": "$.mobile.Router"
}
}
});
see the answer to this question:
Require.js with jQueryMobile-Router
I hope that resolves your issues with requirejs, I've found it to be a very powerful and useful tool, once you get used to its structure.
_Pez

Resources