webpack4 正確的配置方式

原文轉載於 www.rails365.netjavascript

原文: A tale of Webpack 4 and how to finally configure it in the right waycss

基本構建

開始新的項目html

mkdir webpack-4-tutorial
cd webpack-4-tutorial

npm init
複製代碼

上下會初始化一個項目,接下來添加webpack4.java

npm install webpack webpack-cli --save-dev
複製代碼

肯定裝的webpack版本是4.node

接下來修改package.jsonwebpack

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack"
 },
複製代碼

保存以後,npm run dev會出現一個錯誤.git

Insufficient number of arguments or no entry found.
Alternatively, run 'webpack(-cli) --help' for usage info.

Hash: 4442e3d9b2e071bd19f6
Version: webpack 4.12.0
Time: 62ms
Built at: 2018-06-22 14:44:34

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

ERROR in Entry module not found: Error: Can't resolve './src' in '~/workspace/webpack-4-tutorial'
複製代碼

兩個問題,第一個出錯的意思是說,沒有設置mode,默認會認爲是production模式。第二個是說src下沒有找到入口模塊。es6

咱們來改下,再次打開package.jsongithub

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack --mode development"
  },
複製代碼

在項目下新建src文件夾,而後src下新建index.js.web

console.log(「hello, world」);
複製代碼

保存後再次運行npm run dev.

這時候成功打包,發現項目裏多了一個dist文件夾. 這是由於webpack4是號稱0配置,因此不少東西都給你配置好了,好比默認的入口文件,默認的輸出文件。 在webpack中配置環境,基本都是兩個配置文件(development, production).在webpack4中,有這兩個模式來區分。

"scripts": {
  "dev": "webpack --mode development",
  "build": "webpack --mode production"
}
複製代碼

保存後運行npm run build,你會發現main.js文件小了不少。

上面不少東西都是經過默認配置來的,嘗試去重寫配置,在不使用配置文件的狀況下。

"scripts": {
     "dev": "webpack --mode development ./src/index.js --output ./dist/main.js",
   "build": "webpack --mode production ./src/index.js --output ./dist/main.js"
 },

複製代碼

編譯轉換你的代碼

es6就是將來,但是如今的瀏覽器對他的支持不是很好,咱們須要babel來轉換他。

npm install babel-core babel-loader babel-preset-env --save-dev
複製代碼

bable的配置,須要建立一個文件去配置。 新建.babelrc文件,寫入以下內容

{
  "presets": [
    "env"
  ]
}
複製代碼

接下來須要配置babel-loader,能夠在package.json文件配置,可是仍是獨立出去好,比較好維護。項目下新建一個webpack.config.js.加入一些基礎配置。

// webpack v4
const path = require('path');
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  }
};
複製代碼

而後package.json的腳本能夠去除一些配置.

"scripts": {
    "dev": "webpack --mode development",
  "build": "webpack --mode production"
  },
複製代碼

而後再運行編譯,也是能夠正常編譯。

Html && Css

dist文件夾下新建一個index.html的文件.

<html>
  <head>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div>Hello, world!</div>
    <script src="main.js"></script>
  </body>
</html>
複製代碼

上面這段代碼,使用到了style.css. 接來下去處理css的問題. src文件夾下新建style.css

div {
  color: red;
}
複製代碼

而後在js文件中引入css.,打開index.js文件

import "./style.css";
console.log("hello, world");
複製代碼

解析來咱們就須要配置css的規則,打開webpack.config.js

// webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); //新加入

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader']
          })
      }// 新加的css 規則
    ]
  }
};

複製代碼

上面咱們用了一些插件和加載器.須要去安裝.

npm install extract-text-webpack-plugin --save-dev
npm install style-loader css-loader --save-dev
複製代碼

上面咱們提出css來編譯,你能夠看到他的規則, 規則能夠這樣認爲

{
        test: /\.拓展名$/,
        exclude: /不須要執行的文件夾/,
        use: {
          loader: "你的加載器"
        }
}
複製代碼

咱們須要extract-text-webpack-plugin這個提取插件,由於webpack只會辨別js.這裏須要經過ExtractTextPlugin獲取css文本進行壓縮。

咱們再次嘗試編譯,npm run dev發現會有報錯,這個是由於這個提取器在新版本的緣由。相關報錯Webpack 4 compatibility 能夠解決這個問題,那就是換個版本。

npm install -D extract-text-webpack-plugin@next
複製代碼

而後再編譯,發現能夠來,同時再dist下有一個style.css文件。

這時候package.json的依賴文件以下

"devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.4",
    "babel-preset-env": "^1.6.1",
    "css-loader": "^0.28.11",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "style-loader": "^0.20.3",
    "webpack": "^4.4.1",
    "webpack-cli": "^2.0.12"
  }
複製代碼

下面咱們來配置支持scss

npm install node-sass sass-loader --save-dev
複製代碼

咱們在src下新建一個index.html

<html>
  <head>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div>Hello, world!</div>
    <script src="main.js"></script>
  </body>
