使用webpack來生成多頁面應用MPA

使用webpack配置MPA

爲什麼需要使用 webpack 構建多頁應用呢?因爲某些項目使用 SPA 不太合適(大多是 SEO 的原因),或者您在做項目時有其他的需求。
如果你有如下需求:

  • 使用 ES6 進行開發
  • 期望使用面向對象開發(class)
  • 自動壓縮合並 CSS 和 JS 文件
  • 使用 ESLint 進行代碼檢查
  • 自動生成 HTML 文件
  • 自動抽取 CSS 文件 …

有了這些需求,基本上就必須使用 webpack 了。

安裝依賴

首先是項目中需要使用的依賴安裝。

  1. 安裝 webpack 和 webpack-dev-server

npm install webpack webpack-dev-server --save-dev

  1. 安裝 webpack-merge

npm install webpack-merge --save-dev

該插件用來對 webpack 配置進行合併操作。

  1. 安裝 babel 相關插件

npm install babel-core babel-loader babel-preset-env --save-dev

這系列插件用來對 ES6 語法進行轉換。

  1. 安裝樣式處理相關插件

npm install css-loader style-loader postcss-loader autoprefixer --save-dev

這系列插件用來處理 CSS 樣式,其中 autoprefixer 是 postcss 的一個插件,用來自動給 CSS 樣式添加前綴。

  1. 安裝 file-loader

該插件將在導入圖片、字體等文件時發揮作用。PS.您也可以安裝 url-loader 以實現相同的作用:

npm install file-loader --save-dev

npm install url-loader --save-dev

  1. 安裝 ESLint 相關的插件

npm install eslint eslint-loader --save-dev

這些插件用來對 JavaScript 代碼進行檢查。

  1. 安裝 html-webpack-plugin 插件

npm install html-webpack-plugin --save-dev

該插件用來自動生成 HTML 文件。

  1. 安裝 extract-text-webpack-plugin 插件

npm install extract-text-webpack-plugin --save-dev

該插件用來將 CSS 抽取到獨立的文件。

  1. 安裝 clean-webpack-plugin 插件

npm install clean-webpack-plugin --save-dev

該插件用來對 dist 文件夾進行清理工作,每次打包時先清理之前的 dist 文件夾。

下面是這些安裝了的所有依賴:

...

  "devDependencies": {

    "autoprefixer": "^7.1.3",

    "babel-core": "^6.26.0",

    "babel-loader": "^7.1.2",

    "babel-preset-env": "^1.6.0",

    "clean-webpack-plugin": "^0.1.16",

    "css-loader": "^0.28.7",

    "eslint": "^4.6.1",

    "eslint-loader": "^1.9.0",

    "extract-text-webpack-plugin": "^3.0.0",

    "file-loader": "^0.11.2",

    "html-webpack-plugin": "^2.30.1",

    "postcss-loader": "^2.0.6",

    "style-loader": "^0.18.2",

    "url-loader": "^0.5.9",

    "webpack": "^3.5.5",

    "webpack-dev-server": "^2.7.1",

    "webpack-merge": "^4.1.0"

  },

...

配置文件劃分

使用 webpack 進行項目構建時,我們有不同的目的,因此最好將配置文件進行拆分,以適應不同的工作:

├─config

│      config.js

│      webpack.config.base.js

│      webpack.config.dev.js

│      webpack.config.lint.js

│      webpack.config.prod.js

│  webpack.config.js

下面是一些配置的說明:

config.js:一些全局的配置,比如 HTML 文件的路徑、publicPath 等

webpack.config.base.js:最基礎的配置文件

webpack.config.dev.js:開發環境配置文件

webpack.config.lint.js:使用 ESLint 代碼檢查時的配置文件

webpack.config.prod.js:生產環境配置文件

webpack.config.js:主配置文件,根據環境變量引用相應的環境的配置

這些配置文件之間是通過 webpack-merge 這個插件進行合併的。

配置多頁應用的關鍵點

如何使用 webpack 配置多頁面應用呢?實現多頁面應用的關鍵點在哪裏呢?首先需要簡單看一下多頁應用和單頁應用功能的區別。

單頁應用的特點:

只有一個入口頁面(index.html)
這個單頁頁面(index.html)中需要引入打包後的所有 JavaScript 文件
所有的頁面內容完全由 JavaScript 生成
單頁應用有自己的路由系統,服務器端沒有和路由對應的文件
···

多頁應用的特點:

每個版塊對應一個頁面
每個頁面需要對公共的 JavaScript 進行引入
每個頁面還需要引入和其自身對應的 JavaScript 文件
由於對應了多個頁面,因此不是所有頁面內容都是由 JavaScript 生成的
沒有自己的路由系統,服務器端有對應的靜態文件
···
拋開生成頁面內容和路由系統,我們可以看到單頁應用和多頁應用最大的區別就是:

