【问题标题】:Long build time in Gulp (Docker) [closed]Gulp(Docker)中的长时间构建时间[关闭]
【发布时间】:2021-10-26 14:15:45
【问题描述】:

我使用 Gulp 的构建时间大约是 90 秒(有时甚至更长),这似乎是非常缓慢的构建时间。我正在使用 Django、Tailwindcss、Gulp、Webpack 和 Docker。我在没有 docker 的情况下尝试了 'npm run dev',花了 41 秒。

在使用 Docker 时如何优化我的 Gulp 配置?

node_1      | ✔ - [Styles] Success!
node_1      | [12:40:43] Finished 'styles' after 49 s
node_1      | [12:40:48] asset index.js 138 KiB [emitted] (name: main) 1 related asset
node_1      |   
node_1      | webpack 5.51.1 compiled successfully
node_1      | ✔ - [Scripts] Success!
node_1      | [12:40:49] Finished 'scripts' after 54 s
node_1      | ✔ - [HTML] Success!
node_1      | [12:40:54] Finished 'html' after 59 s
node_1      | [12:41:10] gulp-imagemin: Minified 1 image (saved 11 B - 0.1%)
node_1      | ✔ - [Images] Success!
node_1      | [12:41:10] Finished 'images' after 1.25 min
node_1      | [12:41:10] Finished 'build' after 1.27 min
node_1      | [12:41:17] Using gulpfile /usr/src/app/gulpfile.mjs
node_1      | [12:41:17] Starting 'watch'...
node_1      | [Browsersync] Proxying: http://localhost:8000
node_1      | [Browsersync] Access URLs:
node_1      |  -----------------------------------
node_1      |        Local: http://localhost:8000
node_1      |     External: http://172.18.0.4:8000
node_1      |  -----------------------------------
node_1      |           UI: http://localhost:3001
node_1      |  UI External: http://localhost:3001
node_1      |  -----------------------------------
node_1      | [Browsersync] Watching files...

gulpfile

/* eslint-disable import/newline-after-import */

import figures from 'figures';
import imagemin, { gifsicle, mozjpeg, optipng, svgo } from 'gulp-imagemin';

import { createRequire } from 'module';
const require = createRequire(import.meta.url);
// "require" is not defined with ES6 module, so we define it this way above.
// Now 'require' can be used in the usual way.
// Use import for ES6 modules and require for commonJS.

const gulp = require('gulp');
const autoprefixer = require('autoprefixer');
const browserSync = require('browser-sync').create();
const gulpAutoprefixer = require('gulp-autoprefixer');
const gulpClean = require('gulp-clean');
const gulpColor = require('gulp-color');
const gulpConcat = require('gulp-concat');
const gulpCssnano = require('gulp-cssnano');
const htmlMinimizer = require('gulp-html-minimizer'); // Minify HTML files
const gulpPostcss = require('gulp-postcss');
const gulpSass = require('gulp-sass')(require('sass'));
const gulpSourcemaps = require('gulp-sourcemaps');
const gulpUtil = require('gulp-util');
const purgeCss = require('@fullhuman/postcss-purgecss');
const tailwindCSS = require('tailwindcss');
const webpack = require('webpack');
const webpackStream = require('webpack-stream');

const isProd = process.env.NODE_ENV === 'production';
const webpackConfig = isProd
  ? require('./webpack.config.prod')
  : require('./webpack.config');

// Config
const options = {
  config: {
    tailwindjs: './tailwind.config.js',
  },
  paths: {
    src: {
      base: './assets',
      html: './templates/local',
      css: './assets/css',
      js: './assets/js',
      img: './assets/img',
    },
    dist: {
      base: './dist',
      html: './templates/local',
      css: './dist/css',
      js: './dist/js',
      img: './dist/img',
    },
    build: {
      base: './config/static',
      html: './templates/production',
      css: './config/static/css',
      js: './config/static/js',
      img: './config/static/img',
    },
  },
};

