Страницы

Поиск по вопросам

Показаны сообщения с ярлыком npm. Показать все сообщения
Показаны сообщения с ярлыком npm. Показать все сообщения

четверг, 9 апреля 2020 г.

Docker ENOTFOUND при npm install?

#nodejs #npm #docker

                    
Почему при выполнении npm i я начинаю получать сообщения вида:

npm info attempt registry request try #2 at 11:45:00 PM
npm http request GET https://registry.npmjs.org/redis
npm info attempt registry request try #2 at 11:45:00 PM
npm http request GET https://registry.npmjs.org/hiredis
npm info attempt registry request try #2 at 11:45:00 PM
npm http request GET https://registry.npmjs.org/express
npm info retry will retry, error on last attempt: Error: getaddrinfo ENOTFOUND registry.npmjs.org
registry.npmjs.org:443
npm info retry will retry, error on last attempt: Error: getaddrinfo ENOTFOUND registry.npmjs.org
registry.npmjs.org:443
npm info retry will retry, error on last attempt: Error: getaddrinfo ENOTFOUND registry.npmjs.org
registry.npmjs.org:443

    


Ответы

Ответ 1



Помог перезапуск службы docker sudo service docker restart Видимо DNS нужно было обновить

воскресенье, 1 марта 2020 г.

Что значит установить пакет глобально?

#javascript #nodejs #npm


Всех приветствую! Прошу помощи у сообщества, не откажите и объясните по простому,
что значит установить пакет глобально? Например, npm install -g webpack?
    


Ответы

Ответ 1



Установить глобально - это указать при установке флаг -g. После этого пакет поставится в определённую папку (в Windows - специфичную для пользователя, в Linux - для всей системы) и станет доступен из командной строки. Обращаю внимание, что пакет оказывается специфичен для компьютера, а не для проекта, соответственно если передаётся некоторый код, рассчитывающий на глобально установленные модули, то их придётся ставить самостоятельно. Кроме того, нельзя использовать одновременно разные версии глобально установленных модулей. Поэтому, если речь идёт о разработке, то глобальную установку обычно не используют. Вместо неё модуль устанавливается как зависимость, а в секции scripts файла packadge.json прописывается команда для его запуска через npm. Глобально имеет смысл устанавливать утилитные пакеты, которые нужны лично тебе для каких-то целей, например, http-server, если ты хочешь показать другу статический сайтик.

суббота, 15 февраля 2020 г.

Заморозить часть строки в git'е

#git #npm #gitignore


Есть npm'овский packadge.json, один из модулей в котором подключается как git-репозиторий
с тегом. Проблема в том, что адрес репозитория должен содержать имя пользователя:

"some-module": "git+https://qwertiy@git.smth.com/some-module.git#1.2.3"
                            ^^^^^^^_______________________________________ у каждого своё
                                                                 ^^^^^____ версия
меняется


Можно ли как-то настроить git, чтобы он при выполнении pull, commit, rebase и других
команд игнорировал имя пользователя, но обновлял версию пакета без merge-конфликтов?

Т. е. везде имя должно оставаться без изменений: локально - локальное имя, а в закоммиченном
- закоммиченное.

А может быть есть какие-то другие способы, связанные не с git'ом, а с npm'ом?
    


Ответы

Ответ 1



Да, это можно настроить в git. Называется smudge /clean (загрязнить-почистить). Суть в том, что при добавлении файла или извлечении с репозитория он будет пропускаться через фильтр. Итого, нужно будет два фильтра - один будет подставлять правильного пользователя, второй - заменять его на некого "универсально", которого будем оставлять в коде. Здесь расписано детально, как это работает https://alexzaytsev.me/2014/10/19/git-filter-to-convert-spaces-to-tabs-and-vice-versa/ - но тут для пробелов. Вначале в .gitconfig (или .git\info\attributes) добавить фильтр package.json filter=hide_my_name и добавить собственно сами фильтра в gitconfig [filter "hide_my_name"] clean = 'remove-name' smudge = 'restore-name' remove-name и restore-name - это две программы (или скрипта), которые на вход получат содержимое файла на стандартный ввод и должны будут сделать замену. clean задача будет запускаться перед git add, а smugle - после checkout. Написание самых скриптов и как хранить имя для конкретного пользователя - это уже домашняя задача. Но я не исключаю, что эта задача может иметь такое решение: [filter "hide_my_name"] clean = 'perl -pe "s!git+https://qwertiy@!git+https://XXXXXXX@!"' smudge = 'perl -pe "s!git+https://XXXXXXX@!git+https://qwertiy@!"'

понедельник, 10 февраля 2020 г.

посмотреть команды в package.json

#javascript #npm


Какая команда в консоле, чтобы посмотреть список доступных скриптов.

Допустим есть секция со скриптами:



раньше я набирал npm ls или что то вроде этого - вроде и видел список скриптов. 
    


Ответы

Ответ 1



Для того, чтобы вывести список доступных скриптов можно использовать команду npm run npm run-script [-- ...] alias: npm run Описание Запускает указанную команду и объекта "scripts" в package.json. Если "command" не указан, будет выведен список доступных скриптов.

Ответ 2



Я использую для этого npm-list-scripts. Установить можно командой: npm install -g npm-list-scripts Список скриптов можно просмотреть командой npm-list-scripts Пример работы:

воскресенье, 26 января 2020 г.

Ошибка: не является внутренней или внешней командой, исполняемой программой или пакетным файлом

#nodejs #npm




Возникли проблемы при работе с nodejs

Например, когда вызываешь npm --v получается  вот это (см.ниже)

C:\WINDOWS\system32>npm --v
"CALL "C:\Program Files\nodejs\\node.exe" "C:\Program Files\nodejs\\node_modules\npm\bin\npm-cli.js"
prefix -g" не является внутренней или внешней командой, исполняемой программой или
пакетным файлом.
2.14.4


Вроде выводит версию, но перед этим выводит, как вы видите, какую-то ошибку что ли...

В чем проблема? Я не могу понять почему выводит какой-то CALL? 

Обновление

:: Created by npm, please don't edit manually.

ECHO OFF

SETLOCAL

SET "NODE_EXE=%~dp0\node.exe"
IF NOT EXIST "%NODE_EXE%" (
  SET "NODE_EXE=node"
)

SET "NPM_CLI_JS=%~dp0\node_modules\npm\bin\npm-cli.js"
FOR /F "delims=" %%F IN ('CALL "%NODE_EXE%" "%NPM_CLI_JS%" prefix -g') DO (
  SET "NPM_PREFIX_NPM_CLI_JS=%%F\node_modules\npm\bin\npm-cli.js"
)
IF EXIST "%NPM_PREFIX_NPM_CLI_JS%" (
  SET "NPM_CLI_JS=%NPM_PREFIX_NPM_CLI_JS%"
)

"%NODE_EXE%" "%NPM_CLI_JS%" %*


Извиняюсь за оформление. Это было содержимое npm.cmd.
    


Ответы

Ответ 1



Запрашивать версию надо одним из следующих способов: -v --version Насколько я помню, вариант --v не является классическим. Впрочем, мой npm версии 2.10.1 его тоже съел.

пятница, 24 января 2020 г.

Оформление пакета для NPM

#npm #nodejs


Здравствуйте.
Решил я тут создать и опубликовать пакет для node.js. Прочитал пару статей по оформлению
пакетов, дал команду "npm init" и понеслась.
Написал код, написал README.md, сохранил всё на gitlab, сделал "npm publish" и..
не впечатлило.