單頁應用需要在入口頁面引入所有的 JavaScript 文件
多頁應用需要在每個頁面中引入公共的 JavaScript 文件以及其自身的 JavaScript 文件
由於 CSS 文件是可以由 extract-text-webpack-plugin 這個插件自動提取並插入到 HTML 頁面的,因此我們只需要關心如何在 HTML 頁面中引入 JavaScript 文件了。
webpack 在打包時,會將入口文件中的 JavaScript 文件打包到某個目標文件中,在不考慮代碼分割提取的情況下,一個入口文件會打包爲一個目標文件,多個入口文件會打包爲多個對應的目標文件。
因此,我們可以將每個多頁頁面中的特有的 JavaScript 文件作爲入口文件,在打包時將對應打包成不同的 bundle 文件(結果文件),如果你想要的話,還可以在打包時進行代碼分割處理,將公用代碼抽取成一個文件,然後在 HTML 中引入這些 JavaScript 文件就好了。
總結一下,使用 webpack 配置多頁應用的關鍵點在於:

將每個頁面中特有的 JavaScript 文件作爲入口文件進行打包
在打包後,每個頁面中都需要引入這些打包後的文件
您可以在打包時進行公用代碼提取,然後在 HTML 文件中引入
說了這麼多,其實就是利用了 webpack 多入口文件進行打包。

自動生成 HTML 頁面

在使用 webpack 對 JavaScript 文件進行打包時,通常需要在打包的文件名中加一個 hash 字符串用來防止緩存,當我們修改了 JavaScript 代碼後,打包後的文件名也會發生變化。此時如果手動在 HTML 中引用這些 JavaScript 文件,是非常麻煩的。
因此,我們期望能自動生成 HTML 文件,並自動引用打包後的 JavaScript 文件。所謂自動生成 HTML 文件,可以理解爲將源代碼的 HTML 複製到目標文件夾中,同時自動引用打包後的 JavaScript 文件。
要完成這項操作,就需要使用前面安裝的 html-webpack-plugin 這個插件。

html-webpack-plugin 插件的使用

首先,在我的項目中,有這麼一些 HTML 頁面,將它們放在 html 文件夾中:

Mode                LastWriteTime         Length Name

----                -------------         ------ ----

-a----         2017/9/5     18:04           1071 company_intro.html

-a----         2017/9/5     18:04            988 contact_us.html

-a----         2017/9/5     18:04           1131 cooperate.html

-a----         2017/9/5     18:04           1244 enterprise_culture.html

-a----         2017/9/5     18:04           1011 hornors.html

-a----         2017/9/5     18:04           1365 index.html

-a----         2017/9/5     18:04           1769 investment.html

-a----         2017/9/5     18:04           1005 join_us.html

-a----         2017/9/5     18:04           1037 news_center.html

-a----         2017/9/5     18:04            987 news_item.html

-a----         2017/9/5     18:04           1134 operate.html

-a----         2017/9/5     18:04           1255 product.html

-a----         2017/9/5     18:04           1132 schools.html

然後,把這些 HTML 文件名(不要後綴)都寫在 config.js 文件中,以供取用:

module.exports = {

    HTMLDirs:[

        "index",

            "company_intro",

            "enterprise_culture",

            "hornors",

            "news_center",

            "news_item",

            "product",

            "schools",

            "operate",

            "cooperate",

            "join_us",

            "contact_us",

            "investment"

            ],

        }

HTMLDirs 是一個數組,其中保存了項目中會用到的所有 HTML 頁面。
接下來,每個 HTML 頁面都對應一份 JavaScript 代碼,因此在 js 文件夾中建立對應的 JavaScript 文件:

Mode                LastWriteTime         Length Name

----                -------------         ------ ----

-a----         2017/9/5     18:04           2686 company_intro.js

-a----         2017/9/5     18:04            594 contact_us.js

-a----         2017/9/5     18:04           1725 cooperate.js

-a----         2017/9/8     16:54           3505 enterprise_culture.js

-a----         2017/9/5     18:04           2208 hornors.js

-a----         2017/9/8     16:54           4491 index.js

-a----         2017/9/5     18:04           3180 investment.js

-a----         2017/9/5     18:04           1327 join_us.js

-a----         2017/9/8     16:55           3689 news_center.js

-a----         2017/9/5     18:04           1972 news_item.js

-a----         2017/9/5     18:04           2728 operate.js

-a----         2017/9/5     18:04           2664 product.js

-a----         2017/9/5     18:04           2476 schools.js

這兩項是必須的,只有提供了每個頁面的 HTML 文件和對應的 JavaScript 文件,才能構建多頁面應用。
同時,可能每個頁面都有自己的樣式,因此您也可以在 css 文件夾中建立一些樣式文件:

Mode                LastWriteTime         Length Name

----                -------------         ------ ----

-a----         2017/9/5     18:04            419 company_intro.css

-a----         2017/9/5     18:04            167 contact_us.css

-a----         2017/9/5     18:04            214 cooperate.css

-a----         2017/9/5     18:04            926 enterprise_culture.css

-a----         2017/9/5     18:04            255 hornors.css

