Gulp.js: how to rewrite relative paths? - javascript

Structure:
static
├── build
│ ├── css
│ ├── fonts
│ ├── img
│ └── js
└── src
├── blocks
├── fonts
└── img
Piece of gulpfile.js:
var path = {
build: {
js: 'static/build/js',
css: 'static/build/css',
fonts: 'static/build/fonts',
img: 'static/build/img'
},
src: {
vendor_fonts: ['bower_components/**/*.{svg,woff,eot,ttf}', 'semantic/**/*.{svg,woff,eot,ttf}'],
vendor_img: ['bower_components/**/*.{png,jpg,jpeg,gif}', 'semantic/**/*.{png,jpg,jpeg,gif}']
}
};
gulp.task('vendor:img', function(){
return gulp.src(path.src.vendor_img)
.pipe(imagemin({
progressive: true,
interlaced: true,
use: [pngguant()]
}))
.pipe(gulp.dest(path.build.img))
});
gulp.task('vendor:fonts', function() {
gulp.src(path.src.vendor_fonts)
.pipe(gulp.dest(path.build.fonts))
});
When i build 3-party packages (such as fotorama or semantic ui), they have a relative paths - as a result, main.css have only relative paths and server cant't find them.
How i can solve this?

If your gulpfile.jss is in your root you should be able to just prefix your paths with nodes Global Object __dirname
__dirname#
{String}
The name of the directory that the currently executing script resides in.
Example: running node example.js from /Users/mjr
console.log(__dirname);
// /Users/mjr
__dirname isn't actually a global but rather local to each module.
https://nodejs.org/api/globals.html#globals_dirname
So if your gulpfile was in your root in your paths just do
__dirname + "/build/whatever/whatever";
This all being if I understand your question correctly.

Related

Unable to load image using Webpack 5

I'm using webpack 5 to bundle an embeddable widget.
I can't seem to load an image created on the fly.
const img = document.createElement('img');
img.src = 'assets/doggo.svg';
http://localhost:8080/assets/doggo.svg gives 404
In my webpack.config.js I have the following:
module: {
rules: [
// Typecript
{
test: /\.ts|\.tsx$/,
use: 'awesome-typescript-loader',
include: __dirname
},
// Images
{
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
type: 'asset/resource',
},
// Fonts and SVGs
{
test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
type: 'asset/inline',
},
],
},
Below is my file structure:
├── package.json
├── postcss.config.js
├── src
│   ├── index.ts
│   ├── assets
│   ├── index.html
│   ├── index.ts
│   ├── types.d.ts
│   └── utils
├── tsconfig.json
├── webpack.config.js
└── yarn.lock
The approach below seems to work.
import doggoImg from './assets/doggo.svg';
const img = document.createElement('img');
img.src = doggoImg;
const container = document.createElement('div');
container.appendChild(img);

Rollup & React- How to separate component bundles?

