webpack在前端項目中使用心得一二

webpack作文件合併

使用構建工具很是經常使用一個功能就是合併js和css文件,gulp和grunt都是編寫相應的任務來完成,轉到webpack忽然懵逼了,簡單的項目怎麼作文件合併呢?其實只需把多個js文件同時引入到main.js(入口文件)中便可,css藉助extract-text-webpack-plugin搞定。css

無論是簡單的純展現頁面仍是複雜的單頁或多頁面,webpack差很少能夠完全取代gulp、grunt了,利用file、scss、pug、babel等各類loader處理各類需求比grunt那種編寫任務型的配置方便太多。html

webpack很是智能,屢次引入相同模塊,最終打包後只會包含一次。若是你不想打包某個模塊,在webpack.config.js裏配置externals便可。對於css模塊,externals是無效的,js裏不引入,直接在html裏放link就行了,不要陷入webpack的魔障。對於一些老舊的jq插件,能夠配置providePlugin或使用expose-loader,用法就自行google了。熟悉了以後,各類新舊項目,大小項目都能用webpack耍的飛起。前端

// webpack.config.js
// ...

externals: {
    'vue': 'Vue',
    'jquery': 'jQuery',
},

webpack-dev-server跨域設置

開發的時候常常有跨域需求,前端跨域方法雖然不少,可是隻是爲了開發時用用,感受沒一個好用的。利用webpack-dev-server能夠輕鬆解決開發時跨域問題,devServer啓動了一個node服務器幫你代理請求,詳細配置請看proxy,這個設置是將全部以/api開頭的路由映射到xxx.com,target記得帶上協議名哦(http://)。pathRewrite就是將/api/a路徑重寫爲/a。固然你也能夠配置爲/轉發請求,這樣靜態資源也能夠在localhost下請求到了。跨域的前提是服務器上配置了'Access-Control-Allow-Origin:*',開發時服務器端通常都設置了。vue

// webpack.config.js
// ...

devServer: {
    port: 8888,
    historyApiFallback: true,
    stats: 'minimal',  // 輸入精簡信息
    overlay: true, // 將錯誤顯示在html之上
    proxy: {
        '/api': {
            target: 'http://xxx.com',
            secure: false,
            changeOrigin: true,
            // pathRewrite: {'^/api': ''},
        }
    }
},

webpack-dev-server熱更新失效

自從用了webpack-dev-server,個人f5鍵長舒一口氣,不過有時候碰到webpack-dev-server熱更新回失效,通常是配置出了問題。只需在pulugins裏添加HotModule插件,devServer不要配置hot:true了,雖然文檔裏寫的是設置hot:true開啓熱更新,可是我試過配置hot熱更新就失效了,不解!node

// webpack.config.js
// ...

plugins: [
        new webpack.HotModuleReplacementPlugin(), // 熱加載
]

2017.9.30更新:
webpack文檔裏寫的是命令行加上 -hot 啓用熱更新模式,不用手動加hrm plugin。
使用extract-text-webpack-plugin和html模版(例如:art-template)時,修改html和css不會觸發熱更新,只有js變更能夠觸發。由於這些loader沒有實現hmr相關api,能夠經過安裝css-hot-loader等來hack
有個簡便方法,配置devServer:watchContentBase: true,開啓watch模式,文件有改動就會觸發自動刷新,雖然性能稍差。jquery

使用pug(jade)做爲vue文件中的html模板

npm安裝pug,記住不是pug-loader,也不用配置vue-loader,只需在template標籤中指定lang=pug,就能夠愉快的使用pug語法了,比起html看起來簡潔多了。webpack

<template lang="pug">
    header
        .logo
        h1 我是頭部
</template>

html-webpack-plugin在多頁面中的妙用

之前只用webpack寫單頁引用,index.html就是個空殼,後來也有一些純展現頁面,包含多個html文件,也想用webpack,畢竟各類loader太好用了。這時候就須要好好利用html-webpack-plugin了。直接上一個webpack配置,基於vue-simple的webpack配置作了些修改,同時參考了歪鬧大神的webpack多頁面教程,利用glod獲取文件名,自動生成html-webpack-plugin配置,so geek!利用pug寫html,scss寫css,做爲一個頁面仔,也不那麼無聊了,效率也是槓槓滴。git

let path = require('path');
let webpack = require('webpack');
let ExtractTextPlugin = require('extract-text-webpack-plugin');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let glob = require('glob');

// js名必須與html的fileName對應
let entry = (() => {
    let obj = {};
    getEntry('src/views/pages/*.pug').forEach(fileName => {
        obj[fileName] = './src/js/' + fileName + '.js';
    });
    return obj;
})();

module.exports = {
    entry: entry,
    output: {
        path: path.resolve(__dirname, './dist'),
        publicPath: '/dist/',
        filename: 'js/[name].js',
        // chunkFilename: 'js/[name][id].chunk.js', // 公共代碼塊
    },
    externals: {
        // 'vue': 'Vue',
        // 'jquery': 'jQuery',
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    loaders: {
                        scss: ExtractTextPlugin.extract({
                            fallback: 'vue-style-loader',
                            use: 'css-loader!sass-loader',
                        }),
                    }
                }
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/
            },
            // 不要使用options配置url-loader webpack會報錯
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader?limit=10000&name=img/[name].[hash:7].[ext]',
            },
            {
                test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
                loader: 'file-loader?limit=10000&name=img/[name].[hash:7].[ext]',
            },
            {
                test: /\.scss$/,
                loader: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: 'css-loader!postcss-loader!sass-loader'
                })
            },
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: 'css-loader!postcss-loader'
                })
            },
            {
                test: /\.html$/,
                loader: 'html-loader?attrs=img:src img:data-src'
            },
            {
                test: /\.pug$/,
                loader: 'pug-loader'
            },
        ]
    },
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {}
    },
    devServer: {
        port: 8888,
        historyApiFallback: true,
        stats: 'minimal',  // 輸入精簡信息
        overlay: true, // 將錯誤顯示在html之上
        proxy: {
            '/api': {
                target: 'http://localhost:9999',
                secure: false,
                changeOrigin: true,
                // pathRewrite: {'^/api': ''},
            }
        }
    },
    performance: {
        hints: false
    },
    devtool: '#eval-source-map',
    plugins: [
        new webpack.HotModuleReplacementPlugin(), // 熱加載

        // new webpack.ProvidePlugin({
        //     $: 'jquery',
        //     jQuery: 'jquery',
        // }),

        new ExtractTextPlugin('css/[name].css'), //單獨使用link標籤加載css並設置路徑,相對於output配置中的publicPath

    ],
};

