How to autoprefix css files generated by less, in Webstorm? - less

I've got Webstorm 7 (on Win7) compiling my .less files into minified css with sourcemaps (using lessc on nodejs v0.10.26, run from a File Watcher in Webstorm), and I can then run autoprefixer on that generated css to automatically insert vendor prefixes.
What I'm not sure how to do, is combine the two steps. Is it possible to chain File Watchers in Webstorm?
Possible approaches:
Create a batch script that is called from the file watcher, then calls less and autoprefixer in sequence.
Create a node.js script/module that calls less, then autoprefixer.
Have the less transpiler output the css with a custom extension (e.g., .unprefixedcss), then have a File Watcher specifically for that extension.
Something I'm missing?

There is a plugin for less which does this job without adding a watcher: https://github.com/less/less-plugin-autoprefix
After installation you can add --autoprefix="…" to your arguments for the output in webstorms file watcher.

yes, it's possible to chain file watchers. The autoprefixer file watcher will listen to css changes and run after less. The first and secong approaches will work too

I tried the batch script approach with a python script, called from a single File Watcher:
#!/usr/bin/env python
"""
less-prefixed.py
Chains less and autoprefixer, to produce a minified, vendor-prefixed css file.
"""
# TODO: move config data to a config file
# TODO: delete the intermediate files generated by less
import argparse
import os
import subprocess
from pprint import pprint as pp
# Config data
node_folder = r'C:/Users/ClementMandragora/AppData/Roaming/npm'
less_script = os.path.join(node_folder, 'lessc.cmd')
autoprefixer_script = os.path.join(node_folder, 'autoprefixer.cmd')
parser = argparse.ArgumentParser()
parser.add_argument("--file-name", help="filename, not including the extension", required=True)
parser.add_argument("--working-dir", help="the directory to do the work in", required=True)
args = parser.parse_args()
print('\nArgs:')
pp(vars(args))
print('')
os.chdir(args.working_dir)
print('CWD: {c}\n'.format(c=os.getcwd() + '\n'))
print('Running less-css...')
# Compile and minify the less file to css.
# Include a sourcemap.
exitcode = subprocess.Popen([
less_script,
'--no-color',
'-x',
'--source-map={n}.css.map'.format(n=args.file_name),
'{n}.less'.format(n=args.file_name), # source
'{n}.min.css'.format(n=args.file_name) # dest
], cwd=args.working_dir).wait()
assert exitcode is 0, 'Nonzero return code from less! Got: {r}'.format(r=exitcode)
print('less compilation completed.\nRunning autoprefixer...')
# Run autoprefixer over the result from lessc.
exitcode = subprocess.Popen([
autoprefixer_script,
'-o',
'{n}.prefixed.min.css'.format(n=args.file_name), # dest
'{n}.min.css'.format(n=args.file_name) # source
], cwd=args.working_dir).wait()
assert exitcode is 0, 'Nonzero return code from autoprefixer! Got: {r}'.format(r=exitcode)
print('autoprefixer completed.\nFinal filename is {n}.prefixed.min.css'.format(n=args.file_name))
It worked, but seemed unwieldy.
Next attempt was having multiple file watchers; it turns out that have autoprefixer watch for changes to css files, then generate another css file, results in a loop.
So I created a custom File Type in Webstorm for files matching *.min.css (the output of the less transpiler), then created a File Watcher for that extension. The other differences from the default/included less File Watcher are:
Program: C:\Users\ClementMandragora\AppData\Roaming\npm\autoprefixer.cmd
Arguments: -o $FileNameWithoutExtension$.prefixed.css $FileName$
Output paths to refresh: $FileNameWithoutExtension$.prefixed.css:$FileNameWithoutExtension$.prefixed.css.map
It wasn't initially clear to me that the 'Output paths to refresh' also signal Webstorm to parent the generated files under the main *.less file, reducing project clutter. (I'm keeping source and output in the same folder.)

Related

Importing Docstrings from Python modules using Sphinx and autodoc [duplicate]