-a----         2017/9/5     18:04            693 investment.css

-a----         2017/9/5     18:04            136 join_us.css

-a----         2017/9/5     18:04            541 news_center.css

-a----         2017/9/5     18:04            623 news_item.css

-a----         2017/9/5     18:04            342 operate.css

-a----         2017/9/5     18:04            236 product.css

-a----         2017/9/5     18:04            213 schools.css

關於建立樣式這一項,不是必須的。
最後,我們就可以使用 html-webpack-plugin 這個插件來自動生成 HTML 文件了,html-webpack-plugin 插件的用法如下:

// 引入插件

const HTMLWebpackPlugin = require("html-webpack-plugin");

// 引入多頁面文件列表

const { HTMLDirs } = require("./config");

// 通過 html-webpack-plugin 生成的 HTML 集合

let HTMLPlugins = [];

// 入口文件集合

let Entries = {}

 

// 生成多頁面的集合

HTMLDirs.forEach((page) => {

    const htmlPlugin = new HTMLWebpackPlugin({

        filename: `${page}.html`,

        template: path.resolve(__dirname, `../app/html/${page}.html`),

        chunks: [page, 'commons'],

    });

    HTMLPlugins.push(htmlPlugin);

    Entries[page] = path.resolve(__dirname, `../app/js/${page}.js`);

})

在上面的代碼中,首先引入了所需的插件和變量,然後利用 html-webpack-plugin 循環生成 HTML 頁面。
簡單說下 HTMLWebpackPlugin 構造函數的幾個參數:

filename:生成的 HTML 文件名,我這裏選擇和原始文件名保持一致
template:生成 HTML 文件使用的模板,也就是我們之前在 html 文件夾中建立的那些文件
chunks:生成 HTML 文件時會自動插入相應的代碼片段(也就是 JavaScript 文件),我這裏選擇插入每個頁面對應的 JavaScript 文件,以及最後提取出來的公共文件代碼塊。
關於 chunks 還需要說明一點,chunks 是一個數組,在生成 HTML 文件時會將數組中的對應的 JavaScript 片段自動插入到 HTML 中,這些片段也就是 webpack 打包時的 output 選項中的 [name]。這裏只需要寫上 [name] 值就行了,無需使用打包生成的完整名稱,因爲這會還沒開始打包呢,打包後生成的名稱咱也不知道。
最後,我們把這些生成 HTML 文件的配置插入到 HTMLPlugins 這個數組中,同時設置 webpack 的入口文件。

目錄劃分

在這個腳手架中,我是這樣劃分項目結構的:

├─app

│  ├─css

│  ├─html

│  ├─img

│  ├─js

│  └─lib

├─config

└─dist

    ├─css

    ├─img

    └─js

其中 app 是項目的源碼,config 是 webpack 相關的一些配置文件,dist 是存放打包後的文件,是由 webpack 自動生成的。

更詳細的文件結構如下:

 

│  .babelrc

│  .eslintrc.js

│  .gitignore

│  package.json

│  postcss.config.js

│  webpack.config.js

│ 

├─app

│  │  favicon.ico

│  │ 

│  ├─css

│  │      main.css

│  │     

│  ├─html

│  │      index.html

│  │   

│  │     

│  ├─img

│  │      back.png

│  │     

│  ├─js

│  │      ajax.js

│  │      footer.js

│  │      index.js

│  │      nav.js

│  │      public.js

│  │      tity_nav.js

│  │     

│  └─lib

│        flexible.js

│        normalize.css

│        swiper.css

│        swiper.js

│       

└─config

        config.js

        webpack.config.base.js

        webpack.config.dev.js

        webpack.config.lint.js

        webpack.config.prod.js

package.json

所有的功能都是從 package.json 的 scripts 入口開始執行的,我想要腳手架有以下功能:

  • 開發環境構建
  • 生產環境構建
  • ESLint 代碼檢查環境
  • 生產環境構建後的服務器預覽環境
  • 在開發或代碼檢查環境,需要啓用 webpack-dev-server 命令,生產環境構建需要啓用 webpack 命令,預覽環境需要啓用 http-server 環境。
  • 上文介紹時把 http-server 給落下了,您現在可以進行如下安裝:

npm install http-server --save-dev

scripts 命令行配置如下:

"scripts": {

  "dev": "set NODE_ENV=dev && webpack-dev-server --open",

  "build": "set NODE_ENV=prod && webpack -p",

  "lint": "set NODE_ENV=lint && webpack-dev-server --open",

  "serve": "http-server ./dist -p 8888 -o",

  "serve2": "http-server ./dist -p 8888"

},

下面是整個 package.json 文件:

{

    "name": "xxx",

    "version": "1.0.0",

    "description": "",

    "main": "index.js",

    "scripts": {

    "dev": "set NODE_ENV=dev && webpack-dev-server --open",

    "build": "set NODE_ENV=prod && webpack -p",

    "lint": "set NODE_ENV=lint && webpack-dev-server --open",

    "serve": "http-server ./dist -p 8888 -o",

    "serve2": "http-server ./dist -p 8888"

    },

    "author": "",

    "license": "ISC",

    "devDependencies": {

    "autoprefixer": "^7.1.3",

    "babel-core": "^6.26.0",

    "babel-loader": "^7.1.2",

    "babel-plugin-transform-es2015-spread": "^6.22.0",

    "babel-preset-env": "^1.6.0",

    "clean-webpack-plugin": "^0.1.16",

    "css-loader": "^0.28.7",

    "eslint": "^4.5.0",

    "eslint-loader": "^1.9.0",

    "extract-text-webpack-plugin": "^3.0.0",

    "file-loader": "^0.11.2",

    "html-webpack-plugin": "^2.30.1",

    "http-server": "^0.10.0",

    "postcss-loader": "^2.0.6",

    "style-loader": "^0.18.2",

    "url-loader": "^0.5.9",

    "webpack": "^3.5.5",

    "webpack-dev-server": "^2.7.1",

    "webpack-merge": "^4.1.0"

    },

    "dependencies": {}

}

啓用環境

如果您想啓用某個環境,需要使用 npm run xxx 命令:

  • npm run dev:進入開發環境
  • npm run build:進入生產環境
  • npm run lint:執行代碼檢查
  • npm run serve:服務器環境下預覽(打開瀏覽器)
  • npm run serve2:服務器環境下預覽(不打開瀏覽器)

默認情況下,使用這些命令都會先引入和 package.js 同目錄下的 webpack.config.js 文件。由於我們不會將所有的配置都放在 webpack.config.js 中,而是過環境變量進行區分,在 webpack.config.js 中引用其他的配置文件。
設置環境變量採用的語法:

set NODE_ENV=xxx
這裏我們爲開發、生產、代碼檢查和預覽這幾個環境設置了環境變量。

  • webpack.config.js
  • webpack.config.js 文件比較簡單,只有兩行代碼,其作用就是用來引用其他的配置文件:

// 獲取環境命令,並去除首尾空格

const env = process.env.NODE_ENV.replace(/(\s*$)|(^\s*)/ig,"");

// 根據環境變量引用相關的配置文件

module.exports = require(`./config/webpack.config.${env}.js`)

webpack.config.base.js

webpack.config.base.js 是最基礎的配置文件,包含了這些環境都可能使用到的配置。

1)相關插件引入


const path = require("path");

// 引入插件

const HTMLWebpackPlugin = require("html-webpack-plugin");

// 清理 dist 文件夾

const CleanWebpackPlugin = require("clean-webpack-plugin")

// 抽取 css

const ExtractTextPlugin = require("extract-text-webpack-plugin");

#### 2)自動生成 HTML 的配置

 

// 引入多頁面文件列表

const config = require("./config");

// 通過 html-webpack-plugin 生成的 HTML 集合

let HTMLPlugins = [];

// 入口文件集合

let Entries = {}

 

// 生成多頁面的集合

config.HTMLDirs.forEach((page) => {

    const htmlPlugin = new HTMLWebpackPlugin({

        filename: `${page}.html`,

        template: path.resolve(__dirname, `../app/html/${page}.html`),

        chunks: [page, 'commons'],

    });

    HTMLPlugins.push(htmlPlugin);

    Entries[page] = path.resolve(__dirname, `../app/js/${page}.js`);

})

3)主配置文件一覽

module.exports = {

    // 入口文件

    entry:Entries,

    // 啓用 sourceMap

    devtool:"cheap-module-source-map",

    // 輸出文件

    output:{},

    // 加載器

    module:{

        rules:[

        ],

    },

    // 插件

    plugins:[],

}

4)配置 css 加載器

{

    // 對 css 後綴名進行處理

    test:/\.css$/,

    // 不處理 node_modules 文件中的 css 文件

    exclude: /node_modules/,

    // 抽取 css 文件到單獨的文件夾

    use: ExtractTextPlugin.extract({

        fallback: "style-loader",

        // 設置 css 的 publicPath

        publicPath: config.cssPublicPath,

        use: [{

                loader:"css-loader",

                options:{

                    // 開啓 css 壓縮

                    minimize:true,

                }

            },

            {

                loader:"postcss-loader",

            }

        ]

    })

},

這裏有兩點需要說明:
A.publicPath:在 css 中設置背景圖像的 url 時,經常會找不到圖片(默認會在 css 文件所在的文件夾中尋找),這裏設置 extract-text-webpack-plugin 插件的 publicPath 爲圖片文件夾所在的目錄,就可以順利找到圖片了。
在 config.js 中,設置 cssPublicPath 的值:

cssPublicPath:”../”
B.postcss 我主要用來自動添加 css 前綴以及一點美化操作,在使用 postcss 時,需要在 postcss.config.js 中進行配置:

module.exports = { 

    plugins: { 

    'autoprefixer': {

        browsers: ['last 5 version','Android >= 4.0'],

        //是否美化屬性值 默認:true

        cascade: true,

        //是否去掉不必要的前綴 默認:true

        remove: true

    

    

}

5)配置 js 加載器

js 加載器的配置如下:

{

    test: /\.js$/,

    exclude: /node_modules/,

    use: {

        loader: 'babel-loader',

        options: {

            presets: ['env']

        }

    }

},

6)配置圖片加載器

圖片加載器的配置如下:

{

    test: /\.(png|svg|jpg|gif)$/,

    use:{

        loader:"file-loader",

        options:{

            // 打包生成圖片的名字

            name:"[name].[ext]",

            // 圖片的生成路徑

            outputPath:config.imgOutputPath

        }

    }

},

outputPath 規定了輸出圖片的位置,默認情況下,圖片在打包時會和所有的 HTML/CSS/JS 文件打包到一起,通過設置 outputPath 值可以將所有的圖片都打包到一個單獨的文件中。
設置 config.js 的 imgOutputPath:

imgOutputPath:”img/”,
在打包時,會將所有的圖片打包到 dist 文件夾下的 img 文件夾中。

7)配置自定義字體加載器

自定義字體加載器的配置如下:

{

    test: /\.(woff|woff2|eot|ttf|otf)$/,

    use:["file-loader"]

}

8)插件配置

插件配置如下:

plugins:[

    // 自動清理 dist 文件夾

    new CleanWebpackPlugin(["dist"]),

    // 將 css 抽取到某個文件夾

    new ExtractTextPlugin(config.cssOutputPath),       

    // 自動生成 HTML 插件

    ...HTMLPlugins

],

同打包圖片,在抽取 css 時也可以指定抽取的目錄,只需將路徑傳入 extract-text-webpack-plugin 插件的構造函數中。
配置 config.js 的 cssOutputPath 選項:

cssOutputPath:"./css/styles.css",

這裏將所有的 css 提取到 dist 文件夾下的 css 文件夾中,並命名爲 style.css。

webpack.config.base.js 詳細配置

下面是 webpack.config.base.js 的詳細配置文件:

const path = require("path");

// 引入插件

const HTMLWebpackPlugin = require("html-webpack-plugin");

// 清理 dist 文件夾

const CleanWebpackPlugin = require("clean-webpack-plugin")

// 抽取 css

const ExtractTextPlugin = require("extract-text-webpack-plugin");

// 引入多頁面文件列表

const config = require("./config");

// 通過 html-webpack-plugin 生成的 HTML 集合

let HTMLPlugins = [];

// 入口文件集合

let Entries = {}

 

// 生成多頁面的集合

config.HTMLDirs.forEach((page) => {

    const htmlPlugin = new HTMLWebpackPlugin({

        filename: `${page}.html`,

        template: path.resolve(__dirname, `../app/html/${page}.html`),

        chunks: [page, 'commons'],

    });

    HTMLPlugins.push(htmlPlugin);

    Entries[page] = path.resolve(__dirname, `../app/js/${page}.js`);

})

 

module.exports = {

    entry:Entries,

    devtool:"cheap-module-source-map",

    output:{

        filename:"js/[name].bundle.[hash].js",

        path:path.resolve(__dirname,"../dist")

    },

    // 加載器

    module:{

        rules:[

            {

                // 對 css 後綴名進行處理

                test:/\.css$/,

                // 不處理 node_modules 文件中的 css 文件

                exclude: /node_modules/,

                // 抽取 css 文件到單獨的文件夾

                use: ExtractTextPlugin.extract({

                    fallback: "style-loader",

                    // 設置 css 的 publicPath

                    publicPath: config.cssPublicPath,

                    use: [{

                            loader:"css-loader",

                            options:{

                                // 開啓 css 壓縮

                                minimize:true,

                            }

                        },

                        {

                            loader:"postcss-loader",

                        }

                    ]

                })

            },

            {

                test: /\.js$/,

                exclude: /node_modules/,

                use: {

                    loader: 'babel-loader',

                    options: {

                        presets: ['env']

                    }

                }

            },

            {

                test: /\.(png|svg|jpg|gif)$/,

                use:{

                    loader:"file-loader",

                    options:{

                        // 打包生成圖片的名字

                        name:"[name].[ext]",

                        // 圖片的生成路徑

                        outputPath:config.imgOutputPath

                    }

                }

            },

            {

                test: /\.(woff|woff2|eot|ttf|otf)$/,

                use:["file-loader"]

            }

        ],

    },

    plugins:[

        // 自動清理 dist 文件夾

        new CleanWebpackPlugin(["dist"]),

        // 將 css 抽取到某個文件夾

        new ExtractTextPlugin(config.cssOutputPath),       

        // 自動生成 HTML 插件

        ...HTMLPlugins

    ],

}

webpack.config.dev.js

這個配置文件主要用來在開發環境使用,需要 webpack-dev-server 這個插件提供支持。該文件的配置如下:

// 引入基礎配置文件