Как так у всех получается содержимое README.md "прицеплять" как документацию на странице
пакета (например: https ://www.npmjs.com/package/express-session), а у меня получилось
нечто такое: https://www.npmjs.com/package/express-sticky-cluster

Содержимое package.json:

{
    "author": {
    "name": "Valeriy V. Pushkar",
    "email": ""
  },
  "bugs": {
    "url": "https ://github.com/kainpl/express-sticky-cluster/issues"
  },
  "dependencies": {
    "http-proxy": "*",
    "merge": "*",
    "cookie": "*"
  },
  "description": "Sticky session balancer based on a cluster and node-http-proxy
modules, with express and socket.io support",
  "devDependencies": {},
  "directories": {},
  "dist": {
    "shasum": "671d155887bf4b6b3055989ef65b077c022df890",
    "tarball": "https ://registry.npmjs.org/express-sticky-cluster/-/express-sticky-cluster-0.0.1.tgz"
  },
  "gitHead": "066bc4d03d2d058ff534be1949120a41d0507464",
  "homepage": "https ://github.com/kainpl/express-sticky-cluster#readme",
  "keywords": [
    "express.js",
    "cluster",
    "http-proxy",
    "socket.io",
    "sticky-cluster",
    "sticky-sessions"
  ],
  "license": "MIT",
  "main": "index.js",
  "maintainers": [
    {
      "name": "kain_pl",
      "email": ""
    }
  ],
  "name": "express-sticky-cluster",
  "optionalDependencies": {},
  "readme": "https ://github.com/kainpl/express-sticky-cluster#readme",
  "repository": {
    "type": "git",
    "url": "git+https ://github.com/kainpl/express-sticky-cluster.git"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "version": "0.1.1"
}

    


Ответы

Ответ 1



Спасибо! Ответ на вопрос: Уберите поле readme. Тогда npm сам всё сделает – Alexey Ten

Как справиться с этой ошибкой? версия node 8.0.0

#nodejs #npm


SyntaxError: Use of const in strict mode.
    at Module._compile (module.js:439:25)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:902:3
npm ERR! weird error 8
npm WARN This failure might be due to the use of legacy binary "node"
npm WARN For further explanations, please read
/usr/share/doc/nodejs/README.Debian

npm ERR! not ok code 0

    


Ответы

Ответ 1



Эта ошибка срабатывает когда вы используете const вне строгого окружёния, вне 'use strict'. В тексте ошибки прямо советуют включить строгий режим. Однако в 8 версии ноды этой ошибки быть точно не должно. Проверьте версию ноды, которую используете. Я всегда ставил ноду с их сайта в папку пользователя $home/bin, это если для личного использования. На сервере же вы просто можете запустить ноду в докере.

четверг, 23 января 2020 г.

Ошибки при инсталляции некоторых модулей через npm

#nodejs #angularjs #npm


Изучаю Angular, попытался собрать эти проекты: 

https://github.com/angular/angular-phonecat (стандартный с оф сайта)
и https://github.com/ngbp/ngbp

Проблема в том, что npm не может зарезолвить установку всех node js пакетов (основные
- bower, grunt-cli ставятся корректно, но хочется чтобы работало все)

Система: Windows 8.1 64 bit

Пытался гуглить, искал разные решения, ничего не помогло.

Ошибки: 


    


Ответы

Ответ 1



Это ошибка компиляции для платформы windows. Нужно добавить необходимые инструменты в вашу Windows. Вот пример решения для node-gyp / bcrypt Error compiling bcrypt - node.js. После компиляции node-gyp все будет работать.

суббота, 4 января 2020 г.

Как создать npm-пакет, который будет иметь возможность запускаться прямо из терминала по своему имени?

#nodejs #npm #node_modules


Интересует, как создаются такие npm-пакеты, которые в дальнейшем можно вызывать прямо
из терминала?

Например, при установке пакета express-generator, в папку, где лежит бинарник node'а
и npm'а (например ~/.local/bin/node/bin/) добавляется ссылка на ../lib/node_modules/[package]/bin/.
То есть, поскольку путь к node'у лежит в переменной окружения $PATH, то и к этому пакету
тоже теперь есть доступ прямо из терминала. Я могу просто написать express и этот файл
начнет выполняться ('~/.local/bin/node/lib/node_modules/express-generator/bin/express-cli.js`).

Что удивляет еще больше, так это 2 другие вещи: почему пакет называется express-generator,
а запускается он командой express? И почему этот файл является обычным .js файлом,
но запускается из терминала как ни в чем не бывало? Где-то неявно указывается его открытие
через Node?

В общем, интересует, как можно создать подобного рода пакет, чтобы сразу при его
установке добавлялась ссылка на .js файл в путь к node'у, чтобы мой пакет можно было
запустить прямо из терминала.

Благодарю.

P.S. Если где-то путаю термины, то прошу меня поправить, ибо только начинаю разбираться
во всей этой каше.



По просьбе "сформулировать вопрос более точно".
Как создать npm-пакет, который будет иметь возможность запускаться прямо из терминала
по своему имени? Подробности описаны выше.
    


Ответы

Ответ 1



За это отвечает секция bin в package.json: "bin": { "mytool": "bin/tool.js" } tool.js, в свою очередь, должен содержать так называемый шебанг - #!/usr/bin/env node, например. При установке такого пакета, в node_modules/.bin появится исполняемый бинарник mytool. Точнее симлинк mytool -> ../yourpackage/bin/tool.js. Запускать локально установленные утилиты можно как $(npm bin)/mytool При установке пакета с -g он попадёт в глобальный node_modules/.bin, который присутствует в $PATH. Тогда его можно вызывать просто, как mytool.

Ответ 2



Вот пример такого пакета package.json { "name": "myscript", "version": "0.0.1", "description": "Do nothing", "license": "MIT", "preferGlobal": true, "bin": { "myscript": "index.js" } } preferGlobal указывает, что это пакет преимущественно запускается в командной строке и его надо установить глобально - ключ -g, если устанавливать без этого ключа, то будет выдано предупреждение. bin указывает какой будет создан symlink. Ключ - это имя symlink (вашей команды, express, например), а значение - это файл, на который этот symlink указывает. В случае с express-generator там будет "bin":{"express":"./bin/express-cli.js"} index.js Первая строчка указывает как именно запускать этот файл. #!/usr/bin/env node console.log('Script is running'); index.js нужно сделать исполняемым chmod +x index.js Для проверки этого пакета в процессе разработки необходимо выполнить вот эту команду. npm link И вы получите возможность запускать myscript в терминале. После публикации пакета в npmjs он будет работать как все остальные пакеты.

четверг, 2 января 2020 г.

Gulp 4 выдает ошибку

#javascript #nodejs #gulp #npm


Исходники: Gulp4.zip

Ошибка:

assert.js:42
  throw new errors.AssertionError({
  ^

AssertionError [ERR_ASSERTION]: Task function must be specified
    at Gulp.set [as _setTask] (E:\Web\test\node_modules\undertaker\lib\set-task.js:10:3)
    at Gulp.task (E:\Web\test\node_modules\undertaker\lib\task.js:13:8)
    at Object. (E:\Web\test\gulpfile.js:224:6)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)


Версия Gulp:

PS E:\Web\test> gulp -v
[06:20:13] CLI version 2.0.1
[06:20:13] Local version 4.0.0


Версия Npm:

PS E:\Web\test> npm -v
6.5.0


package.json



{
  "name": "html-ready",
  "version": "1.0.0",
  "description": "",
  "main": "gulpfile.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Devinora",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.2.0",
    "@babel/preset-env": "^7.2.0",
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.3",
    "browser-sync": "^2.26.3",
    "gulp": "^4.0.0",
    "gulp-autoprefixer": "^6.0.0",
    "gulp-babel": "^8.0.0",
    "gulp-file-include": "^2.0.1",
    "gulp-imagemin": "^5.0.3",
    "gulp-minify-css": "^1.2.4",
    "gulp-plumber": "^1.2.1",
    "gulp-rename": "^1.4.0",
    "gulp-sass": "^4.0.2",
    "gulp-sourcemaps": "^2.6.4",
    "gulp-terser": "^1.1.6",
    "gulp-watch": "^5.0.1",
    "gulp.spritesmith": "^6.9.0",
    "imagemin-pngquant": "^6.0.0",
    "rimraf": "^2.6.2"
  },
  "dependencies": {
    "npm": "^6.5.0"
  }
}




gulpfile.js



'use strict';

var gulp = require('gulp'),
  watch = require('gulp-watch'),
  plumber = require('gulp-plumber'),
  prefixer = require('gulp-autoprefixer'),
  babel = require('gulp-babel'),
  terser = require('gulp-terser'), //альтернатива gulp-uglifyes
  sass = require('gulp-sass'),
  sourcemaps = require('gulp-sourcemaps'),
  fileinclude = require('gulp-file-include'),
  cssmin = require('gulp-minify-css'),
  imagemin = require('gulp-imagemin'),
  pngquant = require('imagemin-pngquant'),
  rimraf = require('rimraf'),
  browserSync = require("browser-sync"),
  rename = require('gulp-rename'),
  spritesmith = require('gulp.spritesmith'),
  reload = browserSync.stream;

var path = {
  dist: {
    html: 'dist/',
    php: 'dist/',
    js: 'dist/js/',
    css: 'dist/css/',
    img: 'dist/img/',
    fonts: 'dist/fonts/'
  },
  app: {
    html: 'app/*.html',
    php: 'app/*.php',
    js: 'app/js/main.js',
    jsInit: 'app/js/init.js',
    style: 'app/scss/main.scss',
    sprite: 'app/img/sprite/**/*.*',
    img: 'app/img/*.*',
    fonts: 'app/fonts/**/*.*',
  },
  watch: {
    html: 'app/**/*.html',
    php: 'app/*.php',
    js: 'app/js/**/*.js',
    style: 'app/scss/**/*.scss',
    img: 'app/img/*.*',
    sprite: 'app/img/sprite/**/*.*',
    fonts: 'app/fonts/**/*.*'
  },
  export: {
    img: 'app/img/',
    style: 'app/scss/imports/'
  },
  spriteTemplate: 'sass.template.mustache',
  clean: './dist'
};

var config = {
  server: {
    baseDir: "dist" // or ./dist
  },
  // tunnel: true,
  // host: "178.150.110.97",
  // notify: false,
  logPrefix: "Frontend_Devil"
};

gulp.task('webserver', function() {
  browserSync(config);
});

gulp.task('clean', function(cb) {
  rimraf(path.clean, cb);
});

gulp.task('html:dist', function() {
  gulp.src(path.app.html)
    .pipe(plumber())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(gulp.dest(path.dist.html))
    .pipe(reload());
});

gulp.task('php:dist', function() {
  gulp.src(path.app.php)
    .pipe(plumber())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(gulp.dest(path.dist.php))
    .pipe(reload());
});

gulp.task('js:dist', function() {
  //init.js
  //Файл для инициации
  // gulp.src(path.app.jsInit)
  // .pipe(plumber())
  // .pipe(sourcemaps.init())
  // .pipe(fileinclude({
  // 	prefix: '@@',
  // 	basepath: '@file'
  // }))
  // .pipe(babel({
  // 	presets: ["@babel/preset-env"]
  // }))
  // .pipe(terser())
  // .pipe(sourcemaps.write())
  // .pipe(rename({suffix: '.babel-min', prefix : ''}))
  // .pipe(gulp.dest(path.dist.js))

  //Обычный js файл.
  gulp.src(path.app.js)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(path.dist.js))
  //Babel-js файл.
  gulp.src(path.app.js)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(babel({
      presets: ["@babel/preset-env"]
    }))
    .pipe(rename({
      suffix: '.babel',
      prefix: ''
    }))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(path.dist.js))
  //Mini-js файл.
  gulp.src(path.app.js)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(terser()) //альтернатива uglifyes
    .pipe(sourcemaps.write())
    .pipe(rename({
      suffix: '.min',
      prefix: ''
    }))
    .pipe(gulp.dest(path.dist.js));
  //Babel-mini-js файл.
  gulp.src(path.app.js)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(babel({
      presets: ["@babel/preset-env"]
    }))
    .pipe(terser())
    .pipe(sourcemaps.write())
    .pipe(rename({
      suffix: '.babel-min',
      prefix: ''
    }))
    .pipe(gulp.dest(path.dist.js))
    .pipe(reload());
});

gulp.task('style:dist', function() {
  gulp.src(path.app.style)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(sass({
      sourceMap: true,
      errLogToConsole: true
    }))
    .pipe(prefixer())
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(path.dist.css))
    .pipe(cssmin())
    .pipe(sourcemaps.write())
    .pipe(rename({
      suffix: '.min',
      prefix: ''
    }))
    .pipe(gulp.dest(path.dist.css))
    .pipe(reload());
});

