how to handle output files in parcel - parceljs

I have a project with this structure:
src
|- index.pug
| - layout
| |- index.less
| - scripts
| |- index.js
For now, when I run parcel build src/index.pug, all the files are bundled and I've got this on the distribution folder:
dist
|- index.html
|- index.12345.css
|- index.12345.js
When I was expected something like:
ist
|- index.html
|- layout
| |- index.12345.css
|- scripts
| |- index.12345.js
So, my question is: Can I specify the output path for my CSS, js, and images using ParcelJS?

Unfortunately, this isn't supported out-of-the box by parcel. Parcel v1 you can use this plugin. For parcel v2, it is possible to write a namer plugin that accomplishes this.
Here's the code (in typescript):
import { Namer } from "#parcel/plugin";
import type { Bundle } from "#parcel/types";
import path from "path";
export default new Namer({
name({ bundle }) {
switch (bundle.type) {
case "js":
return getPathWithFolder("scripts", bundle);
case "less":
return getPathWithFolder("layout", bundle);
case "css":
return getPathWithFolder("layout", bundle);
default:
return null;
}
},
});
function getPathWithFolder(folderName: string, bundle: Bundle): string | null {
const filePath = bundle.getMainEntry()?.filePath;
if (!filePath) return null;
let nameWithoutExtension = path.basename(filePath, path.extname(filePath));
if (!bundle.needsStableName) {
// See: https://parceljs.org/plugin-system/namer/#content-hashing
nameWithoutExtension += "." + bundle.hashReference;
}
return `${folderName}/${nameWithoutExtension}.${bundle.type}`;
}
Then, supposing the above code was published in a package called parcel-namer-folders, you would add it to your parcel pipeline with this .parcelrc:
{
"extends": "#parcel/config-default",
"namers": ["parcel-namer-folders", "..."]
}
Here is an example repo where this is working.

Related

Babel Not working for imports from node_modules

I just discovered RollUP and I am stuck with an issue where Babel does not run for imports from node_modules.
Here is an example:
My Javascript Code
import { _map } from "#varunsridharan/js-vars"
const myarray = _map.call([1,2,3,4],(x)=> x * 2);
console.log(myarray);
Rollup Config
import { babel } from '#rollup/plugin-babel';
import { nodeResolve } from '#rollup/plugin-node-resolve';
import { uglify } from 'rollup-plugin-uglify';
import filesize from 'rollup-plugin-filesize';
import visualizer from 'rollup-plugin-visualizer';
export default {
input: './src/index.js',
output: {
file: './dist/myfile.min.js',
format: 'iife',
plugins: [
uglify( { mangle: true } ),
]
},
plugins: [
nodeResolve(),
babel(),
filesize(),
visualizer()
]
};
When I run rollup -c in CLI I get this output:
babelHelpers: 'bundled' option was used by default. It is recommended to configure this option explicitly, read more here: https://github.com/rollup/plugins/tree/master/packages/babel#babelhelpers
198 | * Array Related Vars.
199 | */
> 200 | const Arr = Array;
| ^ Unexpected token: keyword «const»
201 | const _Arrayprop = Arr.prototype;
202 | const _filter = _Arrayprop.filter;
203 | const _push = _Arrayprop.push;
[!] (plugin uglify) Error: Unexpected token: keyword «const»
SyntaxError: Unexpected token: keyword «const»
at JS_Parse_Error.get (eval at <anonymous> (E:\localhost\www\javascript\dizzle\node_modules\uglify-js\tools\node.js:18:1), <anonymous>:69:23)
at reportError (E:\localhost\www\javascript\dizzle\node_modules\jest-worker\build\workers\processChild.js:107:11)
at reportClientError (E:\localhost\www\javascript\dizzle\node_modules\jest-worker\build\workers\processChild.js:87:10)
at execFunction (E:\localhost\www\javascript\dizzle\node_modules\jest-worker\build\workers\processChild.js:157:5)
at execHelper (E:\localhost\www\javascript\dizzle\node_modules\jest-worker\build\workers\processChild.js:139:5)
at execMethod (E:\localhost\www\javascript\dizzle\node_modules\jest-worker\build\workers\processChild.js:143:5)
at process.<anonymous> (E:\localhost\www\javascript\dizzle\node_modules\jest-worker\build\workers\processChild.js:64:7)
at process.emit (events.js:315:20)
at emit (internal/child_process.js:876:12)
at processTicksAndRejections (internal/process/task_queues.js:85:21)
Based on the output i was able to understand that babel did not run for the imported modules. so i checking the options provided for rollup babel plugin # (https://github.com/rollup/plugins/tree/master/packages/babel) and found that it has include AND exclude options and i tried with the below config
babel( {
include: [ "node_modules/#varunsridharan/*/**", "./src/**" ],
exclude: "node_modules/**",
} ),
Still, nothing happened so I tried without ./src/** in babel include config and found that babel is not running in my main javascript file which imports the node_modules's file
Node Module Project Link: https://github.com/varunsridharan/js-vars

babel enable import of each dir from root without relative

My root dir structure is like so:
src
utils
types
clients
package.json
etc.
my current babel config i run is like:
{
presets: ['#babel/preset-env', '#babel/preset-typescript', '#babel/preset-react', '#babel/preset-flow'],
plugins: ['#babel/plugin-syntax-dynamic-import', '#babel/transform-runtime'],
env: {
build: {
ignore: ['**/*.spec.tsx', '**/*.spec.ts', '**/*.stories.tsx']
}
},
ignore: ['node_modules']
}
How do I allow various /src files directly imports from root. eg.
import { handyFunction } from 'utils'
import { api } from 'clients'
as opposed to doing this relatively:
import { handyFunction } from '../../../utils'
import { api } from '../../../clients'
You can use babel plugin module resolver as mentioned here https://www.npmjs.com/package/babel-plugin-module-resolver.

