iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 23
0
Modern Web

重新學習網頁設計系列 第 23

DAY 23. Webpack 設定

DAY 23. Webpack 設定

由於近幾年前端需求變化之大,因此各類相關技術演進速度劇增
作為核心的JavaScript當然不在話下,若遲遲不肯跟進自己的開發流,恐怕很難跟上時代

以最基本的JS向下編譯器, CSS預處理器來說分別可以使用babel, Sass
接著還要處理一些瀏覽器不支援的API, 所以需要Polyfill

本篇文章將分享個人的幾個Config File並依序解釋其意義
經編譯過後的js相容於大多數的瀏覽器, 而CSS則相容於各瀏覽器的最新版本。

install packages

這裡是我常用的一些package包含vueaxios,其他都是一些webpack loader

$ npm install axios --save-dev
$ npm install vue --save-dev
$ npm install vue-template-compiler@"same version of vue"
$ npm install babel-core babel-plugin-transform-runtime babel-polyfill babel-preset-env babel-preset-stage-2 copy-webpack-plugin extract-text-webpack-plugin babel-loader file-loader postcss-loader sass-loader css-loader style-loader vue-loader webpack node-sass --save-dev

webpack.config.js

webpack.config.js此檔案大多建立於網站根目錄
當然我們也可以建立在子目錄之中,並且在執行webpack時特別指定設定檔路徑


// nodejs path module
const path = require('path')

// webpack
const webpack = require('webpack')

// 這個插件可以複製檔案,有時候我們並不想對某些檔案做處理,只想單純使用它,就可以用這個插件
const CopyWebpackPlugin = require('copy-webpack-plugin')

// 這個插件可以用來提取CSS程式, 使其變成一個獨立CSS檔
const ExtractTextPlugin = require("extract-text-webpack-plugin")

// 這個變數儲存目前 env, 可以用這個變數決定要不要壓縮程式碼等等
const isProduction = (process.env.NODE_ENV === 'production')

// 定義網站根目錄函數
const root = src => path.join(__dirname, './', src)

// 定義一個方便取得路徑的函數
const src = file => path.join(root('resource/script'), file)

// 隱藏警告
process.noDeprecation = true

// 設定檔主體
module.exports = {
    /**
     | 進入點,可以是單一字串或物件
     | 如果是物件,每一個key都會是一個檔案
     */
    entry: {
        app: [
            './resource/script/main.js',
            './resource/style/main.scss'
        ],
        'vendor.bundle': [
            'vue', 'axios'
        ]
    },
    /*
     | 結果輸出的資料夾
     | [name].js的 name 將會是entry 物件的 key
     */
    output: {
        path: path.resolve(__dirname, 'dist/assets/'),
        filename: '[name].js',
    },
    /*
     | 這裡開始定義對哪些檔案使用哪些loader.
     */
    module: {
        // rules 是一個陣列,接受多個物件
        rules: [
            // 規則一 編譯sass/scss file
            {
                // 副檔名規則
                test: /\.(s[ac]ss)$/,
                // 排除目錄
                exclude: [/node_modules/],
                /* 
                 | 由於我們要將結果提取出來因此這裡使用 ExtractTextPlugin插件
                 | 注意這裡 use 是一個陣列, 程式將會依序調用陣列裡的元素
                 | sass-loader -> postcss-loader -> css-loader -> style-loader
                 | 而css-loader的 options.url = false 代表不特別處理CSS裡的URL例如圖片網址
                 */
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: [{
                        loader: 'css-loader',
                        options: {
                            url: false
                        }
                    }, {
                        loader: 'postcss-loader'
                    }, {
                        loader: 'sass-loader',
                    }]
                })
            },
            // 規則一 編譯js file
            {
                // 副檔名
                test: /\.js$/,
                // 排除目錄
                exclude: /(node_modules|bower_components)/,
                // 使用 babel-loader, 我們將把babel設定寫在 .babelrc檔案之中
                use: {
                    loader: 'babel-loader'
                }
            },
            // 規則三 編譯vue file
            {
                // 副檔名
                test: /\.vue$/,
                // 使用 vue-loader, 切記若編譯時出現錯誤,可能是vue與vue-template-compiler的版本不符
                use: {
                    loader: 'vue-loader',
                    // 不處理檔案中的url
                    options: {
                        url: false
                    }
                }
            }
        ]
    },

    resolve: {
        /*
         | alias 設定,我們可以在此定義自己需要的alias
         | 在此我將 `~` 定義為網站根目錄的 alias
         | 因此能夠在js file中使用類似 import Foo form '~/components/Foo' 而不需帶副檔名
         */
        alias: {
            vue: 'vue/dist/vue.js',
            '~': src('/')
        },
        /*
         | 當我們使用 import 或 require 不帶副檔名時
         | webpack 將會依序嘗試以下副檔名
         */
        extensions: ['.js', '.vue', '.json']
    },

    plugins: [
        /*
         | 這個插件能夠確保我們在編譯時,排除一些第三方 lib
         */
        new webpack.optimize.CommonsChunkPlugin({
            names: ['vendor.bundle']
        }),
        /*
         | 提取CSS file 
         */
        new ExtractTextPlugin({
            filename: "style.css",
            disable: false,
            allChunks: true
        }),
        /*
         | 如果執行環境是 Production, 那麼就將程式 minimize
         */
        new webpack.LoaderOptionsPlugin({
            minimize: isProduction
        }),
        /*
         | 這個插件會將存在from裡的檔案複製到 output目錄中
         | 或是我可以額外定義目的地 `to`
         */
        new CopyWebpackPlugin([
            {
                from: 'resource/script/three'
                // to: 'a/path/we/want/to/store/file'
            },
            {
                from: 'resource/image'
            }
        ])
    ]
}