gulp.task('image:dist', function() {
  gulp.src(path.app.img)
    .pipe(plumber())
    .pipe(imagemin({
      progressive: true,
      svgoPlugins: [{
        removeViewBox: false
      }],
      use: [pngquant()],
      interlaced: true
    }))
    .pipe(gulp.dest(path.dist.img))
    .pipe(reload());
});

gulp.task('sprite:dist', function() {
  var spriteData =
    gulp.src(path.app.sprite)
    .pipe(plumber())
    .pipe(spritesmith({
      imgName: 'sprite.png',
      cssName: '_sprite.scss',
      cssFormat: 'scss',
      algorithm: 'binary-tree',
      cssTemplate: path.spriteTemplate,
      cssVarMap: function(sprite) {
        sprite.name = 's-' + sprite.name
      }
    }));
  spriteData.img.pipe(gulp.dest(path.export.img));
  spriteData.css.pipe(gulp.dest(path.export.style));
});

gulp.task('fonts:dist', function() {
  gulp.src(path.app.fonts)
    .pipe(plumber())
    .pipe(gulp.dest(path.dist.fonts))
});

gulp.task('dist', [
  'html:dist',
  'php:dist',
  'js:dist',
  'sprite:dist',
  'style:dist',
  'fonts:dist',
  'image:dist'
]);

gulp.task('watch', function() {
  watch(path.watch.html, function(event, cb) {
    gulp.start('html:dist');
  });
  watch(path.watch.php, function(event, cb) {
    gulp.start('php:dist');
  });
  watch(path.watch.style, function(event, cb) {
    gulp.start('style:dist');
  });
  watch(path.watch.js, function(event, cb) {
    gulp.start('js:dist');
  });
  watch(path.watch.img, function(event, cb) {
    gulp.start('image:dist');
  });
  watch(path.watch.sprite, function(event, cb) {
    gulp.start('sprite:dist');
  });
  watch(path.watch.fonts, function(event, cb) {
    gulp.start('fonts:dist');
  });
});

gulp.task('default', ['dist', 'webserver', 'watch']);




Частичное решение

Проблема была в том, что при переходе на новый Gulp 4, не сделали обратной совместимости.
Не знаю почему, и оправдано ли это, но ниже я приведу пример, который мне помог.

Они добавили два новых метода: gulp.series, gulp.parallel.

Было: 



gulp.task('dist', [
	'html:dist',
	'php:dist',
	'js:dist',
	'sprite:dist',
	'style:dist',
	'fonts:dist',
	'image:dist'
]);