const webpackBase = require("./webpack.config.base");

// 引入 webpack-merge 插件

const webpackMerge = require("webpack-merge");

// 引入配置文件

const config = require("./config");

// 合併配置文件

module.exports = webpackMerge(webpackBase,{

    // 配置 webpack-dev-server

    devServer:{

        // 項目根目錄

        contentBase:config.devServerOutputPath,

        // 錯誤、警告展示設置

        overlay:{

            errors:true,

            warnings:true

        }

    }

});

其中,webpack-merge 這個插件用來對配置文件進行合併,在 webpack.config.base.js 的基礎上合併新的配置。
devServer 配置項的 contentBase 項是項目的根目錄,也就是我們的 dist 目錄,區別在於這個 dist 目錄不是硬盤上的 dist 目錄,而是存在於內存中的 dist 目錄。在使用 webpack-dev-server 時,將會以這個內存中的 dist 目錄作爲根目錄。
devServer 的 overlay 選項中設置了展示錯誤和警告,這樣當代碼發生錯誤時,會將錯誤信息投射到瀏覽器上,方便我們開發。
這裏將 contentBase 指向了 config 中的一個配置:

devServerOutputPath:"../dist",

webpack.config.prod.js

該配置文件用來在生產環境啓用,主要用來壓縮、合併和抽取 JavaScript 代碼,並將項目文件打包至硬盤上的 dist 文件夾中。

// 引入基礎配置

const webpackBase = require("./webpack.config.base");

// 引入 webpack-merge 插件

const webpackMerge = require("webpack-merge");

// 引入 webpack

const webpack = require("webpack");

// 合併配置文件

module.exports = webpackMerge(webpackBase,{

    plugins:[

        // 代碼壓縮

        new webpack.optimize.UglifyJsPlugin({

            // 開啓 sourceMap

            sourceMap: true

        }),

        // 提取公共 JavaScript 代碼

        new webpack.optimize.CommonsChunkPlugin({

            // chunk 名爲 commons

            name: "commons",

            filename: "[name].bundle.js",

        }),

    ]

});

在抽取公共的 JavaScript 代碼時,我們將公共代碼抽取爲 commons.bundle.js,這個公共代碼的 chunk(name)名就是 commons,在使用 html-webpack-plugin 自動生成 HTML 文件時會引用這個 chunk。

webpack.config.lint.js

這項配置用來進行代碼檢查,配置如下:

const webpackBase = require("./webpack.config.base");

const webpackMerge = require("webpack-merge");

const config = require("./config");

module.exports = webpackMerge(webpackBase,{

    module:{

        rules:[

            {

                test: /\.js$/,

                // 強制先進行 ESLint 檢查

                enforce: "pre",

                // 不對 node_modules 和 lib 文件夾中的代碼進行檢查

                exclude: /node_modules|lib/,

                loader: "eslint-loader",

                options: {

                    // 啓用自動修復

                    fix:true,

                    // 啓用警告信息

                    emitWarning:true,

                }

            },

        ]

    },

    devServer:{

        contentBase:config.devServerOutputPath,

        overlay:{

            errors:true,

            warnings:true

        }

    }

});

在使用 eslint-loader 時,我們設置了 enforce:”pre” 選項,這個選項表示在處理 JavaScript 之前先啓用 ESLint 代碼檢查,然後再使用 babel 等 loader 對 JavaScript 進行編譯。
在 eslint-loader 的 options 選項中,設置了自動修復和啓用警告信息,這樣當我們的代碼出現問題時,ESLint 會首先嚐試自動修復(如將雙引號改爲單引號),對於無法自動修復的問題,將以警告或錯誤的信息進行展示。

配置 .eslintrc.js

要想使用 ESLint 進行代碼檢查,除了使用 eslint-loader 之外,還需針對 ESLint 本身進行配置,這就需要一個 .eslintrc.js 文件。該文件的配置如下:

module.exports = {

    env: {

    browser: true,

    commonjs: true,

    es6: true,

    node: true,

    },

    extends: 'eslint:recommended',

    parserOptions: {

    sourceType: 'module',

    },

    rules: {

    'comma-dangle': ['error', 'always-multiline'],

    indent: ['error', 2],

    'linebreak-style': ['error', 'unix'],

    quotes: ['error', 'single'],

    semi: ['error', 'always'],

    'no-unused-vars': ['warn'],

    'no-console': 0,

    },

};

package.json