</html>
複製代碼

安裝html插件

npm install html-webpack-plugin --save-dev
複製代碼

安裝完成以後來修改webpack.config.js

// webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');// 新加

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader']
          })
      }// 新加
    ]
  },
  plugins: [
    new ExtractTextPlugin({filename: 'style.css'}),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    })// 新加

  ]
};

複製代碼

這個是最終的html的一個模版. 如今html,css,js基本配置的差很少,咱們刪除dist來試試。

rm -rf dist/
npm run dev
複製代碼

這時候會發現dist下存在js,css,html文件.

緩存

能夠查看關於hash緩存的文檔來使瀏覽器只請求改變的文件.

webpack4提供了chunkhash來處理。

來看看:

// webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');// 新加

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js' //changed
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader']
          })
      }// 新加
    ]
  },
  plugins: [
    new ExtractTextPlugin(
      {filename: 'style.[chunkhash].css', disable: false, allChunks: true}
    ), //changed
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    })

  ]
};

複製代碼

而後src下的html也要修改

<html>
  <head>
    <link rel="stylesheet" href="<%=htmlWebpackPlugin.files.chunks.main.css %>">
  </head>
  <body>
    <div>Hello, world!</div>
    <script src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>
  </body>
</html>
複製代碼

能夠發現這裏改變來,這個是使模版使用hash.

好了,如今能夠編譯,會發現dist下的css和js名字是帶有hash指的。

緩存帶來的問題,如何解決

若是咱們改變代碼,在編譯的時候,發現並無生成創新的hash名文件。

div {
  color: 'red';
  background-color: 'blue';
}
複製代碼

再次進行編譯npm run dev,發現並無生產新的hash文件名稱,可是若是改變js代碼,再次編譯,會發現是改變了hash名稱

import "./index.css"
console.log('Hello, world!');
複製代碼

如何解決?

兩種辦法:

  • 方法1 把css提取器中的[chunkhash]換成[hash].可是這個會與webpack4.3中的contenthash有衝突.能夠結合webpack-md5-hash一塊兒使用。

npm install webpack-md5-hash --save-dev

// webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash'); //新加
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader']
          })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin(
      {filename: 'style.[hash].css', disable: false, allChunks: true}
    ),//changed
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash() //新加

  ]
};

複製代碼

而後編譯查看是否改變。 如今的變化是,改變css文件,那麼css文件的hash名字改變。若是改變js文件,那麼css和js的壓縮hash名稱都將改變。

  • 方法2(推薦)

方法1可能還會存在其餘的衝突,因此來嘗試下mini-css-extract-plugin

這個插件是爲了取代extract-plugin, 並帶來兼容性的改變

npm install --save-dev mini-css-extract-plugin

嘗試使用

// webpack v4
const path = require('path');
// const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//新加

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      // {
      // test: /\.css$/,
      // use: ExtractTextPlugin.extract(
      // {
      // fallback: 'style-loader',
      // use: ['css-loader']
      // })
      // }
      {
        test: /\.(scss|css)$/,
        use:  [  'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
      } // 新加
    ]
  },
  plugins: [
    // new ExtractTextPlugin(
    // {filename: 'style.[hash].css', disable: false, allChunks: true}
    // ),
    new MiniCssExtractPlugin({
      filename: 'style.[contenthash].css',
    }),//新加
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash()

  ]
};

複製代碼

好了,接下來咱們嘗試改變文件會怎麼變化。 改變css,進行編譯發現只有css的文件改變來。改變js文件,發現編譯以後只有js的hash名稱改變,不錯,就是這樣。

繼承PostCss

postcss你們應該不會陌生了。

npm install postcss-loader --save-dev
npm i -D autoprefixer
複製代碼

-D.

建立postcss.config.js

module.exports = {
    plugins: [
      require('autoprefixer')
    ]
}
複製代碼

而後來配置你的webpack.config.js

// webpack v4
const path = require('path');
// const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.(scss|css)$/,
        use:  [  'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']//changed
      }
    ]
  },
  plugins: [
    // new ExtractTextPlugin(
    // {filename: 'style.[hash].css', disable: false, allChunks: true}
    // ),
    new MiniCssExtractPlugin({
      filename: 'style.[contenthash].css',
    }),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash()

  ]
};

複製代碼

保持dist整潔

這裏使用clean-webpack-plugin插件.

npm i clean-webpack-plugin --save-dev

// webpack v4
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');//新加

module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.(scss|css)$/,
        use:  [  'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']//changed
      }
    ]
  },
  plugins: [
    // new ExtractTextPlugin(
    // {filename: 'style.[hash].css', disable: false, allChunks: true}
    // ),
    new CleanWebpackPlugin('dist', {} ),//新加
    new MiniCssExtractPlugin({
      filename: 'style.[contenthash].css',
    }),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash()

  ]
};

複製代碼

這樣每次編譯的時候,就會清空dist文件夾

最終代碼

相關文章
相關標籤/搜索