gulp.task('watch', function() {
	watch(path.watch.html, function(event, cb) {
		gulp.start('html:dist');
	});
	watch(path.watch.php, function(event, cb) {
		gulp.start('php:dist');
	});
	watch(path.watch.style, function(event, cb) {
		gulp.start('style:dist');
	});
	watch(path.watch.js, function(event, cb) {
		gulp.start('js:dist');
	});
	watch(path.watch.img, function(event, cb) {
		gulp.start('image:dist');
	});
	watch(path.watch.sprite, function(event, cb) {
		gulp.start('sprite:dist');
	});
	watch(path.watch.fonts, function(event, cb) {
		gulp.start('fonts:dist');
	});
});

gulp.task('default', ['dist', 'webserver', 'watch']);




Стало:



//Удалил 

// gulp.task('dist', [
// 	'html:dist',
// 	'php:dist',
// 	'js:dist',
// 	'sprite:dist',
// 	'style:dist',
// 	'fonts:dist',
// 	'image:dist'
// ]);

gulp.task('watch', function() {
	gulp.watch(path.watch.html, function(event, cb) {
		gulp.start('html:dist');
	});
	gulp.watch(path.watch.php, function(event, cb) {
		gulp.start('php:dist');
	});
	gulp.watch(path.watch.style, function(event, cb) {
		gulp.start('style:dist');
	});
	gulp.watch(path.watch.js, function(event, cb) {
		gulp.start('js:dist');
	});
	gulp.watch(path.watch.img, function(event, cb) {
		gulp.start('image:dist');
	});
	gulp.watch(path.watch.sprite, function(event, cb) {
		gulp.start('sprite:dist');
	});
	gulp.watch(path.watch.fonts, function(event, cb) {
		gulp.start('fonts:dist');
	});
});

gulp.task('default', gulp.parallel(
	'html:dist',
	'php:dist',
	'js:dist',
	'sprite:dist',
	'style:dist',
	'fonts:dist',
	'image:dist',
	'webserver',
	'watch'
));




P.S: На счет правильности написания  gulp.task('watch') я сомневаюсь, но такое решение
мне помогло.

P.S.S: Это малая часть проблем. Буду благодарен, если отредактируете gulpfile.js
так как нужно. Если нужны будет исходники, дайте знать.

[07:12:09] Starting ''...
[07:12:09] '' errored after 2.72 ms
[07:12:09] TypeError: gulp.start is not a function
    at E:\Web\test\gulpfile.js:227:8
    at bound (domain.js:301:14)
    at runBound (domain.js:314:12)
    at asyncRunner (E:\Web\test\node_modules\async-done\index.js:55:18)
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickDomainCallback (internal/process/next_tick.js:218:9)

    


Ответы

Ответ 1



