johnagan / clean-webpack-plugin

A webpack plugin to remove your build folder(s) before building
MIT License
1.96k stars 135 forks source link

Prevent files created by other plugins from being removed upon rebuild #175

Open RyanEwen opened 4 years ago

RyanEwen commented 4 years ago

Issue description or question

How can I prevent files built by other plugins from being removed on rebuild of unrelated files, without having to explicitly list those files?

Webpack Config

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlWebpackPartialsPlugin = require('html-webpack-partials-plugin')

const clientConfig = {
    mode: 'development',
    target: 'web',
    entry: {
        App: './src/client/index.js'
    },
    output: {
        filename: '[name].bundle.js',
        path: path.join(__dirname, 'dist', 'client')
    },
    devtool: false,
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'Customer Gateway',
        }),
        new HtmlWebpackPartialsPlugin({
            path: path.join(__dirname, 'src', 'client', 'body.html')
        }),
    ],
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                loaders: ['babel-loader']
            },
        ]
    },
}

module.exports = [clientConfig]

When I edit a JS file, the dist folder is cleared, but my index.html file is not recreated since nothing about it needed to change. Is there a way to prevent this from happening without explicitly listing index.html as a file to exclude? Can the clean plugin tell what was rebuilt and only delete those files?

RyanEwen commented 4 years ago

cleanStaleWebpackAssets: false seems to help, however I wouldn't consider index.html from html-webpack-plugin to be stale

RyanEwen commented 4 years ago

I think the reason this issue isn't more common is likely becuase most people are using hash: true with the html plugin. I'm going to use that in favor of the workaround in my previous post, since I need the hash feature anyway.

josephspurrier commented 4 years ago

My index.html file gets removed after a bunch of changes. I'm forced to restart webpack:

image

Here is my webpack.config.js:

/* eslint-disable @typescript-eslint/no-var-requires */
const { resolve } = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");

// Try the environment variable, otherwise use root.
const ASSET_PATH = process.env.ASSET_PATH || "/";

module.exports = {
  entry: "./src/index.ts",
  plugins: [
    new CleanWebpackPlugin({
      verbose: true,
    }),
    new HtmlWebpackPlugin({
      filename: "./index.html",
      title: "gomithrilapp",
    }),
    new MiniCssExtractPlugin({
      filename: "static/[name].[contenthash].css",
    }),
    new CopyWebpackPlugin(
      [
        { from: "./static/healthcheck.html", to: "static/" },
        { from: "./static/swagger.json", to: "static/" },
      ],
      { copyUnmodified: true }
    ),
  ],
  resolve: {
    extensions: [".tsx", ".ts", ".js"],
    alias: {
      "@": resolve(__dirname, "./src"),
      "~": resolve(__dirname),
    },
  },
  output: {
    path: resolve(__dirname, "./dist"),
    filename: "static/[name].[contenthash].js",
    publicPath: ASSET_PATH,
  },
  optimization: {
    splitChunks: {
      chunks: "all",
    },
  },
  // Enable sourcemaps for debugging webpack's output.
  devtool: "source-map",
  performance: {
    hints: false,
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: "ts-loader",
        exclude: /node_modules/,
      },
      {
        enforce: "pre",
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "eslint-loader",
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader",
      },
      // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
      {
        enforce: "pre",
        test: /\.js$/,
        loader: "source-map-loader",
      },
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
          },
          {
            loader: "sass-loader",
            options: {
              sourceMap: true,
            },
          },
        ],
      },
    ],
  },
};

And my package.json:

{
  "name": "gomithriltsapp",
  "version": "1.0.0",
  "description": "A sample notepad application in Mithril and Go.",
  "main": "gomithriltsapp",
  "scripts": {
    "start": "webpack -d --watch",
    "build": "webpack -p",
    "lint": "eslint --ext .js --ignore-path .gitignore .",
    "test": "cypress run",
    "test-debug": "DEBUG=cypress:* cypress run",
    "cypress": "cypress open",
    "storybook": "start-storybook -p 9090 -s .storybook/static"
  },
  "repository": {
    "type": "git",
    "url": "git://github.com/josephspurrier/gomithriltsapp.git"
  },
  "author": "Joseph Spurrier",
  "license": "MIT",
  "dependencies": {},
  "devDependencies": {
    "@babel/core": "^7.10.4",
    "@babel/plugin-transform-react-jsx": "^7.10.4",
    "@babel/preset-env": "^7.10.4",
    "@babel/register": "^7.10.4",
    "@cypress/webpack-preprocessor": "^4.1.5",
    "@fortawesome/fontawesome-free": "^5.13.1",
    "@storybook/addon-a11y": "^5.3.19",
    "@storybook/addon-actions": "^5.3.19",
    "@storybook/addon-console": "^1.2.1",
    "@storybook/addon-knobs": "^5.3.19",
    "@storybook/addon-storysource": "^5.3.19",
    "@storybook/mithril": "^5.3.19",
    "@types/js-cookie": "^2.2.6",
    "@types/mithril": "^2.0.3",
    "@typescript-eslint/eslint-plugin": "^3.6.0",
    "@typescript-eslint/parser": "^3.6.0",
    "babel-loader": "^8.1.0",
    "bulma": "^0.8.2",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^5.1.1",
    "css-loader": "^3.6.0",
    "cypress": "^4.11.0",
    "eslint": "^6.8.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-loader": "^3.0.4",
    "eslint-plugin-mithril": "^0.1.1",
    "eslint-plugin-prettier": "^3.1.4",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "html-webpack-plugin": "^4.3.0",
    "js-cookie": "^2.2.1",
    "mini-css-extract-plugin": "^0.9.0",
    "mithril": "^2.0.4",
    "msw": "^0.19.5",
    "node-sass": "^4.14.1",
    "prettier": "^2.0.5",
    "sass-loader": "^8.0.2",
    "source-map-loader": "^1.0.1",
    "style-loader": "^1.2.1",
    "ts-loader": "^8.0.0",
    "typescript": "^3.9.6",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.12"
  }
}
josephspurrier commented 4 years ago

In my example above, all my content files are going to dist/static. Since I was only having the issue with it deleting index.html, I just modified my config so the output path is: resolve(__dirname, "dist/static"). That way, the plugin only cleans up the static folder and not the dist folder where index.html lives.

beardedtim commented 4 years ago

That way, the plugin only cleans up the static folder and not the dist folder where index.html lives.

Ran into the same issue as describe above and the solution above worked. To be specific for future me:

module.exports = {
...webpackConfig,
  output: {
    filename: "[name].[hash].js",
    // Set this to some folder that can be handled via the cleanup
    path: path.resolve(__dirname, '..', "dist", 'client', 'static'),
    publicPath: ASSET_PATH,
  },
  plugins:[
    new HtmlPlugin({
      template: path.resolve(__dirname, 'template.html'),
     // set this to outside of the folder that is handled by the cleanup
      filename: path.resolve(__dirname, '..', 'dist', 'client', 'index.html')
    }),
    new CleanWebpackPlugin({
      verbose: true,
    }),
  ],
}