const logger = (text, symbol = figures.info, color = 'YELLOW') => {
  console.log(gulpColor(`${symbol} - ${text}`, color));
};
const reload = done => {
  setTimeout(() => {
    browserSync.reload();
  }, 1000);
  done();
};

gulp.task('clean', () => {
  logger('[Cleaning] Cleaning old dist..');
  return gulp
    .src(
      isProd
        ? [options.paths.build.base, options.paths.build.html]
        : options.paths.dist.base,
      {
        read: false,
        allowEmpty: true,
      }
    )
    .pipe(gulpClean())
    .on('end', () => logger('[Cleaning] Success!', figures.tick, 'GREEN'))
    .on('error', () => logger('[Cleaning] Failed', figures.cross, 'RED'));
});

// Updated gulp pipe: passing webpack in webpack-stream to avoid this issue:
// https://github.com/webpack-contrib/terser-webpack-plugin/issues/335
gulp.task('scripts', () => {
  logger('[Scripts] Compiling...');
  return gulp
    .src(`${options.paths.src.js}/app.js`)
    .pipe(webpackStream(webpackConfig, webpack))
    .pipe(
      isProd
        ? gulp.dest(options.paths.build.js)
        : gulp.dest(options.paths.dist.js)
    )
    .on('end', () => logger('[Scripts] Success!', figures.tick, 'GREEN'))
    .on('error', () => logger('[Scripts] Failed', figures.cross, 'RED'));
});