I currently am trying to build a UI Library for React and I am having a little bit of trouble. Currently I am using typescript and rollup, and I am able to bundle a single index.js and I am able to import those components but it is importing the whole library.
Currently:
File structure:
src
--components
-----button
-------button.tsx
-------button.types.ts
-----input
-------input.tsx
-------input.types.ts
-----index.ts
rollup.js
My rollup targets index.ts which has everything exported like so:
export { default as Button} from './button/button'
export { default as Input } from './input/input'
And I am able to import in a react project like so:
import { Button, Input } from 'my-library'
What I would Like to do
I would like that each component is bundled separately and they would be imported like so
import { Input } from 'my-library/input'
import { Button } from 'my-library/button'
What I've Tried:
After reading the docs, it seemed that the preserveModule: true is what I was looking for but then I tried importing as above but it started to complain that nothing was found.
My current rollup.js looks like this:
export default {
input: 'src/index.ts',
output: [
{
exports: 'named',
dir: 'build/',
format: 'esm',
sourcemap: true,
preserveModules: true,
},
],
plugins: [
cleaner({ targets: ['./build'] }),
peerDepsExternal(),
resolve(),
commonjs(),
terser(),
typescript({
exclude: ['**/*.stories.tsx', '**/*.test.tsx'],
}),
],
};
EDIT: I've posted a more comprehensive tutorial on medium here
I tried using preserveModules but it doesnt generate an index.js file for each Components such that I can import like so :
import Button from 'lib/Button'
Hence I came up with a work around to make rollup loop through my src folders to generate a folder with entrypoint for every Component folder i had in src at rootDir
Maintain a strict folder structure with entry point for every Component folder. Do not have loose files, other than index.ts in src folder that have no folders. Name your folders properly like how you want users to import it
src folder structure:
rollup.config.js
src
├── Accordion
│ ├── Accordion.tsx
│ ├── AccordionBody.tsx
│ ├── AccordionButton.tsx
│ ├── AccordionCollapse.tsx
│ ├── AccordionContext.ts
│ ├── AccordionHeader.tsx
│ ├── AccordionItem.tsx
│ ├── AccordionItemContext.ts
│ └── index.ts
├── Alert
│ ├── Alert.tsx
│ └── index.ts
├── Badge
│ ├── Badge.tsx
│ └── index.ts
├── Breadcrumb
│ ├── Breadcrumb.tsx
│ ├── BreadcrumbItem.tsx
│ └── index.ts
├── Button
│ ├── Button.tsx
│ └── index.ts
├── ButtonGroup
│ ├── ButtonGroup.tsx
│ └── index.ts
...
├── Tooltip
│ ├── Tooltip.tsx
│ ├── TooltipBox.tsx
│ └── index.ts
├── index.ts
Its crucial for this case to maintain an entry point for each Component folder. I still maintained an entry point for src folder so that users can still import multiple components from the library with one line
i.e. import {Button, Accordion, ...} from 'lib'
Rollup config
getFolders returns an array of Folder names that are meant for export
loop through getFolders to generate the rollup obj per folder.
For typescript projects, rollup outputs the typings file with preserved folder structure already, so I realised that the folders Accordion, Button etc. were already there with typings file only. Now we need to add the index.js file to it!
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import typescript from 'rollup-plugin-typescript2';
import replace from '#rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
const packageJson = require('./package.json');
import { getFolders } from './scripts/buildUtils';
const plugins = [
peerDepsExternal(),
resolve(),
commonjs(),
typescript({
tsconfig: './tsconfig.json',
useTsconfigDeclarationDir: true,
}),
terser()
]
const getFolders = (entry) => {
// get the names of folders and files of the entry directory
const dirs = fs.readdirSync(entry)
// do not include folders not meant for export and do not process index.ts
const dirsWithoutIndex = dirs.filter(name => name !== 'index.ts').filter(name => name !== 'utils')
// ['Accordion', 'Button'...]
return dirsWithoutIndex
}
//loop through your folders and generate a rollup obj per folder
const folderBuilds = getFolders('./src').map(folder=> {
return {
input: `src/${folder}/index.ts`,
output: {
// ensure file destination is same as where the typings are
file: `dist/${folder}/index.js`,
sourcemap: true,
exports: 'named',
},
plugins,
external: ['react', 'react-dom'],
}
})
export default [
{
input: ['src/index.ts'],
output: [
{
file: packageJson.module,
format: 'esm',
sourcemap: true,
exports: 'named',
},
],
plugins,
external: ['react', 'react-dom'],
},
...folderBuilds,
{
input: ['src/index.ts'],
output: [
{
file: packageJson.main,
format: 'cjs',
sourcemap: true,
exports: 'named',
},
],
plugins,
external: ['react', 'react-dom'],
},
];
CJS file
finally i also added the rollup config to generate the cjs file. I did not bother to code split the cjs file since most users are using es6 imports
"frank" build
Post build, I run a script to copy paste package.json, Readme to the ./dist folder
/* eslint-disable no-console */
const { resolve, join, basename } = require('path');
const { readFile, writeFile, copy } = require('fs-extra');
const packagePath = process.cwd();
const distPath = join(packagePath, './dist');
const writeJson = (targetPath, obj) =>
writeFile(targetPath, JSON.stringify(obj, null, 2), 'utf8');
async function createPackageFile() {
const packageData = await readFile(
resolve(packagePath, './package.json'),
'utf8'
);
const { scripts, devDependencies, ...packageOthers } =
JSON.parse(packageData);
const newPackageData = {
...packageOthers,
private: false,
typings: './index.d.ts',
main: './main.js',
module: './index.js',
};
const targetPath = resolve(distPath, './package.json');
await writeJson(targetPath, newPackageData);
console.log(`Created package.json in ${targetPath}`);
}
async function includeFileInBuild(file) {
const sourcePath = resolve(packagePath, file);
const targetPath = resolve(distPath, basename(file));
await copy(sourcePath, targetPath);
console.log(`Copied ${sourcePath} to ${targetPath}`);
}
async function run() {
try {
await createPackageFile();
await includeFileInBuild('./README.md');
// await includeFileInBuild('../../LICENSE');
} catch (err) {
console.error(err);
process.exit(1);
}
}
run();
finally from root npm publish ./dist
This is how my dist folder looks like finally
dist
├── Accordion
│ ├── Accordion.d.ts
│ ├── AccordionBody.d.ts
│ ├── AccordionButton.d.ts
│ ├── AccordionCollapse.d.ts
│ ├── AccordionContext.d.ts
│ ├── AccordionHeader.d.ts
│ ├── AccordionItem.d.ts
│ ├── AccordionItemContext.d.ts
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── Alert
│ ├── Alert.d.ts
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── Badge
│ ├── Badge.d.ts
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── Breadcrumb
│ ├── Breadcrumb.d.ts
│ ├── BreadcrumbItem.d.ts
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── Button
│ ├── Button.d.ts
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── ButtonGroup
│ ├── ButtonGroup.d.ts
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
...
├── Tooltip
│ ├── Tooltip.d.ts
│ ├── TooltipBox.d.ts
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── index.d.ts
├── index.js
├── index.js.map
├── main.js
├── main.js.map
├── package.json
I got my solutions after much research from rollup issue thread on gh.
Here are some references:
Franking the build : https://stackoverflow.com/questions/62518396/importing-from-subfolders-for-a-javascript-package#:~:text=Votes-,13,-This%20is%20possible
folder structuring :
https://github.com/ezolenko/rollup-plugin-typescript2/issues/136#issuecomment-792383946
inspiration for getFolders() that i wrote was from this author's getFiles()
https://www.codefeetime.com/post/rollup-config-for-react-component-library-with-typescript-scss/