I have faced a problem with Sphinx in Python. Even if I have followed the instructions from https://groups.google.com/forum/#!topic/sphinx-users/lO4CeNJQWjg I was not able to solve it.
I have Docs/source folder which contains:
conf.py
index.rst
RstFiles (the folder which contains .rst files for each module).
In conf.py I specify the abs path in the following way:
sys.path.insert(0, os.path.abspath('..'))
In index.rst I call all the modules from RstFiles folder in the following way:
.. toctree::
:maxdepth: 2
:caption: Contents:
BatchDataContainer.rst
BatchDefaultValues.rst
BatchTypes.rst
And finally, the content of each .rst file is in the following way:
BatchDataContainer
==================
.. automodule:: RstFiles.BatchDataContainer
:members:
When I run sphinx-build I get 2 main errors:
D:\hfTools\Projects\Validation-Source\Docs\source\RstFiles\BatchDataContainer.rst:
WARNING: document isn't included in any toctree
and
WARNING: autodoc: failed to import module 'BatchDataContainer' from
module 'RstFiles'; the following exception was raised: No module named
'RstFiles'
Any ideas what might be wrong cause I have tried different things already and nothing has helped?
If conf.py is located in this directory,
D:\hfTools\Projects\Validation-Source\Docs\source,
and the project's Python modules (including BatchDataContainer.py) are in
D:\hfTools\Projects\Validation-Source\Products,
then you need sys.path.insert(0, os.path.abspath('../..')) in conf.py.
The automodule directive needs to be updated as well:
.. automodule:: Products.BatchDataContainer
:members:

VueJS place multiple .env in folder

Hello I'm using VueJS 2 and I have multiple .env in my project.
My app have .env for each company to select the company configuration (skin color / files...)
Actually I have all my .env in the root folder:
.env.company1-dev
.env.company1-staging
.env.company1-prod
.env.company2-dev
.env.company2-staging
.env.company2-prod
.env.company3-dev
.env.company3-staging
.env.company3-prod
So when I'll get 20 companies it will be confused on my root folder so it is possible to create a folder where I can place all my .env ?
The idea :
/environments/company1/
.env.dev
.env.staging
.env.prod
/environments/company2/
.env.dev
.env.staging
.env.prod
/environments/company3/
.env.dev
.env.staging
.env.prod
On your vue.config.js file you can add:
const dotenv = require("dotenv");
const path = require("path");
let envfile = ".env";
if (process.env.NODE_ENV) {
envfile += "." + process.env.NODE_ENV;
}
const result = dotenv.config({
path: path.resolve(`environments/${process.env.VUE_APP_COMPANY}`, envfile)
});
// optional: check for errors
if (result.error) {
throw result.error;
}
the before run you can set VUE_APP_COMPANY to a company name and run your app,
Note: It's important to put this code on vue.config.js and not in main.js because dotenv will use fs to read files.
References
https://github.com/motdotla/dotenv#path
https://github.com/vuejs/vue-cli/issues/787
https://cli.vuejs.org/guide/mode-and-env.html#environment-variables
The accepted answer we have also used in the past. But I found a better solution to handle different environments. Using the npm package dotenv-flow allows not only the use of different environments but has some more benefits like:
local overwriting of variables by using .env.local or .env.staging.local and so on
definition of defaults using .env.defaults
In combination we have set up our projects with this configuration:
.env
.env.defaults
.env.development
.env.production
.env.staging
.env.test
And the only thing you have to do in your vue.config.js, nuxt.config.js or other entry points is
require('dotenv-flow').config()
Reference: https://www.npmjs.com/package/dotenv-flow
The powershell solution
I was handling exactly the same problem. Accepted solution is kind of ok, but it did not solve all differences between companies. Also, if you are using npm, your scripts can look nasty. So if you have powershell, here is what I suggest - get rid of the .env files :)
You can keep your structure like you want in the question. Just convert the env files to ps1.
/build/company1/
build-dev.ps1
build-stage.ps1
build-prod.ps1
/build/company2/
build-dev.ps1
build-stage.ps1
build-prod.ps1
Inside each of those, you can fully customize all env variables, run build process and apply some advanced post-build logic (like careful auto-deploy, publishing, merging with api project, ..).
So for example company1\build-stage.ps1 can look like this:
# You can pass some arguments to the script
param (
[string]$appName = "company1"
)
# Set environment variables for vue pipeline
$env:VUE_APP_ENVIRONMENT = "company1-stage";
$env:NODE_ENV="development";
$env:VUE_APP_NAME=$appName;
$env:VUE_APP_API_BASE_URL="https://company1.stage.mycompany.com"
# Run the vue pipeline build
vue-cli-service build;
# Any additional logic e.g.
# Copy-Item -Path "./dist" -Destination "my-server/my-app" -Recurse¨
Last part is easy - just call it (manualy or from integration service like TeamCity). Or, you can put it inside package.json.
...
"scripts": {
"build-company1-stage": "#powershell -Command ./build/company1/build-stage.ps1 -appName Company-One",
}
...
The you can call whole build process just by calling
npm run build-company1-stage
Similary, you can create localhost, dev, prod, test and any other environment. Let the javascript handle the part of building the app itself. For other advanced work, use poweshell. I think that this solution gives you much more flexibility for configuration and build process.
P.S.
I know that this way I'm merging configuration and build process, but you can always extract the configuration outside the file if it gets bigger.