if (process.env.NODE_ENV === 'production') {
    module.exports.devtool = '#source-map';
    // http://vue-loader.vuejs.org/en/workflow/production.html
    module.exports.plugins = (module.exports.plugins || []).concat([
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: '"production"'
            }
        }),
        new webpack.optimize.UglifyJsPlugin({
            sourceMap: true,
            compress: {
                warnings: false
            }
        }),
        new webpack.LoaderOptionsPlugin({
            minimize: true
        })
    ]);
}

// 自動生htmlPlugins
getEntry('src/views/pages/*.pug').forEach(fileName => {
    let conf = {
        filename: fileName + '.html', //生成的html存放路徑,相對於path
        template: 'src/views/pages/' + fileName + '.pug', //html模板路徑
        inject: true,
        hash: true,
        minify: {
            removeComments: true,
            minifyJS: true,
        },
        chunks: [fileName],
    };
    module.exports.plugins.push(new HtmlWebpackPlugin(conf));
});

// 獲取文件名函數
function getEntry(viewsPath) {
    let files = glob.sync(viewsPath);
    let entries = [];
    let entry, basename, extname;

    for (let i = 0; i < files.length; i++) {
        entry = files[i];
        extname = path.extname(entry); // 擴展名 eg: .html
        basename = path.basename(entry, extname);  // eg: index
        entries.push(basename);
    }
    return entries;
}

路徑 —— alias別名和~的使用

alias:{github

'@': path.resolve(__dirname, 'src')

}web

import路徑中使用別名是一個很好的實踐,將@指向src,咱們import的時候以@/開頭,在各層目錄裏就能用各類../

若是你想在css或html使用@,請在前面加上~告訴webpack用require處理他。

例如在是scss裏導入其餘node_modules裏的css文件 @import "~swiper/dist/css/style.css"

例如在是scss裏導入其餘src下的css文件 @import "~@/css/mixin.css"

相關文章
相關標籤/搜索