gulp-eslint not linting .js files inside of a dot directory

I have .js files inside of a dot directory that are not being linted by gulp-eslint.
Example: .foo/file1.js
I've confirmed that the glob is picking up the files inside of the dot directory.
gulp-eslint is passing successfully for the files inside of a parent dot directory even when an intentional error is introduced inside these files.
I've confirmed that directories without a . in the name of the directory (e.g. src/file.js, etc.) are failing linting, when the same intentional error is introduced.
My project structure is something like this:
project/
│
├── .foo/
│ ├──file1.js
│ └──file2.js
│
├── src/
│ ├──file1.js
│ └──file2.js
│
├── gulpfile.js
└── .eslintrc
Contents of gulpfile.js
const gulp = require('gulp');
const eslint = require('gulp-eslint');
gulp.task('lint', () => {
return gulp.src([ './src/**/*.js', './.foo/**/*.js' ])
.pipe(eslint({
configFile: './.eslintrc'
}))
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
Contents of .eslintrc
// Reducing down to a single, simple rule
{
"env": {
"es6": true
},
"rules": {
"quotes": [
"error",
"single"
]
}
}
Is there something incorrect in my config that is preventing the .js files inside of the dot directory .foo from being linted?
Thanks!
It looks to be a known "quirk" of eslint (as of 6.8.0).
The workaround (until a PR is merged to fix this) is to use an .eslintignore file to unignore dot directories explicitly:
#.eslintignore
!.foo

How to copy files that do not need to be compiled in Gulp?

Suppose that my project is like this:
├── dist
├── src
│   ├── greeter.ts
│   ├── index.html
│   └── test.txt
└── tsconfig.json
Only greeter.ts need to be complied to dir dist, but how about other files? How to copy other files to dir dist?
here is my gulpfile.js:
gulp.task('ts',cb=>{
return gulp.src('src/**/*.ts')
.pipe(sourcemaps.init())
.pipe(tsProject())
.js
.pipe(babel({
presets: ['env']
}))
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist'));
});
Create a another task to copy other files and add its dependency on other task
gulp.task('copyFile', function () {
return gulp.src([
'src/**/*', //Include All files
'!src/**/*.ts' //It will exclude typescript files
]).pipe(gulp.dest('dist'));
});
gulp.task('ts', ['copyFile'], cb => {
//Your existing code
});

How to load into specific path

i have an app directory looks like
app/
├── controllers
│   ├── index.js
│   └── users.js
├── errors.js
├── models
│   └── user.js
└── other_things
in the server.js i have the following code using express-load
load('errors', {cwd: 'app'})
.then('models')
.then('controllers')
.into(app);
but console.log(app.errors) is undefined
and console.log(app); show the following among many other unrelated output
'': { errors: { not_found: [Function] } } }
how do i convert that to be
'errors':{ not_found: [Function] } }
the errors.js is defined as following
exports.not_found = function(err){
//... yada yada...
}
this solution work prior to express-load 1.1.14:
load('app/errors').into(app, function(err, instance){
app.errors = app.app.errors;
delete app.app;
});
load('models', {cwd: 'app'}).then('controllers').into(app);
and it was fixed in version 1.1.14

Categories