Kivy: PyInstaller not including Kivy modules upon compiling spec file

I've been following Creating Packages for Mac OS from Kivy.org in order to try and create a .app for my Kivy .py file.
However, despite following the guide through, my App never works, it crashes instantly upon opening. Pyinstaller's warning's concerning the build were dumped in a .txt that contained the following:
W: no module named kivy.graphics.ClearBuffers (top-level import by kivy.uix.screenmanager)
W: no module named kivy.core.spelling.SpellingBase (top-level import by kivy.core.spelling.spelling_enchant)
W: no module named kivy.core.image.ImageLoader (top-level import by kivy.core.image.img_gif)
W: no module named multiprocessing.RLock (top-level import by multiprocessing.sharedctypes)
and so on . . . (Full file is very long, but can be viewed here)
It seems like no kivy modules at all could be found, so they must have not been included for some reason. This is what I want to ask how to fix.
As of right now, I have been using the commands:
kivy pyinstaller.py myapp.py
kivy pyinstaller.py myapp.spec
respectively to create both the spec file and the App.
The spec file doesn't seem to have anything missing. (I've included the hooks and checked with a working spec file I used to create an .exe in the past)
# -*- mode: python -*-
# -*- coding: utf-8 -*-
from kivy.tools.packaging.pyinstaller_hooks import install_hooks
install_hooks(globals())
a = Analysis(['Meep/Meep.py'],
pathex=['/Users/Owatch/Documents/pyinstaller/Meep'],
hiddenimports=[],
runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='Meep',
debug=False,
strip=None,
upx=True,
console=False , icon='Meep/icon.icns')
coll = COLLECT(exe,Tree('/Users/Owatch/Desktop/examples/demo/touchtracer/'),
a.binaries,
a.zipfiles,
a.datas,
strip=None,
upx=True,
name='Meep')
Anyways, I'm not sure why this is occuring. My suspicions are mostly around the following:
1: I downloaded pyinstaller as a .zip since I could not find the .py file on my system. This is despite having it installed via pip on what I believe to be a separate python installation (I have 2.7 separately)
2: My reference to touchtracer is somehow wrong, it is linked to the touchtracer directory that came bundled in the dmg for Kivy. (A folder named Examples, which I dragged to my desktop)
Other than that, I'm afraid I'm pretty clueless. Thanks for helping (If you can!)
It appears that the error was associated with a flawed spec file. Nothing else to report.

Can't select all .hbs files in subfolders on windows