.babelrc

.babelrcbabel的設定檔
通常建立於網站根目錄,另外也可以將babel設定寫在package.json或是webpack.config.js裡頭
但將設定檔獨立出來有助於增加可讀性,因此只建議使用.babelrc

{
    /*
     | babel-preset-env, 包含了所有最新的API
     | 有了它我們就不必指定要es6, es7 或更新 
     */
    "presets": [
        [
            "env",
            {
                "modules": false
            }
        ],
        /*
         | 每個API要成為正式的API都必須經過4個階段(0-3)
         | 這裡我們建議使用到 stage-2 階段的API
         */
        "stage-2"
    ],
    "plugins": [
        [
            "transform-runtime",
            {
                // 切換是否將內聯的Babel幫助器(classCallCheck,extends等)替換為對moduleName的調用。
                // default true
                "helpers": true,
                // 切換是否將新的內置(Promise,Set,Map等)轉換為使用非全局污染的polyfill。
                // default true, 由於個人都會在專案中引入polyfill因此改為false.
                "polyfill": false,
                // 切換是否將生成器函數轉換為使用不會污染全局作用域的再生器運行時。
                // default true
                "regenerator": true
            }
        ]
    ],
    // 不保留註解
    "comments": false
}

postcss.config.js

此設定用於postcss,且一如往常的建議放於根目錄即可

// 在這裡我只用於做 autoprefix
const autoprefixer = require('autoprefixer')

module.exports = {
    plugins: [
        autoprefixer({ browsers: ['last 2 versions'] })
    ]
}

結語

大多的設定檔預設系統都會去根目錄抓
但有時使用的工具多了,設定檔自然會跟著很多,屆時當然有必要整理
但個人偏好是若專案不大,其實簡單放根目錄清晰易懂。

關於webpack的使用,本人也持續在模索中
大多數的插件在Webpack官網搜尋中都能找到相關教學
在這分享的是我目前專案上所用的設定方式,希望對大家有用
如果大家看完後發現哪裡奇怪,或使用後發生問題也歡迎一起討論解決。


上一篇
DAY 22. Three.js 總結
下一篇
DAY 24. JavaScript Fetch API
系列文
重新學習網頁設計30

尚未有邦友留言

立即登入留言