摘要:時至今日,已經成為前端工程必備的基礎工具之一,不僅被廣泛用于前端工程發布前的打包,還在開發中擔當本地前端資源服務器模塊熱更新等角色,結合等代碼檢查工具,還可以實現在對源代碼的嚴格校驗檢查。
時至今日,Webpack 已經成為前端工程必備的基礎工具之一,不僅被廣泛用于前端工程發布前的打包,還在開發中擔當本地前端資源服務器(assets server)、模塊熱更新(hot module replacement)、API Proxy 等角色,結合 ESLint 等代碼檢查工具,還可以實現在對源代碼的嚴格校驗檢查。
正如上文中提到的,前端從開發到部署前都離不開 Webpack 的參與,而 Webpack 的默認配置文件只有一個,即 webpack.config.js,那么問題來了,開發期和部署前應該使用同一份 Webpack 配置嗎?答案肯定是否定的,既然 webpack.config.js 是一個 JS 文件,我們當然可以在文件里寫 JavaScript 業務邏輯,通過讀取環境變量 NODE_ENV 來判斷當前是在開發(dev)時還是最終的生產環境(production),然而很多同學習慣把這兩者的配置都混寫在根目錄下的 webpack.config.js,通過很多零散的 if…else 來“臨時”決定某一個 plugin 或者某一個 loader 的配置項,隨著 loaders 和 plugins 的不斷增加,久而久之 webpack.config.js 變得原來越隆長,代碼的可讀性和可維護性也大大下降。
我想通過本文來介紹一種用 3 個 JS 文件來配置 Webpack 的方法,這里借鑒了很多開源項目的配置,同時也結合了我們自己在開發中碰到的種種問題解決方案。
本文中提及的配置基于 Webpack 2 或以上,建議使用 3.0 及以上版本
開發環境與生產環境的區別
開發環境
NODE_ENV 為 development
啟用模塊熱更新(hot module replacement)
額外的 webpack-dev-server 配置項,API Proxy 配置項
輸出 Sourcemap
生產環境
NODE_ENV 為 production
將 React、jQuery 等常用庫設置為 external,直接采用 CDN 線上的版本
樣式源文件(如 css、less、scss 等)需要通過 ExtractTextPlugin 獨立抽取成 css 文件
啟用 post-css
啟用 optimize-minimize(如 uglify 等)
中大型的商業網站生產環境下,是絕對不能有 console.log() 的,所以要為 babel 配置 Remove console transform
這里需要說明的是因為開發環境下啟用了 hot module replacement,為了讓樣式源文件的修改也同樣能被熱替換,不能使用 ExtractTextPlugin,而轉為隨 JS Bundle 一起輸出。
你需要三份配置文件
在 base 文件里,你需要將開發環境和生產環境中通用的配置集中放在這里:
const CleanWebpackPlugin = require("clean-webpack-plugin");
const path = require("path");
const webpack = require("webpack");
// 配置常量
// 源代碼的根目錄(本地物理文件路徑)
const SRC_PATH = path.resolve("./src");
// 打包后的資源根目錄(本地物理文件路徑)
const ASSETS_BUILD_PATH = path.resolve("./build");
// 資源根目錄(可以是 CDN 上的絕對路徑,或相對路徑)
const ASSETS_PUBLIC_PATH = "/assets/";
module.exports = {
context: SRC_PATH, // 設置源代碼的默認根路徑
resolve: {
extensions: [".js", ".jsx"] // 同時支持 js 和 jsx
},
entry: {
// 注意 entry 中的路徑都是相對于 SRC_PATH 的路徑
vendor: "./vendor",
a: ["./entry-a"],
b: ["./entry-b"],
c: ["./entry-c"]
},
output: {
path: ASSETS_BUILD_PATH,
publicPath: ASSETS_PUBLIC_PATH,
filename: "./[name].js"
},
module: {
rules: [
{
enforce: "pre", // ESLint 優先級高于其他 JS 相關的 loader
test: /.jsx?$/,
exclude: /node_modules/,
loader: "eslint-loader"
},
{
test: /.jsx?$/,
exclude: /node_modules/,
// 建議把 babel 的運行時配置放在 .babelrc 里,從而與 eslint-loader 等共享配置
loader: "babel-loader"
},
{
test: /.(png|jpg|gif)$/,
use:
[
{
loader: "url-loader",
options:
{
limit: 8192,
name: "images/[name].[ext]"
}
}
]
},
{
test: /.woff(2)?(?v=[0-9].[0-9].[0-9])?$/,
use:
[
{
loader: "url-loader",
options:
{
limit: 8192,
mimetype: "application/font-woff",
name: "fonts/[name].[ext]"
}
}
]
},
{
test: /.(ttf|eot|svg)(?v=[0-9].[0-9].[0-9])?$/,
use:
[
{
loader: "file-loader",
options:
{
limit: 8192,
mimetype: "application/font-woff",
name: "fonts/[name].[ext]"
}
}
]
}
]
},
plugins: [
// 每次打包前,先清空原來目錄中的內容
new CleanWebpackPlugin([ASSETS_BUILD_PATH], { verbose: false }),
// 啟用 CommonChunkPlugin
new webpack.optimize.CommonsChunkPlugin({
names: "vendor",
minChunks: Infinity
})
]
};
這是用于開發環境的 Webpack 配置,繼承自 base:
const webpack = require("webpack");
// 讀取同一目錄下的 base config
const config = require("./webpack.base.config");
// 添加 webpack-dev-server 相關的配置項
config.devServer = {
contentBase: "./",
hot: true,
publicPath: "/assets/"
};
// 有關 Webpack 的 API 本地代理,另請參考 https://webpack.github.io/docs/webpack-dev-server.html#proxy
config.module.rules.push(
{
test: /.less$/,
use: [
"style-loader",
"css-loader",
"less-loader"
],
exclude: /node_modules/
}
);
// 真實場景中,React、jQuery 等優先走全站的 CDN,所以要放在 externals 中
config.externals = {
react: "React",
"react-dom": "ReactDOM"
};
// 添加 Sourcemap 支持
config.plugins.push(
new webpack.SourceMapDevToolPlugin({
filename: "[file].map",
exclude: ["vendor.js"] // vendor 通常不需要 sourcemap
})
);
// Hot module replacement
Object.keys(config.entry).forEach((key) => {
// 這里有一個私有的約定,如果 entry 是一個數組,則證明它需要被 hot module replace
if (Array.isArray(config.entry[key])) {
config.entry[key].unshift(
"webpack-dev-server/client?http://0.0.0.0:8080",
"webpack/hot/only-dev-server"
);
}
});
config.plugins.push(
new webpack.HotModuleReplacementPlugin()
);
module.exports = config;
這是用于生產環境的 webpack 配置,同樣繼承自 base:
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
// 讀取同一目錄下的 base config
const config = require("./webpack.base.config");
config.module.rules.push(
{
test: /.less$/,
use: ExtractTextPlugin.extract(
{
use: [
"css-loader",
"less-loader"
],
fallback: "style-loader"
}
),
exclude: /node_modules/
}
);
config.plugins.push(
// 官方文檔推薦使用下面的插件確保 NODE_ENV
new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "production")
}),
// 啟動 minify
new webpack.LoaderOptionsPlugin({ minimize: true }),
// 抽取 CSS 文件
new ExtractTextPlugin({
filename: "[name].css",
allChunks: true,
ignoreOrder: true
})
);
module.exports = config;
現在在你的工程文件夾里應該已經有三個 Webpack 配置文件,它們分別是:
webpack.base.config.js
webpack.dev.config.js
webpack.config.js
最后,你還需要在 package.json 里添加相應的配置:
{
...
"scripts": {
"build": "webpack --optimize-minimize",
"dev": "webpack-dev-server --config webpack.dev.config.js",
"start": "npm run dev" // 或添加你自己的 start 邏輯
},
...
}
和很多項目一樣,在開發環境下的時候,你需要使用 npm run dev 來啟動,而在生產環境中,則用 npm run build 來發布。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/2255.html
摘要:用函數式編程對進行斷舍離當從業的老司機學會函數式編程時,他扔掉了的特性,也不用面向對象了,最后發現了真愛啊作用域和閉包作用域和閉包在里非常重要。旨在幫助非函數式編程的同學,能快速切入到函數式編程的理念。 1、用函數式編程對JavaScript進行斷舍離 當從業20的JavaScript老司機學會函數式編程時,他扔掉了90%的特性,也不用面向對象了,最后發現了真愛?。。?! https:/...
摘要:用函數式編程對進行斷舍離當從業的老司機學會函數式編程時,他扔掉了的特性,也不用面向對象了,最后發現了真愛啊作用域和閉包作用域和閉包在里非常重要。旨在幫助非函數式編程的同學,能快速切入到函數式編程的理念。 1、用函數式編程對JavaScript進行斷舍離 當從業20的JavaScript老司機學會函數式編程時,他扔掉了90%的特性,也不用面向對象了,最后發現了真愛啊?。?! https:/...
摘要:用函數式編程對進行斷舍離當從業的老司機學會函數式編程時,他扔掉了的特性,也不用面向對象了,最后發現了真愛啊作用域和閉包作用域和閉包在里非常重要。旨在幫助非函數式編程的同學,能快速切入到函數式編程的理念。 1、用函數式編程對JavaScript進行斷舍離 當從業20的JavaScript老司機學會函數式編程時,他扔掉了90%的特性,也不用面向對象了,最后發現了真愛?。。?! https:/...
摘要:主要做了兩套方案,一套是基于的單頁應用,還有一套就是多頁應用。麻煩的是原先使用這個方案。這太麻煩了,還不如使用一步到位。后記暫時只做了這些,這套工具還沒有正式投入使用估計會有挺多問題的。 不想看下面廢話的,可以直接看這里。 前言 這兩周負責公司前端基礎工程的建設。主要做了兩套方案,一套是基于vue的單頁應用,還有一套就是多頁應用。對于vue單頁這塊是沒什么問題的,直接用vue-cli生...
摘要:如果采用導出一個來描述所需配置的方法需要寫兩個文件。再在啟動時通過指定使用哪個配置文件。例如啟動命令是時,則的值是。采用描述的一份配置采用函數描述的一份配置采用異步函數描述的一份配置以上配置會導致針對這三份配置執行三次不同的構建。 除了通過導出一個Object來描述webpack所需要的配置,還有其他更靈活的方式,以簡化不同場景的配置。下面來一一介紹它們。 1. 導出一個Functio...
閱讀 1117·2021-11-25 09:43
閱讀 1639·2021-09-13 10:25
閱讀 2592·2021-09-09 11:38
閱讀 3400·2021-09-07 10:14
閱讀 1714·2019-08-30 15:52
閱讀 641·2019-08-30 15:44
閱讀 3572·2019-08-29 13:23
閱讀 1974·2019-08-26 13:33