{

    "name": "xxx",

    "version": "1.0.0",

    "description": "",

    "main": "index.js",

    "scripts": {

    "dev": "set NODE_ENV=dev && webpack-dev-server --open",

    "build": "set NODE_ENV=prod && webpack -p",

    "lint": "set NODE_ENV=lint && webpack-dev-server --open",

    "serve": "http-server ./dist -p 8888 -o",

    "serve2": "http-server ./dist -p 8888"

    },

    "author": "",

    "license": "ISC",

    "devDependencies": {

    "autoprefixer": "^7.1.3",

    "babel-core": "^6.26.0",

    "babel-loader": "^7.1.2",

    "babel-plugin-transform-es2015-spread": "^6.22.0",

    "babel-preset-env": "^1.6.0",

    "clean-webpack-plugin": "^0.1.16",

    "css-loader": "^0.28.7",

    "eslint": "^4.5.0",

    "eslint-loader": "^1.9.0",

    "extract-text-webpack-plugin": "^3.0.0",

    "file-loader": "^0.11.2",

    "html-webpack-plugin": "^2.30.1",

    "http-server": "^0.10.0",

    "postcss-loader": "^2.0.6",

    "style-loader": "^0.18.2",

    "url-loader": "^0.5.9",

    "webpack": "^3.5.5",

    "webpack-dev-server": "^2.7.1",

    "webpack-merge": "^4.1.0"

    },

    "dependencies": {}

}

.gitignore

node_modules

dist

npm-debug.log

 

.babelrc

 

{

    "plugins": ["transform-es2015-spread"]

}

.eslintrc.js

module.exports = {

    env: {

    browser: true,

    commonjs: true,

    es6: true,

    node: true,

    },

    extends: 'eslint:recommended',

    parserOptions: {

    sourceType: 'module',

    },

    rules: {

    'comma-dangle': ['error', 'always-multiline'],

    indent: ['error', 2],

    'linebreak-style': ['error', 'unix'],

    quotes: ['error', 'single'],

    semi: ['error', 'always'],

    'no-unused-vars': ['warn'],

    'no-console': 0,

    },

};

postcss.config.js

