webpack 4 :從0配置到專案搭建

phoebeCodeSpace發表於2018-07-05

webpack4釋出以來,我寫專案都是用腳手架,即使再簡單的專案,真的是really shame。。雖然道聽途說了很多 webpack4 的特性,卻沒有嘗試過,因為它給人的感覺就是,em...很難。但是今天我從最簡單的部分開始,一點點搭建起一個專案。

0配置,配置了什麼

讓我們從0開始,新建一個專案,在終端執行以下語句:

mkdir webpack-4-quickstart && cd webpack-4-quickstart
npm init -y
npm i webpack --save-dev
npm i webpack-cli --save-dev
複製程式碼

修改程式碼 package.jsonscripts 部分:

"scripts": {
  "build": "webpack"
}
複製程式碼

現在,我們的 package.json 是這樣的:

{
  "name": "webpack-4-quickstart",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
     "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.14.0",
    "webpack-cli": "^3.0.8"
  }
}
複製程式碼

此時,我們執行 npm run build, 會給出以下提示/錯誤:

webpack4-error

  1. error: 沒有入口檔案
  2. warning: 建議設定 mode 選項

entry & output

為了解決第一個問題,我們嘗試新建 src/index.js:

console.log(`I'm a entry point`);
複製程式碼

此時再次執行 npm run build,成功打包出了 dist/main.js,因此我們可以得知:

webpack4 more配置了 entry(入口) src/index.js 和output(出口) dist/main.js

當然,如果你想覆蓋這個配置(比如修改為 ./foo/src/js/index.js),可以在 package.json 修改:

"scripts": {
  "dev": "webpack --mode development ./foo/src/js/index.js --output ./foo/main.js",
  "build": "webpack --mode production ./foo/src/js/index.js --output ./foo/main.js"
}
複製程式碼

production & development

webpack4 之前,我們寫一個專案起碼會設定兩種型別檔案:

  • 用於開發環境的webpack.dev.conf.js,定義 webpack 啟動的伺服器等
  • 用於生產環境的webpack.prod.conf.js,定義UglifyJSPlugin或其他配置等

而 webpack4 的 mode 給出了兩種配置:developmentproduction

我們修改 package.jsonscripts 部分:

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

我們分別執行 npm run devnpm run build

webpack4-mode

執行 npm run dev 打包的是未壓縮的程式碼,而 npm run build 是壓縮後的程式碼。

  • 生產模式下:啟用了 程式碼壓縮、作用域提升(scope hoisting)、 tree-shaking,使程式碼最精簡
  • 開發模式下:相較於更小體積的程式碼,提供的是打包速度上的優化

總結

webpack 4 的零配置主要應用於:

  • entry 預設設定為 ./src/index.js
  • output 預設設定為 ./dist/main.js
  • productiondevelopment 兩種模式

專案搭建

專案搭建,我們對webpack的訴求是:

  • js的處理:轉換 ES6 程式碼,解決瀏覽器相容問題
  • css的處理:編譯css,自動新增字首,抽取css到獨立檔案
  • html的處理:複製並壓縮html檔案
  • dist的清理:打包前清理源目錄檔案
  • assets的處理:靜態資源處理
  • server的啟用:development 模式下啟動伺服器並實時重新整理

轉換 ES6 程式碼,解決瀏覽器相容問題

用 babel 轉換 ES6 程式碼

用 babel 轉換 ES6 程式碼需要使用到 babel-loader ,我們需要安裝一系列的依賴:

    npm i babel-core babel-loader babel-preset-env --save-dev
複製程式碼

然後在根目錄新建一個babel配置檔案 .babelrc

    {
        "presets": [
            "env"
        ]
    }
複製程式碼

那麼如何將配置用於webpack打包中?

  • 新建一個 webpack 的配置檔案
  • 在 npm scripts 中使用 --module-bind
  1. 使用 webpack 的配置檔案的方法:

    新建 webpack.config.js

        module.exports = {
          module: {
            rules: [
              {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                  loader: "babel-loader"
                }
              }
            ]
          }
        }
    複製程式碼
  2. 在 npm scripts 中配置的方法:

    "scripts": {
      "dev": "webpack --mode development --module-bind js=babel-loader",
      "build": "webpack --mode production --module-bind js=babel-loader"
    }
複製程式碼

使用 babel-polyfill 解決相容性問題

然而瀏覽器依然不支援一些語法的使用,導致相容性問題,我們用 babel-polyfill 解決:

    npm i babel-polyfill babel-plugin-transform-runtime  --save-dev
複製程式碼

.babelrc 新增配置:

{
    "presets": [
        "env"
    ],
    "plugins": [
       "transform-runtime"
    ]
}
複製程式碼

最後在 webpack.config.js 中將 babel-polyfill 加到你的 entry 陣列中:

const path = require('path');
module.exports = {
    entry: [
        "babel-polyfill",
        path.join(__dirname, './src/index.js')
    ],
    // ...
};
複製程式碼

編譯css,自動新增字首,抽取css到獨立檔案

webpack 並不會主動將你的css程式碼提取到一個檔案,過去我們使用 extract-text-webpack-plugin,在webpack4中我們使用mini-css-extract-plugin來解決這個問題。

postcss-loader 用於新增瀏覽器字首,相關配置我喜歡在根目錄新建 postcss.config.js 配置

    npm i mini-css-extract-plugin css-loader --save-dev
    npm i style-loader postcss-loader  --save-dev
複製程式碼
    // webpack.config.js
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    module.exports = (env, argv) => {
      const devMode = argv.mode !== 'production'
      return {
        module: {
          rules: [
            // ...,
            {
                test: /\.css$/,
                use: [
                    devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
                    'css-loader',
                    'postcss-loader'
                ]
            },
            ]
          },
          plugins: [
            // ...,
            new MiniCssExtractPlugin({
              filename: "[name].css",
              chunkFilename: "[id].css"
            })
          ]
      }
    }