В Gulp 4 изменили способ определения задач, если задача зависит от выполнения другой задачи, другими словами параметр списка [] для указания задач на выполнение - устарел. У вас описан вотчер следующим образом (обратите внимание на gulp.start, его нужно будет заменить, так как запуск должен производиться иначе): gulp.task('watch', function() { watch(path.watch.js, function(event, cb) { gulp.start('js:dist'); }); watch(path.watch.html, function(event, cb) { gulp.start('html:dist'); }); // some code here... }); Вотчер нужно переделать так (вместо start используй series) : gulp.task('watch', function() { gulp.watch(path.watch.js, gulp.series('js:dist')); gulp.watch(path.watch.html, gulp.series('html:dist')); // some code here... }); Это примера запуска вотчера на JS и HTML (остальные по подобию). Единсвенное замечание - следите за правильностью указания пути к файлам в шаблонах (к примеру 'app/**/*.html'). Также переделайте запуск следующей таски (замените параметра списка []): gulp.task('dist', [ 'html:dist', 'php:dist', 'js:dist', 'sprite:dist', 'style:dist', 'fonts:dist', 'image:dist' ]); К примеру на следующий код: gulp.task('dist', gulp.parallel( 'html:dist', 'php:dist', 'js:dist', 'sprite:dist', 'style:dist', 'fonts:dist', 'image:dist' )); Далее, запуск 'default' задачи, у вас он выглядит так (как писал ранее - параметр указания списка задач через [] - устарел): gulp.task('default', ['dist', 'webserver', 'watch']); Сделайте запуск 'default' задачи вот так (чтобы они работали параллельно через gulp.parallel, также убрали запуск через параметр списка []): gulp.task('default', gulp.parallel('dist', 'webserver', 'watch')); В Gulp 4 принято использовать вместо параметра списка [] следующие функции gulp.series(...tasks) и gulp.parallel(...tasks). По использованным функциям: gulp.parallel(...tasks) — запускает указанные задачи параллельно, при этом, если возникает ошибка, то выполнение будет завершено gulp.series(...tasks) — запускает задачи последовательно в указанном порядке, при этом, если возникает ошибка, то выполнение будет завершено Ссылка на документацию по запуску задач внутри gulp.series: Running tasks in series Сссылка на похожую проблему и ее решение: Everytime I run gulp anything, I get a assertion error. - Task function must be specified А также ссылка на гайд по переходу на Gulp 4: A quick guide for switching to gulp 4 Также, хочу обратить внимание на то, что все пакеты, которые вы используете в своем gulpfile необходимо обновить, обязательно удостоверьтесь в том, что они поддерживают Gulp 4. Про основные нюансы я рассказал, других проблем не должно возникнуть при переходе на Gulp 4, как правило основной проблемой является параметра списка [], и иногда слишком старые пакеты. Пример работы вашего приложения. Для начала, версии, которые установлены на моем компьютере (версии node, npm, gulp): После этого я запустил gulp и в браузере открылась страница: Я внес правки в html файл и сохранил изменения, при этом вотчер сработал и отобразилось в консоли изменение, также попробовал изменить js файл и в консоли эти изменения тоже отобразились: В браузере отобразились изменения практически моментально: Вот, собственно сам gulpfile который я запустил: 'use strict'; var gulp = require('gulp'), watch = require('gulp-watch'), plumber = require('gulp-plumber'), prefixer = require('gulp-autoprefixer'), babel = require('gulp-babel'), terser = require('gulp-terser'), //альтернатива gulp-uglifyes sass = require('gulp-sass'), sourcemaps = require('gulp-sourcemaps'), fileinclude = require('gulp-file-include'), cssmin = require('gulp-minify-css'), imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant'), rimraf = require('rimraf'), browserSync = require("browser-sync"), rename = require('gulp-rename'), spritesmith = require('gulp.spritesmith'), reload = browserSync.stream; var path = { dist: { html: 'dist/', php: 'dist/', js: 'dist/js/', css: 'dist/css/', img: 'dist/img/', fonts: 'dist/fonts/' }, app: { html: 'app/*.html', php: 'app/*.php', js: 'app/js/main.js', jsInit: 'app/js/init.js', style: 'app/scss/main.scss', sprite: 'app/img/sprite/**/*.*', img: 'app/img/*.*', fonts: 'app/fonts/**/*.*', }, watch: { html: 'app/**/*.html', php: 'app/*.php', js: 'app/js/**/*.js', style: 'app/scss/**/*.scss', img: 'app/img/*.*', sprite: 'app/img/sprite/**/*.*', fonts: 'app/fonts/**/*.*' }, export: { img: 'app/img/', style: 'app/scss/imports/' }, spriteTemplate: 'sass.template.mustache', clean: './dist' }; var config = { server: { baseDir: "dist" // or ./dist }, // tunnel: true, // host: "178.150.110.97", // notify: false, logPrefix: "Frontend_Devil" }; gulp.task('webserver', function() { browserSync(config); }); gulp.task('clean', function(cb) { rimraf(path.clean, cb); }); gulp.task('html:dist', function(done) { gulp.src(path.app.html) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.html)) .pipe(reload()); done(); }); gulp.task('php:dist', function(done) { gulp.src(path.app.php) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.php)) .pipe(reload()); done(); }); gulp.task('js:dist', function(done) { //init.js //Файл для инициации // gulp.src(path.app.jsInit) // .pipe(plumber()) // .pipe(sourcemaps.init()) // .pipe(fileinclude({ // prefix: '@@', // basepath: '@file' // })) // .pipe(babel({ // presets: ["@babel/preset-env"] // })) // .pipe(terser()) // .pipe(sourcemaps.write()) // .pipe(rename({suffix: '.babel-min', prefix : ''})) // .pipe(gulp.dest(path.dist.js)) //Обычный js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Babel-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(rename({suffix: '.babel', prefix : ''})) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Mini-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(terser()) //альтернатива uglifyes .pipe(sourcemaps.write()) .pipe(rename({suffix: '.min', prefix : ''})) .pipe(gulp.dest(path.dist.js)); //Babel-mini-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(terser()) .pipe(sourcemaps.write()) .pipe(rename({suffix: '.babel-min', prefix : ''})) .pipe(gulp.dest(path.dist.js)) .pipe(reload()); done(); }); gulp.task('style:dist', function(done) { gulp.src(path.app.style) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(sass({ sourceMap: true, errLogToConsole: true })) .pipe(prefixer()) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.css)) .pipe(cssmin()) .pipe(sourcemaps.write()) .pipe(rename({suffix: '.min', prefix : ''})) .pipe(gulp.dest(path.dist.css)) .pipe(reload()); done(); }); gulp.task('image:dist', function(done) { gulp.src(path.app.img) .pipe(plumber()) .pipe(imagemin({ progressive: true, svgoPlugins: [{removeViewBox: false}], use: [pngquant()], interlaced: true })) .pipe(gulp.dest(path.dist.img)) .pipe(reload()); done(); }); gulp.task('sprite:dist', function(done) { var spriteData = gulp.src(path.app.sprite) .pipe(plumber()) .pipe(spritesmith({ imgName: 'sprite.png', cssName: '_sprite.scss', cssFormat: 'scss', algorithm: 'binary-tree', cssTemplate: path.spriteTemplate, cssVarMap: function(sprite) { sprite.name = 's-' + sprite.name } })); spriteData.img.pipe(gulp.dest(path.export.img)); spriteData.css.pipe(gulp.dest(path.export.style)); done(); }); gulp.task('fonts:dist', function(done) { gulp.src(path.app.fonts) .pipe(plumber()) .pipe(gulp.dest(path.dist.fonts)) done(); }); gulp.task('dist', gulp.parallel( 'html:dist', 'php:dist', 'js:dist', 'sprite:dist', 'style:dist', 'fonts:dist', 'image:dist' )); gulp.task('watch', function() { gulp.watch(path.watch.html, gulp.series('html:dist')); gulp.watch(path.watch.php, gulp.series('php:dist')); gulp.watch(path.watch.style, gulp.series('style:dist')); gulp.watch(path.watch.js, gulp.series('js:dist')); gulp.watch(path.watch.sprite, gulp.series('sprite:dist')); gulp.watch(path.watch.fonts, gulp.series('fonts:dist')); }); gulp.task('default', gulp.parallel('dist', 'webserver', 'watch')); Поскольку некоторые задачи могут содержать асинхронный код, вы должны сигнализировать gulp, когда ваша задача завершит выполнение. В Gulp 3 версий вы могли не делать этого. Если вы не указали явно асинхронное завершение, gulp просто предположил бы, что ваша задача является синхронной и что она завершена, как только ваша задача завершится. В Gulp 4 был внедрен более строгий режим в этом отношении. Вы должны явно сигнализировать о завершении задачи. Это можно сделать пятью разными способами, о которых подробно описано в следующем ответе: Gulp error: The following tasks did not complete: Did you forget to signal async completion? Самый простой способ - это вызвать функцию обратного вызова, которую Gulp автоматически передает вашей задаче в качестве первого аргумента. Нужно просто вызвать эту функцию в конце задачи (внес правку в ответ, в параметрах добавлена колбэк функция done).

Ответ 2



Ответ Denis Bubnov актуальный, но я хочу предоставить свой конечный вариант. Отдельное спасибо Max Manchak, так как он в комментариях предоставил работающий код, и помог довести (до совершенства) конечный ответ. 'use strict'; var gulp = require('gulp'), watch = require('gulp-watch'), plumber = require('gulp-plumber'), prefixer = require('gulp-autoprefixer'), babel = require('gulp-babel'), terser = require('gulp-terser'), //альтернатива gulp-uglifyes sass = require('gulp-sass'), sourcemaps = require('gulp-sourcemaps'), fileinclude = require('gulp-file-include'), cssmin = require('gulp-minify-css'), imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant'), rimraf = require('rimraf'), browserSync = require("browser-sync"), rename = require('gulp-rename'), spritesmith = require('gulp.spritesmith'), reload = browserSync.stream; var path = { dist: { html: 'dist/', php: 'dist/', js: 'dist/js/', css: 'dist/css/', img: 'dist/img/', fonts: 'dist/fonts/', videos: 'dist/videos/', files: 'dist/files/' }, app: { html: 'app/*.html', php: 'app/*.php', js: 'app/js/main.js', jsInit: 'app/js/init.js', style: 'app/scss/main.scss', img: 'app/img/*.*', sprite: 'app/img/sprite/**/*.*', fonts: 'app/fonts/**/*.*', videos: 'app/videos/*.*', files: 'app/files/*.*' }, watch: { html: 'app/**/*.html', php: 'app/*.php', js: 'app/js/**/*.js', style: 'app/scss/**/*.scss', img: 'app/img/*.*', sprite: 'app/img/sprite/**/*.*', fonts: 'app/fonts/**/*.*', videos: 'app/videos/*.*', files: 'app/files/*.*' }, export: { img: 'app/img/', style: 'app/scss/imports/' }, spriteTemplate: 'sass.template.mustache', clean: './dist' }; var config = { server: { baseDir: "dist" // or ./dist }, // tunnel: true, // host: "178.150.110.97", // notify: false, logPrefix: "Frontend_Devil" }; gulp.task('webserver', function(cb) { browserSync(config); cb(); }); gulp.task('clean', function(cb) { rimraf(path.clean, cb); }); gulp.task('html:dist', function(cb) { gulp.src(path.app.html) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.html)) .pipe(reload()); cb(); }); gulp.task('php:dist', function(cb) { gulp.src(path.app.php) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.php)) .pipe(reload()); cb(); }); gulp.task('js:dist', function(cb) { //init.js //Файл для инициации // gulp.src(path.app.jsInit) // .pipe(plumber()) // .pipe(sourcemaps.init()) // .pipe(fileinclude({ // prefix: '@@', // basepath: '@file' // })) // .pipe(babel({ // presets: ["@babel/preset-env"] // })) // .pipe(terser()) // .pipe(sourcemaps.write()) // .pipe(rename({suffix: '.babel-min', prefix : ''})) // .pipe(gulp.dest(path.dist.js)) //Обычный js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)); gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(rename({ suffix: '.babel', prefix: '' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Mini-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(terser()) //альтернатива uglifyes .pipe(sourcemaps.write()) .pipe(rename({ suffix: '.min', prefix: '' })) .pipe(gulp.dest(path.dist.js)); //Babel-mini-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(terser()) .pipe(sourcemaps.write()) .pipe(rename({ suffix: '.babel-min', prefix: '' })) .pipe(gulp.dest(path.dist.js)) .pipe(reload()); cb(); }); gulp.task('style:dist', function(cb) { gulp.src(path.app.style) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(sass({ sourceMap: true, errLogToConsole: true })) .pipe(prefixer()) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.css)) .pipe(cssmin()) .pipe(sourcemaps.write()) .pipe(rename({ suffix: '.min', prefix: '' })) .pipe(gulp.dest(path.dist.css)) .pipe(reload()); cb(); }); gulp.task('image:dist', function(cb) { gulp.src(path.app.img) .pipe(plumber()) .pipe(imagemin({ progressive: true, svgoPlugins: [{ removeViewBox: false }], use: [pngquant()], interlaced: true })) .pipe(gulp.dest(path.dist.img)) .pipe(reload()); cb(); }); gulp.task('sprite:dist', function(cb) { var spriteData = gulp.src(path.app.sprite) .pipe(plumber()) .pipe(spritesmith({ imgName: 'sprite.png', cssName: '_sprite.scss', cssFormat: 'scss', algorithm: 'binary-tree', cssTemplate: path.spriteTemplate, cssVarMap: function (sprite) { sprite.name = 's-' + sprite.name } })); spriteData.img.pipe(gulp.dest(path.export.img)); spriteData.css.pipe(gulp.dest(path.export.style)); reload(); cb(); }); gulp.task('fonts:dist', function(cb) { gulp.src(path.app.fonts) .pipe(plumber()) .pipe(gulp.dest(path.dist.fonts)) .pipe(reload()); cb(); }); gulp.task('videos:dist', function(cb) { gulp.src(path.app.videos) .pipe(plumber()) .pipe(gulp.dest(path.dist.videos)) .pipe(reload()); cb(); }); gulp.task('files:dist', function(cb) { gulp.src(path.app.files) .pipe(plumber()) .pipe(gulp.dest(path.dist.files)) .pipe(reload()); cb(); }); gulp.task('dist', gulp.parallel( 'html:dist', 'php:dist', 'js:dist', 'style:dist', 'image:dist', 'sprite:dist', 'fonts:dist', 'videos:dist', 'files:dist' )); gulp.task('watch', function() { gulp.watch(path.watch.html, gulp.series('html:dist')); gulp.watch(path.watch.php, gulp.series('php:dist')); gulp.watch(path.watch.js, gulp.series('js:dist')); gulp.watch(path.watch.style, gulp.series('style:dist')); gulp.watch(path.watch.img, gulp.series('image:dist')); gulp.watch(path.watch.sprite, gulp.series('sprite:dist')); gulp.watch(path.watch.fonts, gulp.series('fonts:dist')); gulp.watch(path.watch.videos, gulp.series('videos:dist')); gulp.watch(path.watch.files, gulp.series('files:dist')); }); gulp.task('default', gulp.parallel('dist', 'webserver', 'watch'));

Ответ 3



При переходе с gulp 3 на gulp 4 есть в принципе 2 проблемы, первая вроде как очевидная при первых попытка поиска решения проблемы: вместо массива с названиями тасков использовать метод gulp.parallel или gulp.series - между ними разница лишь в том, что метод .parallel запускает таски параллельно друг с другом, а вот метод .series не начинает выполнение второго таска указанного в нем до того как закончится первый... итого можно использовать метод .parallel везде если нет строгой зависимости в чередности выполнения тасков переданных данному методу. было: gulp.task('default', ['dist', 'webserver', 'watch']); стало: `gulp.task('default', gulp.parallel('dist', 'webserver', 'watch'));` Вторая же проблема не такая очевидная, т.к. всё зависит от того как ранее настраивали gulpfile. дело в том что таски в gulp представляют из себя поток, и если не "сказать" gulp, что поток завершен, то может вылезть ошибка. Чтобы сообщить gulp что вызванный таск завершился есть 2 способа: 1) передать в параметры функции некий параметр (назовём его callback) и после выполнения всех действий вызвать этот параметр; 2) воспользоваться return для действий в таске. на примере было: `gulp.task('html:dist', function() { gulp.src(path.app.html) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.html)) .pipe(reload()); });` закроем поток таска использовав return: `gulp.task('html:dist', function() { return gulp.src(path.app.html) .pipe(plumber()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(gulp.dest(path.dist.html)) .pipe(reload()); });` предыдущий способ хорош, НО мы можем наблюдать в данном проекте таск js:dist, где мы не можем использовать return так как в таком случае прервется выполнение таска после выполнения первой задачи (т.к. return возвращает результат выполнения и дальше функция не выполняется): `gulp.task('js:dist', function() { gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Babel-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(rename({ suffix: '.babel', prefix: '' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //..... и далее другие задачи таска });` И вот в этом случае лучшим решением будет передать в параметры функции callback и вызвать его после всех необходимых нам действий: `gulp.task('js:dist', function(callback) { gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //Babel-js файл. gulp.src(path.app.js) .pipe(plumber()) .pipe(sourcemaps.init()) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(babel({ presets: ["@babel/preset-env"] })) .pipe(rename({ suffix: '.babel', prefix: '' })) .pipe(sourcemaps.write()) .pipe(gulp.dest(path.dist.js)) //..... и далее другие задачи таска callback(); });`