module.exports = { 

    plugins: { 

    'autoprefixer': {

        browsers: ['last 5 version','Android >= 4.0'],

        //是否美化屬性值 默認:true

        cascade: true,

        //是否去掉不必要的前綴 默認:true

        remove: true

    

    

}

config.js

module.exports = {

    HTMLDirs:[

        "index",

        "company_intro",

        "enterprise_culture",

        "hornors",

        "news_center",

        "news_item",

        "product",

        "schools",

        "operate",

        "cooperate",

        "join_us",

        "contact_us",

        "investment"

    ],

    cssPublicPath:"../",

    imgOutputPath:"img/",

    cssOutputPath:"./css/styles.css",

    devServerOutputPath:"../dist",

 

}

webpack.config.js

// 獲取環境命令,並去除首尾空格

const env = process.env.NODE_ENV.replace(/(\s*$)|(^\s*)/ig,"");

// 根據環境變量引用相關的配置文件

module.exports = require(`./config/webpack.config.${env}.js`)

webpack.config.base.js

 

const path = require("path");

// 引入插件

const HTMLWebpackPlugin = require("html-webpack-plugin");

// 清理 dist 文件夾

const CleanWebpackPlugin = require("clean-webpack-plugin")

// 抽取 css

const ExtractTextPlugin = require("extract-text-webpack-plugin");

// 引入多頁面文件列表

const config = require("./config");

// 通過 html-webpack-plugin 生成的 HTML 集合

let HTMLPlugins = [];

// 入口文件集合

let Entries = {}

 

// 生成多頁面的集合

config.HTMLDirs.forEach((page) => {

    const htmlPlugin = new HTMLWebpackPlugin({

        filename: `${page}.html`,

        template: path.resolve(__dirname, `../app/html/${page}.html`),

        chunks: [page, 'commons'],

    });

    HTMLPlugins.push(htmlPlugin);

    Entries[page] = path.resolve(__dirname, `../app/js/${page}.js`);

})

 

module.exports = {

    entry:Entries,

    devtool:"cheap-module-source-map",

    output:{

        filename:"js/[name].bundle.[hash].js",

        path:path.resolve(__dirname,"../dist")

    },

    // 加載器

    module:{

        rules:[

            {

                // 對 css 後綴名進行處理

                test:/\.css$/,

                // 不處理 node_modules 文件中的 css 文件

                exclude: /node_modules/,

                // 抽取 css 文件到單獨的文件夾

                use: ExtractTextPlugin.extract({

                    fallback: "style-loader",

                    // 設置 css 的 publicPath

                    publicPath: config.cssPublicPath,

                    use: [{

                            loader:"css-loader",

                            options:{

                                // 開啓 css 壓縮

                                minimize:true,

                            }

                        },

                        {

                            loader:"postcss-loader",

                        }

                    ]

                })

            },

            {

                test: /\.js$/,

                exclude: /node_modules/,

                use: {

                    loader: 'babel-loader',

                    options: {

                        presets: ['env']

                    }

                }

            },

            {

                test: /\.(png|svg|jpg|gif)$/,

                use:{

                    loader:"file-loader",

                    options:{

                        // 打包生成圖片的名字

                        name:"[name].[ext]",

                        // 圖片的生成路徑

                        outputPath:config.imgOutputPath

                    }

                }

            },

            {

                test: /\.(woff|woff2|eot|ttf|otf)$/,

                use:["file-loader"]

            }

        ],

    },

    plugins:[

        // 自動清理 dist 文件夾

        new CleanWebpackPlugin(["dist"]),

        // 將 css 抽取到某個文件夾

        new ExtractTextPlugin(config.cssOutputPath),       

        // 自動生成 HTML 插件

        ...HTMLPlugins

    ],

}

webpack.config.dev.js

// 引入基礎配置文件

const webpackBase = require("./webpack.config.base");

// 引入 webpack-merge 插件

const webpackMerge = require("webpack-merge");

// 引入配置文件

const config = require("./config");

// 合併配置文件

module.exports = webpackMerge(webpackBase,{

    // 配置 webpack-dev-server

    devServer:{

        // 項目根目錄

        contentBase:config.devServerOutputPath,

        // 錯誤、警告展示設置

        overlay:{

            errors:true,

            warnings:true

        }

    }

});

webpack.config.prod.js

// 引入基礎配置

const webpackBase = require("./webpack.config.base");

// 引入 webpack-merge 插件

const webpackMerge = require("webpack-merge");

// 引入 webpack

const webpack = require("webpack");

// 合併配置文件

module.exports = webpackMerge(webpackBase,{

    plugins:[

        // 代碼壓縮

        new webpack.optimize.UglifyJsPlugin({

            // 開啓 sourceMap

            sourceMap: true

        }),

        // 提取公共 JavaScript 代碼

        new webpack.optimize.CommonsChunkPlugin({

            // chunk 名爲 commons

            name: "commons",

            filename: "[name].bundle.js",

        }),

    ]

});

webpack.config.lint.js

const webpackBase = require("./webpack.config.base");

const webpackMerge = require("webpack-merge");

const config = require("./config");

module.exports = webpackMerge(webpackBase,{

    module:{

        rules:[

            {

                test: /\.js$/,

                // 強制先進行 ESLint 檢查

                enforce: "pre",

                // 不對 node_modules 和 lib 文件夾中的代碼進行檢查

                exclude: /node_modules|lib/,

                loader: "eslint-loader",

                options: {

                    // 啓用自動修復

                    fix:true,

                    // 啓用警告信息

                    emitWarning:true,

                }

            },

        ]

    },

    devServer:{

        contentBase:config.devServerOutputPath,

        overlay:{

            errors:true,

            warnings:true

        }

    }

});

項目結構

│  .babelrc

│  .eslintrc.js

│  .gitignore

│  package.json

│  postcss.config.js

│  webpack.config.js

│ 

├─app

│  │  favicon.ico

│  │ 

│  ├─css

│  │      main.css

│  │     

│  ├─html

│  │      index.html

│  │   

│  │     

│  ├─img

│  │      back.png

│  │     

│  ├─js

│  │      ajax.js

│  │      footer.js

│  │      index.js

│  │      nav.js

│  │      public.js

│  │      tity_nav.js

│  │     

│  └─lib

│        flexible.js

│        normalize.css

│        swiper.css

│        swiper.js

│       

└─config

        config.js

        webpack.config.base.js

        webpack.config.dev.js

        webpack.config.lint.js

        webpack.config.prod.js

      •  
      •  
      •  
      •  

註釋:

想引用jquery而不是每個頁面都引用只需要:
引入jquery後如果開啓lint檢查模式 可以正常使用的前提是每個頁面都require 一次

  • webpack.config.base.js

cnpm i jquery --save

 

const ProvidePlugin = new webpack.ProvidePlugin({

    $: 'jquery',

    jQuery: 'jquery',

});

引入sass

  • webpack.config.base.js

{

    // s?css => scss或者css

    test:/\.s?css$/,

    // 不處理 node_modules 文件中的 css 文件

    exclude: /node_modules/,

    // 抽取 css 文件到單獨的文件夾

    use: ExtractTextPlugin.extract({

        fallback: "style-loader",

        // 設置 css 的 publicPath

        publicPath: config.cssPublicPath,//在 css 中設置背景圖像的 url 時,經常會找不到圖片(默認會在 css 文件所在的文件夾中尋找),這裏設置 extract-text-webpack-plugin 插件的 publicPath 爲圖片文件夾所在的目錄,就可以順利找到圖片了

        use: [{

                loader:"css-loader",

                options:{

                    // 開啓 css 壓縮

                    minimize:true,

                }

            },

            {

                loader:"postcss-loader",

            },

            {

                loader:"sass-loader",

                //啓用sass 雖然在這隻寫了sass-loader 但還要下載node-sass

            }

        ]

    })

},

如果import了類似swiper這種庫函數 但不處理modules裏面的swiper,所以這裏要允許除了node_modules裏面的swiper的其他所有文件

  • webpack.config.base.js

{

    test: /\.js$/,

    exclude: /^node_modules*swiper$/,

    use: {

        loader: 'babel-loader',

        options: {

            presets: ['env']

        }

    }

},

➳ github地址:點我

原文地址:https://segmentfault.com/a/1190000017565103

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章