AngularDart: How to configure routerProviders / routerProvidersHash for development and production environments?

There is one SO question about same problem. But I can't find production-ready code example how to use routerProviders / routerProvidersHash in real application.
As I understand we need to define two injectors and use one of them depending on compile time environment variable, like shown below.
// File: web/main.dart
// >>> Have to use 2 injectors:
#GenerateInjector([
routerProvidersHash,
ClassProvider(Client, useClass: BrowserClient),
])
final InjectorFactory injectorDev = self.injectorDev$Injector;
#GenerateInjector([
routerProviders,
ClassProvider(Client, useClass: BrowserClient),
])
final InjectorFactory injectorProd = self.injectorProd$Injector;
// <<<
void main() {
final env = ServerEnvironment();
if (env.isProduction) {
runApp(ng.AppComponentNgFactory, createInjector: injectorProd);
} else {
runApp(ng.AppComponentNgFactory, createInjector: injectorDev);
}
}
// File: lib/server_environment.dart
enum ServerEnvironmentId { development, production }
class ServerEnvironment {
ServerEnvironmentId id;
static final ServerEnvironment _instance = ServerEnvironment._internal();
factory ServerEnvironment() => _instance;
ServerEnvironment._internal() {
const compileTimeEnvironment = String.fromEnvironment('MC_ENVIRONMENT', defaultValue: 'development');
if (compileTimeEnvironment != 'development') {
id = ServerEnvironmentId.production;
} else {
id = ServerEnvironmentId.development;
}
}
bool get isProduction {
return id == ServerEnvironmentId.production;
}
}
File: build.production.yaml
targets:
$default:
builders:
build_web_compilers|entrypoint:
generate_for:
- web/main.dart
options:
compiler: dart2js
# List any dart2js specific args here, or omit it.
dart2js_args:
- -DMC_ENVIRONMENT=production
- --fast-startup
- --minify
- --trust-primitives
# Build execution
pub run build_runner build --config production --release -o web:build
Is the assumption of having two injectors is the right way to do?
Thank you in advance!
What I would do is make a different main.dart file for your different injector setup. You shouldn't have too much stuff in main.dart it should just serve as a mechanism to start your app. The branching should occur in build.production.yaml as specifying a different main for production (i.e. web/main_production.dart) and this file is the one with the non-hash route provider. This would remove the need for a "ServerEnvironment" and a if/else with a potentially confusing double injector setup in one file.
// File: web/main.dart
#GenerateInjector([
routerProvidersHash,
ClassProvider(Client, useClass: BrowserClient),
])
final InjectorFactory injector = self.injector$Injector;
void main() {
runApp(ng.AppComponentNgFactory, createInjector: injector);
}
and
// File: web/main_production.dart
#GenerateInjector([
routerProviders,
ClassProvider(Client, useClass: BrowserClient),
])
final InjectorFactory injector = self.injector$Injector;
void main() {
runApp(ng.AppComponentNgFactory, createInjector: injector);
}
with
File: build.production.yaml
targets:
$default:
builders:
build_web_compilers|entrypoint:
generate_for:
- web/main_production.dart
options:
compiler: dart2js
# List any dart2js specific args here, or omit it.
dart2js_args:
- --fast-startup
- --minify
- --trust-primitives
Ran as
# Build execution
pub run build_runner build --config production --release -o web:build

Qbs: Can Module install files?