среда, 1 января 2020 г.

В чем смысл разделения js и css файлов в npm-пакетах с компонентами?

#reactjs #webpack #npm


Разрабатываем npm пакет с компонентами для react, чтобы их переиспользовать в других
проектах и на этапе создания конфигурации для билда возник данный вопрос.

Если посмотреть на аналоги semantic ui, bootstrap, material ui, то можно заметить
разные подходы:

Подход#1:

import "package-name/style.min.css" // или же тегом в 
import { Button } from "package-name";


Подход#2:

import { Button } from "package-name";


В первом варианте стили и скрипты представляют собой отдельные файлы, которые по
факту не работают друг без друга. Во втором случае Button является скомпилированным
файлом .js в котором содержатся и его стили и не нуждается в дополнительной загрузке CSS.

Есть ли какая то разница между подходами? В чем плюсы минусы каждого из них?

Спасибо
    


Ответы

Ответ 1



Отдельное подключение CSS позволяет заменить файл стилей на другой. К примеру, пользователь bootstrap может сделать вот так и заменить шрифт на всём сайте: $font-family-sans-serif: My Cool Font, $font-family-sans-serif; @import "bootstrap/scss/bootstrap.scss"; Также подключение CSS в head позволяет стилям загрузиться еще до скриптов - что полезно когда показать контент надо сразу же, а скрипты грузятся долго. В то же время, второй способ позволяет использовать независимую стилизацию для разных компонентов, при которой одни компоненты гарантированно не будут перекрывать своими стилями стили других компонентов. Смотрите технологии Styled Components, Css Modules и Shadow DOM (Web Components, Shadow Css).

понедельник, 30 декабря 2019 г.

Много папок в node_modules , причина в Gulp или npm

#gulp #npm


При установки какого либо пакета, например gulp-sass , в папке node_modules возникает
много папок. Раньше такого у меня не было, не могу понять в чем причина. Неужели это
новый npm так работает? 
    


Ответы

Ответ 1



В июне прошлого года вышла 3-я версия npm. Одним из её ключевых нововведений является плоская структура каталогов - зависимости практически всех пакетов теперь устанавливаются в корень папки node_modules. Внутрь же папок самих пакетов, они попадают только при наличии конфликтов. Данное нововведение прежде всего резко сокращает дублирование, снижая затраты ресурсов на хранение и исполнение кода нескольких одинаковых пакетов внутри проекта.

вторник, 24 декабря 2019 г.

Ошибка в gulp, при формировании sprit'ов

#nodejs #gulp #npm #sprite #спрайт


Доброго времени суток, при запросе на формировании спрайта возникает ошибка. Собственно
код ниже для формирования. А ошибка "events.js:160 throw er; // Unhadled 'error' event
Error: Streaming not supported
Спасибо