複製程式碼
// postcss.config.js
    module.exports = {
        plugins: {
            autoprefixer: {}
        }
    }
複製程式碼

複製並壓縮html檔案 html-webpack-plugin

    npm i html-webpack-plugin html-loader --save-dev
複製程式碼
    // webpack.config.js
    const HtmlWebPackPlugin = require("html-webpack-plugin");
    module.exports = {
        module: {
            rules: [
                // ...,
                {
                    test: /\.html$/,
                    use: [{
                        loader: "html-loader",
                        options: {
                            minimize: true
                        }
                    }]
                }
            ]
        },
        plugins: [
            new HtmlWebPackPlugin({
                template: "./src/index.html",
                filename: "./index.html"
            })
        ]
    };
複製程式碼

打包前清理源目錄檔案 clean-webpack-plugin

每次打包,都會生成專案的靜態資源,隨著某些檔案的增刪,我們的 dist 目錄下可能產生一些不再使用的靜態資源,webpack並不會自動判斷哪些是需要的資源,為了不讓這些舊檔案也部署到生產環境上佔用空間,所以在 webpack 打包前最好能清理 dist 目錄。

    npm install clean-webpack-plugin --save-dev
複製程式碼
  const CleanWebpackPlugin = require('clean-webpack-plugin');
  module.exports = {
    plugins: [
      new CleanWebpackPlugin(['dist']),
    ]
  };
複製程式碼

靜態資源處理 file-loader

    npm install file-loader --save-dev
複製程式碼
    // webpack.config.js
    module.exports = {
      module: {
        rules: [
          {
            test: /\.(png|jpg|gif)$/,
            use: [
              {
                loader: 'file-loader',
                options: {}
              }
            ]
          }
        ]
      }
    }
複製程式碼

development 模式下啟動伺服器並實時重新整理 webpack-dev-server

    npm i webpack-dev-server --save-dev
複製程式碼

package.json

    "scripts": {
      "start": "webpack-dev-server --mode development --open",
      "build": "webpack --mode production"
    }
複製程式碼

使用 webpack 4 建立 react 專案

現在我們模仿 create-react-app 的結構,自己搭建一個 react 專案,並且用less預編譯:

  ├── public
  │   └── index.html      # html 模板
  ├── src
  │   ├── assets          # 靜態資源
  │   │   └── logo.png
  │   ├── components      # 元件
  │   │   └── App.js
  │   ├── index.js        # 入口檔案
  │   └── styles
  │       └── index.less
  ├── .babelrc
  ├── package-lock.json
  ├── package.json
  ├── postcss.config.js
  └── webpack.config.js
複製程式碼

在以上的基礎(專案搭建部分),再安裝react相關模組及less模組:

    npm i react react-dom --save
    npm i babel-preset-react --save-dev
    npm i less less-loader --save-dev
複製程式碼

修改 .babelrc:

    {
      "presets": ["env", "react"]
    }
複製程式碼

修改 webpack.config.js

    // webpack.config.js
    const path = require('path');
    module.exports = (env, argv) => {
        const devMode = argv.mode !== 'production'
        return {
            entry: [
                "babel-polyfill",
                path.join(__dirname, './src/index.js')
            ],
            devServer: {
                port: 3000, //埠號
            },
            module: {
                rules: [
                    // ...
                    // 處理react
                    {
                        test: /\.(js|jsx)$/,
                        exclude: /node_modules/,
                        use: {
                            loader: "babel-loader"
                        }
                    },
                    // 處理less
                    {
                        test: /\.less$/,
                        use: [
                            devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
                            'css-loader',
                            'postcss-loader',
                            'less-loader',
                        ]
                    }
                ]
            }
        }
    };
複製程式碼

基本上搭建完這個專案了,如果你想看完整程式碼

使用 webpack 4 建立 vue 專案

同樣地,我們模仿 vue-cli 的結構,自己搭建一個 vue 專案,這次我們的css預編譯語言用 scss

  ├── public
  │   └── index.html      # html 模板
  ├── src
  │   ├── assets          # 靜態資源
  │   │   └── logo.png
  │   ├── components      # 元件
  │   │   └── App.vue
  │   ├── main.js        # 入口檔案
  │   ├── main.js        # 入口檔案
  │   └── styles
  │       └── index.scss
  ├── .babelrc
  ├── package-lock.json
  ├── package.json
  ├── postcss.config.js
  └── webpack.config.js
複製程式碼

在以上的基礎(專案搭建部分),再安裝vue相關模組及sass模組:

    npm i vue --save
    npm i vue-loader vue-template-compiler --save-dev
    npm i node-sass sass-loader --save-dev
複製程式碼
    // webpack.config.js
    const path = require('path');
    const VueLoaderPlugin = require('vue-loader/lib/plugin')

    module.exports = (env, argv) => {
        const devMode = argv.mode !== 'production'
        return {
            entry: [
                "babel-polyfill",
                path.join(__dirname, './src/main.js')
            ],
            module: {
                rules: [
                    // ...
                    // 解析vue
                    {
                        test: /\.vue$/,
                        loader: 'vue-loader',
                        options: {
                            loaders: {}
                        }
                    },
                    // 處理scss
                    {
                        test: /\.scss$/,
                        use: [
                            devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
                            'css-loader',
                            'postcss-loader',
                            'sass-loader',
                        ]
                    }
                ]
            },
            plugins: [
                // ...
                new VueLoaderPlugin()
            ]
        }
    };
複製程式碼

一個簡易的 vue-cli 也搭建完成,如果你想看完整程式碼

參考資源

相關文章