I want to have a module which will export all needed dependencies like include path, library path and will install needed runtime libraries.
Module {
Depends { name: "cpp" }
property path libLocation: ""
cpp.dynamicLibraries: [
"mylib"
]
cpp.staticLibraries: [
"mylib"
]
cpp.includePaths: [
libLocation + "include/",
]
cpp.libraryPaths: [
libLocation + "lib/",
]
Group {
name: "runtime libraries"
qbs.install: true
prefix: 'lib_location/'
files: ["*.dll"]
}
}
Everything works, but files are not installed. Is it possible to do that?
Update 1:
Files are correctly installed:
if full or relative paths are specified directly(as literals)
by using Project's properties.
Working solution:
Module {
...
Group {
name: "runtime libraries"
prefix: "D:/Projects/MyProject/Dependencies/SDL2pp/mingw/bin/" // works!
//prefix: project.dependenciesPath + "SDL2pp/mingw/bin/" // also works!
files: "*.dll"
qbs.install: true
}
}
But when I'm trying to use Module's property it says: "Reference Error: Can't find variable: ..."
Module {
...
property bool installDlls: true
property string libPath: ""
Group {
name: "runtime libraries"
prefix: libPath // Can't find variable
files: "*.dll"
qbs.install: installDlls // Can't find variable
}
}
Also, It is not work if FileInfo module is used for building a path. Outside the Group path was corectly resolved.
import qbs
import qbs.FileInfo
Module {
...
Group {
name: "runtime libraries"
prefix: FileInfo.joinPaths(project.dependenciesPaths, './SDL2pp/mingw/bin/') // silently not works
files: "*.dll"
qbs.install: true
}
}
Conclusion
I've found 2 solutuins of it:
hadrcoded path as a literal. Unportable solution
using Project's property. Portable, but depends on Project item.
I don't know why Module's properties can't be used inside a Group. Are there some limitations or it's a bug?
Late but found this post trying to do the same, maybe it helps other people.
Found out that using a Module's property inside a Group can be done by giving the Module an id and referencing the property using the id like this
Module {
id: mymodule
...
property bool installDlls: true
property string libPath: ""
Group {
name: "runtime libraries"
prefix: mymodule.libPath
files: "*.dll"
qbs.install: mymodule.installDlls
}
}
I'm using Qbs 1.12.1

qbs avr compiling

I try to build simple project with qbs
import qbs
Project {
name: "simple"
Product {
name: "micro"
type: "obj"
Group {
name: "sources"
files: ["main.c", "*.h", "*.S"]
fileTags: ['c']
}
Rule {
inputs: ["c"]
Artifact {
fileTags: ['obj']
filePath: input.fileName + '.o'
}
prepare: {
var args = [];
args.push("-g")
args.push("-Os")
args.push("-w")
args.push("-fno-exceptions")
args.push("-ffunction-sections")
args.push("-fdata-sections")
args.push("-MMD")
args.push("-mmcu=atmega328p")
args.push("-DF_CPU=16000000L")
args.push("-DARDUINO=152")
args.push("-IC:/Programs/arduino/hardware/arduino/avr/cores/arduino")
args.push("-IC:/Programs/arduino/hardware/arduino/avr/variants/standard")
args.push("-c")
args.push(input.fileName)
args.push("-o")
args.push(input.fileName + ".o")
var compilerPath = "C:/Programs/arduino/hardware/tools/avr/bin/avr-g++.exe"
var cmd = new Command(compilerPath, args);
cmd.description = 'compiling ' + input.fileName;
cmd.highlight = 'compiler';
cmd.silent = false;
console.error(input.baseDir + '/' + input.fileName);
return cmd;
}
}
}
}
And I get error
compiling main.c
C:/Programs/arduino/hardware/tools/avr/bin/avr-g++.exe -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -MMD "-mmcu=atmega328p" "-DF_CPU=16000000L" "-DARDUINO=152" -IC:/Programs/arduino/hardware/arduino/avr/cores/arduino -IC:/Programs/arduino/hardware/arduino/avr/variants/standard -c main.c -o main.c.o
avr-g++.exe: main.c: No such file or directory
avr-g++.exe: no input files
Process failed with exit code 1.
The following products could not be built for configuration qtc_avr_f84c45e7-release:
micro
What do I wrong?
File main.c present in project and in directory.
If I start this command from command prompt I do not get error.
In short, you need to pass input.filePath after -c and -o, not input.fileName. There's no guarantee that the working directory of the command invoked will be that of your source directory.
You can set the workingDirectory of a Command object, but that is not generally recommended as your commands should be independent of the working directory unless absolutely necessary.
Furthermore, you appear to be duplicating the functionality of the cpp module. Instead, your project should look like this:
import qbs
Project {
name: "simple"
Product {
Depends { name: "cpp" }
name: "micro"
type: "obj"
Group {
name: "sources"
files: ["main.c", "*.h", "*.S"]
fileTags: ['c']
}
cpp.debugInformation: true // passes -g
cpp.optimization: "small" // passes -Os
cpp.warningLevel: "none" // passes -w
cpp.enableExceptions: false // passes -fno-exceptions
cpp.commonCompilerFlags: [
"-ffunction-sections",
"-fdata-sections",
"-MMD",
"-mmcu=atmega328p"
]
cpp.defines: [
"F_CPU=16000000L",
"ARDUINO=152"
]
cpp.includePaths: [
"C:/Programs/arduino/hardware/arduino/avr/cores/arduino",
"C:/Programs/arduino/hardware/arduino/avr/variants/standard
]
cpp.toolchainInstallPath: "C:/Programs/arduino/hardware/tools/avr/bin"
cpp.cxxCompilerName: "avr-g++.exe"
}
}
it's work
args.push("-c")
args.push(input.filePath) at you args.push(input.fileName)
args.push("-o")
args.push(output.filePath)at you args.push(input.fileName)