gulp.task('sprite', function () {
var spriteData = gulp.src(config.src + 'images/sprite/*.png')
    .pipe(spritesmith({
        imgName: 'sprite.png',
        cssName: 'Sprite.less',
        cssFormat: 'less',
        padding: 5,
        cssVarMap: function (sprite) {
            sprite.name = 'icon-' + sprite.name;
        },
        imgPath: config.src + 'images/sprite.png'
    }));

spriteData.img
    .pipe(imagemin({
        progressive: true,
        svgoPlugins: [{removeViewBox: false}],
    }))
    .pipe(gulp.dest(config.src + 'images/'));

spriteData.css
    .pipe(gulp.dest(config.src + 'less/'));

return spriteData;


});
    


Ответы

Ответ 1



Вынесите imagemin в отдельный таск, так как этот плагин не может работать с потоком.

воскресенье, 15 декабря 2019 г.

Для чего нужен package-lock.json?

#javascript #nodejs #frontend #npm #package


Доброе время суток.
Я почитал документацию к NPM, почитал форумы, но всё равно до конца не совсем понимаю,
смысловую нагрузку этого файла.

Вот то что описано на npm документации:


  Этот файл предназначен для фиксации в исходных хранилищах и
  предназначен для различных целей:
  
  1) Описывает единственное представление дерева зависимостей, чтобы товарищи
  по команде, разворачивая проект гарантированно
  установил одинаковые зависимости.
  
  2) Предоставьте пользователям возможность «путешествовать во времени» к
  предыдущим состояниям node_modules без фиксации самого каталога.
  
  3) Для облегчения большей видимости изменений в дереве с помощью читаемых
  исходных текстов контроля.
  
  4) И оптимизировать процесс установки, позволяя npm пропускать
  повторяющиеся установленные пакеты.


Вопрос сразу по 1 пункту, ибо у меня package.json и package-lock.json не в гит игноре!
Они комитятся.
И как написано в той же документашке, когда мы делаем npm i, пакетный менеджер устанавливает
зависимости, которые описаны в файле package.json.
И скачав очередную библиотеку мы идем внутрь неё и устанавливаем её зависимости (и
так рекурсивно).
На данном этапе в package-lock.json просто выводится информация какие внутренние
зависимости основных библиотек мы скачали.
Как оно помогает "гарантированно установил одинаковые зависимости" ?

И это всё полностью вытекает из 3 пункта.

Ну и согласен с 4 пунктом, по факту если в node_modules уже есть такой пакет (с той
же версией и хешем), то его устанавливать не будут. НО, опять же эту инфу можно смотреть
не по package-lock.json, а в зависимостях основного пакета, ибо почти у каждой либы
есть внутренний package.json. Т.е нам не нужен промежуточный файл получается.

Верно ли я все понимаю? Пожалуйста, поправьте!
    


Ответы

Ответ 1



Помимо зависимостей, package.json используется так же для определения свойств проекта, описания, информации об авторе и лицензии, сценариев, в то время как package-lock.json используется исключительно для блокировки зависимостей от определенного номера версии. Наличие package-lock.json в проекте не обязательно. Так же для отключение автоматического создания этого файла ты можешь в .npmrc прописать package-lock=false

суббота, 7 декабря 2019 г.

npm: в каких случаях следует использовать @scope?

#nodejs #npm


Я не читал документацию к npm полностью, но среди примеров, которые я видел, @scope
использовался только для обозначения пользователя или организации:

@username/project-name
@orgname/project-name


Хорошо, а какие @scope ещё можно использовать?
Допустим, мы пишем библиотеки, расширяющие фреймворк bootstrap; следует ли все ли
библиотеки объединить в scope с именем @bootstrap, или в данном случае следует использовать
исключительно префиксирование типа boostrap-libname?

Обновление вопроса в связи с конкурсом

Что если имя npm-организации и имя проекта не совпадает? Например, организация @foo
разработала библиотеки @bar и @baz. И какой тогда скоуп надо указывать для библиотек
bar и baz?
    


Ответы

Ответ 1



Вы автор большой либы. У вас есть проект на гитхабе с отдельным именем. Вы разделяете один пакет на более мелкие модули. Вы регаете на npm организацию. Теперь название этой организации и есть ваш скоп. Только члены этой организации могут туда заливать пакеты. Вот так это работает. Очевидные плюсы - никаких name сквоттеров. Внутри вашей орги никто не уведёт красивое имя. Минусы - старые npm клиенты не поддерживают скопы. Вот пример организации https://www.npmjs.com/org/babel

суббота, 30 ноября 2019 г.

Нужно ли коммитать package-lock.json, создаваемый npm?

#nodejs #git #npm


NPM 5 поддерживает deterministic installs, работающий за счет создания файла package-lock.json.

Нужно держать этот файл под сорс контролем?
    


Ответы

Ответ 1



Да, в этом его и смысл, чтоб у каждого кто пользуется репозиторием были одинаковые пакеты.

Ответ 2



"Еще одна вещь, о которой стоит упомянуть: lock-файл точно описывает физическое дерево каталогов в директории node_modules. Преимущество этого заключается в том, что даже если разные разработчики используют разные версии NPM, они все равно должны иметь не только одни и те же версии зависимостей, но и то же самое дерево каталогов. Этим NPM 5 отличается от других пакетных менеджеров, таких как Yarn." ... "lock-файл представляет собой моментальный слепок текущего дерева зависимостей и позволяет воспроизводить сборки между машинами разработчиков. Поэтому рекомендуется добавить его в свою систему контроля версий." © Источник: https://medium.com/devschacht/understanding-lock-files-in-npm-5-4bf615c6cd50

пятница, 29 ноября 2019 г.

В чём отличие npm install --save-dev от --save

#javascript #node.js #npm


В чем заключается отличие команд --save-dev и --save при установке пакета через npm?
    


Ответы

Ответ 1



-S, --save: Пакет будет отображается в ваших dependencies -D, --save-dev: пакет будет отображаться в ваших devDependencies Для более подробной информации смотрите npm-install

Ответ 2



Если указывать флаг --save то при установке пакета, его имя и версия пропишутся в файле package.json в разделе dependencies. Если установить с флагом --save-dev, то имя и версия попадут в раздел devDependencies

Ответ 3



В версии npm 6.5 можно не писать -save или -s , npm сам добавит установленный пакет вам в "dependencies": { }. Из документации https://docs.npmjs.com/cli/install : -P, --save-prod: опять же сохранит в "dependencies": { }. Это ваш код для продакшена, он будет включен в ваш конечный продукт. Добавляйте сюда только те библиотеки, которые будут использованы при работе вашего конечного продукта (вэб страницы например). -D, --save-dev: сохранит пакет в "devDependencies": { }. Это пакеты, которые вы используете в процессе девелопмента, препроцессоры LESS, SASS, валидаторы кода, JShint Slint, препроцессоры JS: Babel. Эти пакеты не будут включены в конечный продукт. -O, --save-optional: пакет будет добавлен в "optionalDependencies": { }. эти пакеты могут быть использованы в работе, но если они будут недоступны или произойдет ошибка при их установке, то npm просто пропустит их и продолжит работу. --no-save: Запрещает сохранять пакет в package.json. +Дополнительные флаги: -E, --save-exact: сохранит версию пакета точно, как указано. -B, --save-bundle: сохранит пакет в "bundleDependencies": { }.

Ответ 4



Если правильно помню, то когда добавляешь -dev , то помимо пакета ставится все, от чего он зависим. Например: bower install jqueryvalidation --save-dev Поставит jqueryvalidation и jquery. т.к. как зависим от нее. если указать без -dev, то jquery поставлена не будет.

понедельник, 25 ноября 2019 г.

Что лучше, 15мб зависимостей или свой велосипед?


При разработке публичного npm пакета часто возникает вопрос, использовать ли существующе
решение, которое тянет с собой чуть-ли не половину всех популярных пакетов с npm, или написать свой велосипед.