gulp.task('styles', () => {
  logger('[Styles] Compiling...');
  return gulp
    .src(`${options.paths.src.css}/**/*.scss`)
    .pipe(gulpSass().on('error', gulpSass.logError))
    .pipe(
      gulpPostcss([
        tailwindCSS(options.config.tailwindjs),
        autoprefixer,
        ...(isProd
          ? [
              purgeCss({
                content: [
                  `${options.paths.src.html}/**/*.{html}`,
                  `${options.paths.src.js}/**/*.{js}`,
                ],
                defaultExtractor: content => {
                  const broadMatches =
                    content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || [];
                  const innerMatches =
                    content.match(/[^<>"'`\s.()]*[^<>"'`\s.():]/g) || [];
                  return broadMatches.concat(innerMatches);
                },
              }),
            ]
          : []),
      ])
    )
    .pipe(gulpAutoprefixer())
    .pipe(isProd ? gulpSourcemaps.init() : gulpUtil.noop())
    .pipe(gulpConcat('style.css'))
    .pipe(isProd ? gulpCssnano() : gulpUtil.noop())
    .pipe(isProd ? gulpSourcemaps.write('.') : gulpUtil.noop())
    .pipe(
      isProd
        ? gulp.dest(options.paths.build.css)
        : gulp.dest(options.paths.dist.css)
    )
    .on('end', () => logger('[Styles] Success!', figures.tick, 'GREEN'))
    .on('error', () => logger('[Styles] Failed', figures.cross, 'RED'));
});

gulp.task('images', () => {
  logger('[Images] Optimizing...');
  return gulp
    .src(`${options.paths.src.img}/**/*.*`)
    .pipe(
      imagemin(
        [
          gifsicle({ interlaced: true }),
          mozjpeg({
            quality: 80,
            progressive: true,
          }),
          optipng({ optimizationLevel: 5 }),
          svgo({ removeViewBox: true, cleanupIDs: false }),
        ],
        {
          silent: false,
        }
      )
    )
    .pipe(
      isProd
        ? gulp.dest(options.paths.build.img)
        : gulp.dest(options.paths.dist.img)
    )
    .on('end', () => logger('[Images] Success!', figures.tick, 'GREEN'))
    .on('error', () => logger('[Images] Failed', figures.cross, 'RED'));
});

gulp.task('html', () => {
  logger('[HTML] Optimizing...');
  return gulp
    .src(`${options.paths.src.html}/**/*.html`)
    .pipe(
      isProd
        ? htmlMinimizer({
            collapseWhitespace: true,
            removeComments: true,
            continueOnParseError: true,
            html5: true,
            // minifyJS: true,
            // minifyCSS: true,
          })
        : gulpUtil.noop()
    )
    .pipe(
      isProd
        ? gulp.dest(options.paths.build.html)
        : gulp.dest(options.paths.dist.html)
    )
    .on('end', () => logger('[HTML] Success!', figures.tick, 'GREEN'))
    .on('error', () => logger('[HTML] Failed', figures.cross, 'RED'));
});

gulp.task('watch', () => {
  browserSync.init({
    // The hostname is the name of your service in docker-compose.yml.
    // The port is what's defined in your Dockerfile.
    hostname: 'django',
    port: 8000,
    proxy: 'localhost:8000',
    open: false,
    files: ['./dist', './templates/local'],
  });

  gulp
    .watch(`${options.paths.src.js}/**/*.*`, gulp.series('scripts'))
    .on('change', reload);
  gulp
    .watch(`${options.paths.src.css}/**/*.*`, gulp.series('styles'))
    .on('change', reload);
  gulp
    .watch(`${options.paths.src.img}/**/*.*`, gulp.series('images'))
    .on('change', reload);
  gulp
    .watch(`${options.paths.src.html}/**/*.*`, gulp.series('html'))
    .on('change', reload);
});

gulp.task(
  'build',
  gulp.series('clean', gulp.parallel('scripts', 'styles', 'images', 'html'))
);


webpack.config.js

module.exports = {
  mode: 'development',
  entry: ['./assets/js/app.js'],
  output: {
    // eslint-disable-next-line no-path-concat
    path: `${__dirname}/dist/js`,
    filename: 'index.js',
  },
  devtool: false,
  module: {
    rules: [
      {
        test: /\.js$/,
        resolve: {
          fullySpecified: false,
        },
        exclude: /node_modules\/(?!app-js)/,
        use: {
          loader: 'babel-loader',
        },
      },
    ],
  },
};

Dockerfile

FROM node:12.22-buster-slim

RUN npm i npm@latest -g

WORKDIR /usr/src

COPY ./app/package*.json ./

RUN apt-get update && apt-get install -y --no-install-recommends \
    autoconf \
    automake \
    g++ \
    libpng-dev \
    make\
    nasm \
    -y wget \
    && wget -q -O /tmp/libpng12.deb http://mirrors.kernel.org/ubuntu/pool/main/libp/libpng/libpng12-0_1.2.54-1ubuntu1_amd64.deb \
    && dpkg -i /tmp/libpng12.deb \
    && rm /tmp/libpng12.deb \
    && npm install --no-optional && npm cache clean --force \
    npm install -g gulp \
    && npm install gulp

ENV PATH /usr/src/node_modules/.bin/:$PATH

WORKDIR /usr/src/app

COPY . .

docker-compose.yml

version: '3'

volumes:
  local_postgres_data: {}
  local_postgres_data_backups: {}
  notused:

services:
  postgres:
    build:
      context: .
      dockerfile: ./app/docker/postgres/Dockerfile
    image: webapp_prodcution_postgres
    volumes:
      - local_postgres_data:/var/lib/postgresql/data:Z
      - local_postgres_data_backups:/backups:z
    env_file:
      - ./app/.envs/.local/.env

  django:
    image: webapp_local_django
    build:
      context: .
      dockerfile: ./app/docker/django/Dockerfile
    volumes:
      - ./app/:/usr/src/app/
    command: /usr/src/app/docker/django/start_dev
    ports:
      - 8000:8000
    env_file:
      - ./app/.envs/.local/.env
    depends_on:
      - postgres

  node:
    image: webapp_local_node
    build:
      context: .
      dockerfile: ./app/docker/node/Dockerfile
    depends_on:
      - django
    volumes:
      - ./app/:/usr/src/app/
      - notused:/usr/src/app/node_modules/
    command: bash -c "rm -rf /usr/src/app/node_modules/* && npm run dev"
    ports:
      - '3000:3000'

package.json

{
  "private": true,
  "main": "gulpfile.mjs",
  "scripts": {
    "dev": "gulp build && gulp watch",
    "build": "cross-env NODE_ENV=production gulp build",
    "preinstall": "npx npm-force-resolutions"
  },
  "devDependencies": {
    "@babel/core": "^7.15.0",
    "@babel/eslint-parser": "^7.15.0",
    "@babel/preset-env": "^7.15.0",
    "@fullhuman/postcss-purgecss": "^4.0.3",
    "@tailwindcss/aspect-ratio": "^0.2.1",
    "@tailwindcss/forms": "^0.3.3",
    "autoprefixer": "^10.3.1",
    "babel-loader": "^8.2.2",
    "browser-sync": "^2.27.5",
    "cross-env": "^7.0.3",
    "eslint": "^7.32.0",
    "eslint-config-airbnb-base": "^14.2.1",
    "eslint-config-node": "^4.1.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-import": "^2.24.0",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-prettier": "^3.4.0",
    "figures": "^4.0.0",
    "gulp": "^4.0.2",
    "gulp-autoprefixer": "^8.0.0",
    "gulp-babel": "^8.0.0",
    "gulp-clean": "^0.4.0",
    "gulp-cli": "^2.3.0",
    "gulp-color": "0.0.2",
    "gulp-concat": "^2.6.1",
    "gulp-cssnano": "^2.1.3",
    "gulp-html-minimizer": "^2.0.1",
    "gulp-imagemin": "^8.0.0",
    "gulp-postcss": "^9.0.0",
    "gulp-sass": "^5.0.0",
    "gulp-sourcemaps": "^3.0.0",
    "gulp-util": "^3.0.8",
    "postcss": "^8.3.6",
    "prettier": "^2.3.2",
    "sass": "^1.37.5",
    "tailwindcss": "^2.2.7",
    "webpack": "^5.50.0",
    "webpack-stream": "^6.1.2"
  },
  "dependencies": {
    "alpinejs": "^3.2.4",
    "aos": "^3.0.0-beta.6",
    "focus-handling": "^1.0.0",
    "sticky-js": "^1.3.0"
  },
  "engines": {
    "node": ">=12.22"
  },
  "resolutions": {
    "glob-parent": "6.0.1",
    "trim-newlines": "4.0.2",
    "yargs-parser": "20.2.9",
    "js-yaml": "4.1.0"
  }
}

【问题讨论】:

  • 你能展示一下你的 Dockerfile 是什么样子的吗?
  • @Stefano 我更新了我的问题并添加了有关 Docker 的更多信息。

标签: node.js docker webpack gulp


【解决方案1】:

从 docker 的角度来看,您可以改进缓存的使用方式。我不认为你发布的内容是完整的,反正我会使用可用的。

我会这样重写:

FROM node:12.22-buster-slim

RUN npm i npm@latest -g \
    && npm install -g gulp

RUN apt-get update && apt-get install -y --no-install-recommends \
    autoconf \
    automake \
    g++ \
    libpng-dev \
    make\
    nasm \
    -y wget \
    && wget -q -O /tmp/libpng12.deb http://mirrors.kernel.org/ubuntu/pool/main/libp/libpng/libpng12-0_1.2.54-1ubuntu1_amd64.deb \
    && dpkg -i /tmp/libpng12.deb \
    && rm /tmp/libpng12.deb

WORKDIR /usr/src

COPY ./app/package*.json ./

RUN npm ci

ENV PATH /usr/src/node_modules/.bin/:$PATH

WORKDIR /usr/src/app

COPY . .

下一步将改进 package.json 文件并添加几个脚本以避免多次安装 gulp。 (我假设您这样做的原因是因为 docker 容器如果仅安装在项目中就找不到它)。

【讨论】:

  • 谢谢!我还添加了我的 package.json。你能检查一下吗?
猜你喜欢
  • 1970-01-01
  • 2019-03-25
  • 1970-01-01
  • 2021-09-06
  • 2020-07-11
  • 2018-01-27
  • 1970-01-01
  • 2014-12-18
  • 2020-08-21
相关资源
最近更新 更多