I want to precompile my ember templates. I installed an application for that, but I can only precompile one file.
I need like to select all files with .hbs extension including subfolders
I tried ember-precompile "components/**/*.hbs" -f precompiledTemplates.js
I get error saying
Error: ENOENT, no such file or directory 'components\**\*.hbs'
How do I say the program to look for .hbs files in all subfolders ?
I figured it's probably not a windows problem, but a limitation of the library I wanted to use(ember-precompile).
Instead I chose to use gulp which works well https://www.npmjs.org/package/gulp-ember-handlebars
Here's my coffeescript gulpfile for precompiling ember templates. After initiating gulp, it compiles my templates, and if one of templates changes, gulp recompiles.
gulp = require("gulp")
concat = require("gulp-concat")
handlebars = require("gulp-ember-handlebars")
gulp.task( "default", ["precompile-ember-templates"], ()->
# default tasks complete
)
gulp.task( "precompile-ember-templates", ()->
console.log("recompiling templates")
gulp.src( ["client/components/**/*.hbs"] )
.pipe( handlebars({outputType: 'browser'}) )
.pipe( concat("templates-compiled.js") )
.pipe( gulp.dest("client/public/") )
)
gulp.watch( "client/components/**/*.hbs", ["precompile-ember-templates"] )
There does seem to be a limitation within the Ember-Precompile code when handling the windows file structure and wildcards.
When running ember-precompile on windows you must do so through a cygwin terminal or similar (in my case I use git bash).
As an example in git bash when I type the line below in my project folder it works for me:
ember-precompile templates/*.handlebars -f templates/templates.js

Program using selenium fails after building with cx_freeze

I'm developing an automatic web tester using Selenium (v2.37.2). Program works properly until I run the test built with cxfreeze (there is also tkinter gui).
there is the init function
def initDriver(self):
if self.browser == FIREFOX:
profile = webdriver.FirefoxProfile(profile_directory=self.profile);
self._driver = webdriver.Firefox(firefox_profile=profile)
elif self.browser == CHROME:
self._driver = webdriver.Chrome(self.executable, chrome_options=profile)
elif self.browser == IEXPLORER:
self._driver = webdriver.Ie(self.executable)
Now when I build it using Cx_freeze I get this error
method redirectToBlank(...) calls initDriver(..) as the first thingSo how I pack the .xpi file to the library.zip file - which option in setup.py I have to use? And do I even have to this?
And the second strange thing is, that the other browsers work fine, when I execute the .exe file in by clicking on its icon, but when I run it from command line, I get errors even for chrome and IE. (Sorry that the traceback isn't complete)
All paths are relative from the executed file (no matter from where you run it),
Thank you for any ideas to solve this problem.
(method redirectToBlank(...) calls initDriver(..) as the first thing)
First issue solved
It's problem with selenium - FirefoxProfile - class, which tries to load webdriver.xpi as a normal file, but selenium pack all libraries to a zip file, so selenium can't find it.
Even forcing cx_freeze in setup file to add webdriver.xpi to a proper directory in zip won't help.
It is necessary to edit FirefoxProfile (in firefox_profile module) class for example like this
def _install_extension(self, addon, unpack=True):
"""
Installs addon from a filepath, url
or directory of addons in the profile.
- path: url, path to .xpi, or directory of addons
- unpack: whether to unpack unless specified otherwise in the install.rdf
"""
if addon == WEBDRIVER_EXT:
# altered lines
import sdi.env
WEBDRIVER_SUBSTITUTE = "path/to/unpacked/webdrive.xpi"
addon = os.path.join(os.path.dirname(__file__), WEBDRIVER_SUBSTITUTE)
# Original lines:
# addon = os.path.join(os.path.dirname(__file__), WEBDRIVER_EXT)
< the rest of the method >
Issue 2
OSError: win error 6: the handle is invalid problem wasn't caused by either cxfreeze or selenium. I run the final exe file from git bash. There's the problem. For some reason git bash doesn't open stdin for the program and that's why it fails. When I run it in standard windows command line, everything is ok or if i run it from git bash like program.exe < empty_file
what i did was remove selenium form packages list.
and put it inside includefiles, then it works.
like this :
includefiles = [(seleniumPackage,'')]
...
options = {'build_exe': {'includes':includes,
'excludes':excludes,
'optimize':2,
'packages':packages,
'include_files':includefiles,
...