Чтобы сузить область, уточню детали. Свой велосипед - это примерно 1000-1500 стро
кода без зависимостей, естественно есть вероятность наделать много багов (но это как повезет). Время на разработку и отладку - день-два. Альтернатива - пакет который отлично решает эту задачу но тащит с собой ~150 вложенных зависимостей на ~15мб. 

Как считаете, что предпочтительнее? И по каким критериям прежде всего решаете, какой сделать выбор в данной ситуации?
    


Ответы

Ответ 1



В разработке ПО есть принцип KISS (keep it simple, stupid — «делай это проще, дурачок») Вполне логичный, в *nix системах очень распространенный. На мой взгляд в общем случае надо работать в соответствии с ним... НО. Нужно трезво оценивать цели и задачи своего решения, и стороннего решения. Если оно создано, поддерживается и развивается известным надежным разработчиком если нужный вам функционал не является в этом решении "побочным". То почему нет? Так же стоит подумать. Набор который тянется: на сколько велик шанс, что он буде крайне полезным в проекте, который использует ваше решение; не будет ли большая вероятность конфликтов с аналогичными решениями (или разница в версиях). Так же важно понять значимость этого функционала в вашем проекте. Возможно вы оди раз напишете эти 1500 строк и хватит на долгие годы, это одно. (тогда этот вариант вполне годен) Другое, если гарантированно эти 1500 строк потребуют и поддержки и развития и, как следствие, сократят доступное время на разработку основного функционала Как пользователь история к месту: попросили меня как-то LAMP на чистую винду поставить Если не ошибаюсь инсталлятор MySQL был написан на .Net. В итоге ради установки ПО котором не нужен NET потребовалось выкачивать сотню мегабайт... Подумайте если велик шанс, что среди пользователей вашего решения большей части вряд ли понадобятся все эти зависимости - значит лучше свой велосипед...

Ответ 2



В мире npm как то принято тянуть побольше зависимостей. И тут выход такой: если это Ваш личный проект, тогда можно делать как нравится. В личных проектах велосипеды - самая правильная вещь (если цель проекта освоить новые технологии). если это проект "на попробовать", "взлетит/не взлетит" (ака стартап) - тогда побольш зависимостей, поменьше своего кода. Нам же идею проверять, инвесторов потенциальных радовать, а не код вылизывать. Потом, возможно, можно будет и переписать. если это проект рабочий (то есть, делается на работе), тогда лучше спросить у менеджера/тимлида/ тому подобное. Если сам тимлид/менеджер, тогда пункты выше. Но тут может оказаться, что юротдел может сказать, что некоторые пакеты имеют "неправильные лицензии" или "сомнительное происхождение" и их придется делать самому. Но тут есть ещё одна штука. Нужно смотреть, а что за зависимости. Мало чего там Может они конфиденциальную информацию собирают и в закрома засылают. И прецеденты уже были. Мне также нравится следующая система. Собираем проект с готовых пакетов, смотрим что бы лицензии у них были "хорошие, с возможностью модификации". А потом, когда проек "похоже работает", начинаем вычищать, переписывая критические участки. К примеру, можн использовать одну мелкую функцию с огромного пакета. Вполне возможно, что есть смысл ее извлечь в отдельный свой пакет. Хотя сейчас набегут хипстеры-оптимизаторы и скажут: "а вдруг завтра понадобиться ещё одна функция? и что извлекать снова? диски сейчас большие, памяти много, процессор пользователь докупит". Но таких нужно игнорировать и пользоваться здравым смыслом.

вторник, 16 июля 2019 г.

npm 2 и 3 версии

Обновил npm до 3 версии и заметил разницу в расположении пакетов. В проекте, раньше к примеру было так, в node_modules, каждая установка создает папку и ставит свои зависимости к себе в node_modules рекурсивно.
node_modules/ ├── autoprefixer-loader ├── babel-core ├── babel-loader ├── css-loader ├── extract-text-webpack-plugin ├── jade ├── jade-loader ├── less ├── less-loader ├── lodash ├── style-loader ├── webpack └── webpack-dev-server
на 3 же версии, все пакеты и зависимости, сыпятся в одну корневую node_modules Это какой то баг или что? как это можно исправить?


Ответ

Это особенность npm 3. Теперь все пакеты (в том числе их зависимости) устанавливаются непосредственно в node_modules. Также изменилась логика работы с peerDependencies. Теперь модули из этого поля не устанавливаются автоматически. npm выведет предупреждение, если один из таких модулей ещё не установлен. Сделано это всё для борьбы с дубликатами.

воскресенье, 7 июля 2019 г.

Сборка с помощью gulp данных из разных директорий

У меня есть подобная структура проекта
./source/ ./source/shop/ ./source/site/
./build/ ./build/shop/ ./build/site/
В source лежат исходники, которые должны после некоторых модфикаций выплевываться в build. За модификации отвечает gulp. Количество подпапок в source (и в build) соотстветвенно может меняться и каждый раз не хочется переписывать конфиг вручную. Поэтому я при помощи nodejs проверяю какие у меня есть папки в ./source/ и формирую примерно вот такой кофиг
config = { source: { shop: { templates: 'path', ... }, site: { templates: 'path', ... } }, build { shop: { templates: 'path', ... }, site: { templates: 'path', ... } } }
У меня задача правильно все это собирать в зависимости от того, что я хочу. И в связи с этим я сталкиваюсь с двумя задачами, к которым не знаю как подойти.
Во-первых, я хочу запускать сборку подобным образом:
# Собирает всё npm run build
# Собирает только необходимый мне модуль npm run build shop
Но я не знаю можно ли так вообще сделать, а если можно, то нужно будет передавать последнюю часть в gulp, а как это делать непонятно.
Во-вторых, не хочется плодить под каждый модуль задачу потому что все это может меняться. Ну то есть вот так не очень:
gulp.task('templates:shop', function() { return gulp.src(config.source.shop) .gulp.dist(config.build.shop) });
Плохо это потому что если я добавлю в source еще один модуль, например blog, то приется лезть в gulpfile.js и package.json и дописывать какой-то код, чтобы новый модуль поддерживался, а этого бы не хотелось. Возможно есть какое-то готовое решение для подобных задач, но я так ничего не смог найти.


Ответ

Я нашел решение, не знаю насколько это хорошо, но это работает. Я приведу примерный код, чтобы можно было понять суть, у меня в проекте все сложнее несколько.
gulpfile.js
// Для работы с файловой системой import fs from 'fs';
// Тут понятно ;-) import gulp from 'gulp';
// Чтобы получать аргументы import { argv } from 'yargs';
// Получаем список модулей const modules = fs.readdirSync('./source').filter(file => { return fs.statSync('./source' + file).isDirectory(); });
// Проверяем есть ли такой модуль и выводим ошибку, если запустили с несуществующим if(argv.module && !~apps.indexOf(argv.module)) { throw new TypeError('Ошибка при билде несуществующего приложения ' + argv.module); }
gulp.task('default', () => { // Пробегаемся по всем модулям modules.forEach(module => { // Если мы билдим не все, а только один модуль и сейчас в массиве пробегаемся не по этому модулю, то выходим, чтобы не сработала команда if( !(argv.module && argv.module === module || !argv.module) ) return;
// Собираем пути, у меня это делает отдельная функция, но идея такая же const srcPath = './source/' + module; const destPath = './build/' + module;
// Запускаем обработчик gulp.src(srcPath) .pipe(gulp.dest(destPath)); }); });
package.json
"scripts": { "build": "babel-node ./node_modules/gulp/bin/gulp.js" }
У меня тут Babel, чтобы работал ES6, но можно и без него в принципе.
Ну и запускается вот так:
# Собирает всё npm run build
# Собирает только необходимый мне модуль npm run build -- --module=site
Команда запуска билда конкретного модуля выглядит не так красиво, как я хотел изначально, но такой вариант меня тоже устроил.