從零開始配置webpack react開發(fā)環(huán)境

首先初始化項(xiàng)目

npm init

一脏嚷、安裝webpack

要安裝最新版本或特定版本,請(qǐng)運(yùn)行以下命令之一:

npm install --save-dev webpack
npm install --save-dev webpack@<version>

如果你使用 webpack 4+ 版本,你還需要安裝 CLI羽德。

npm install --save-dev webpack-cli

二几莽、新建文件目錄

mkdir ./src ./public ./src/components
vim ./src/index.js
vim ./src/components/HellowWord.js
vim ./public/index.html


# 文件目錄格式
|-- Webpack
    |-- package-lock.json
    |-- package.json
    |-- webpack.config.js
    |-- public
    |-- src
        |-- index.js

<!-- public/index.js-->
<body>
  <div id="app"></div>
</body>
// src/index.js
import React from "react";
import HelloWorld from "./components/HellowWorld";

class App extends React.Component {
  render() {
    return <HelloWorld />;
  }
}

ReactDOM.render(<App />, document.getElementById("app"));
// src/components/HelloWorld.js

import React from "react";

export default class App extends React.Component {
  render() {
    return <h1>Hello World</h1>;
  }
}

三、配置加載器

3.1 構(gòu)建簡(jiǎn)單的webpack.common.js配置文件

根據(jù)上述文件目錄結(jié)構(gòu)宅静,新建配置文件 public/webpack.common.js

const path = require("path");
const webpack = require("webpack");

function resolve(dir) {
  return path.join(__dirname, "..", dir);
}

module.exports = {
  entry: "./src/index.js",
  output: {
    path: util.resolve("dist"),
    filename: "[name].js",
    chunkFilename: "[chunkhash].js",
    jsonpFunction: "myWebpackJsonp"
  }
};

packge.json添加

"scripts": {
  "dev": "webpack --config ./build/webpack.common.js"
},

嘗試運(yùn)行npm run dev

ERROR in ./src/index.js 7:11
Module parse failed: Unexpected token (7:11)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| class App extends React.Component {
|   render() {
>     return <HelloWorld />;
|   }
| }

webpack告訴我們需要使用加載器來處理該文件章蚣,針對(duì) react 文件,需要使用babel-loader姨夹,對(duì)于其他的格式文件纤垂,需要進(jìn)行配置。

由于配置中會(huì)用到一些工具磷账,所以新建/build/util.js峭沦,引入util.js

const path = require("path");

//返回項(xiàng)目根目錄下的dir路徑
exports.resolve = function resolve(dir) {
  return path.join(__dirname, "..", dir);
};

//返回dits中文件路徑下的dir路徑
exports.staticPath = function resolve(dir) {
  return path.join("static/", dir);
};

3.2 配置babel-loader

npm install -D babel-loader @babel/core @babel/preset-env @babel/preset-react

webpack.config.js添加 babel 配置

...

module: {
  rules: [
    {
      test: /\.js?$/,
      include: [util.resolve('src')],
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env', '@babel/preset-react']
        }
      }
    }
  ]
}
...

3.3 配置.css .scss文件 loader

sass-loader依賴node-sass,由于這個(gè)包存放在 github 上逃糟,下載速度比較慢吼鱼,可使用淘寶源下載

npm install sass-loader node-sass css-loader style-loader --save-dev --registry https://registry.npm.taobao.org

webpack.config.jsrules 添加配置

...

  {
    test: /\.css$/,
    use: [{ loader: "style-loader" }, { loader: "css-loader" }]
  },
  {
    test: /\.scss$/,
    use: [
      { loader: "style-loader" }, // 將 JS 字符串生成為 <style> 節(jié)點(diǎn)
      { loader: "css-loader" }, // 將 CSS 轉(zhuǎn)化成 CommonJS 模塊
      { loader: "sass-loader" } // 將 Sass 編譯成 CSS
    ]
  }

...

3.4 配置圖片文件的加載

關(guān)于圖片或文件的相關(guān)loader

  • file-loader默認(rèn)情況下,生成的文件的文件名就是文件內(nèi)容的 MD5 哈希值并會(huì)保留所引用資源的原始擴(kuò)展名履磨。

  • url-loader 功能類似于 file-loader蛉抓,但是在文件大小(單位 byte)低于指定的限制時(shí)剃诅,可以返回一個(gè) DataURL巷送。?? 注意url-loader依賴 file-loader

這里選擇使用url-loader

npm install --save-dev url-loader file-loader

webpack.config.jsrules 添加配置

...

  {
    test: /\.(png|jpg|jpeg|gif)$/,
    use: [
      {
        loader: 'url-loader',
        options: {
          limit: 6000,
          name: util.staticPath('images/[name][hash].[ext]'),
        }
      }
    ]
  }

...

四、開發(fā)環(huán)境構(gòu)建

區(qū)分productiondevelopment環(huán)境下的配置

vim ./build/webpack.dev.js ./build/webpack.prod.js

4.1 安裝相關(guān)功能依賴

# 用于合并webpack配置
npm install --save-dev webpack-merge

# 分別用于構(gòu)建時(shí)清除dist目錄和拷貝處理index.html
npm install --save-dev clean-webpack-plugin html-webpack-plugin

# 用于啟動(dòng)開發(fā)服務(wù)器
npm install webpack-dev-server -D

# 用于開發(fā)時(shí)模塊熱重載
npm install hot-module-replacement-plugin -D

# 產(chǎn)品模式壓縮js
npm install uglifyjs-webpack-plugin -D

# 提取css矛辕、壓縮css(替代ExtractTextWebpackPlugin)
npm install mini-css-extract-plugin -D

# 注入process.env變量
npm install cross-env -D

?? 需要注意的是:在 css 文件的loader配置中MiniCssExtractPlugin.loaderstyle-loader不能同時(shí)使用笑跛。


const devMode = process.env.NODE_ENV !== 'production'
...
{
  test: /\.css$/,
  use: [
    devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
    "css-loader"
  ]
},
{
  test: /\.scss$/,
  use: [
    devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
    { loader: "css-loader" }, // 將 CSS 轉(zhuǎn)化成 CommonJS 模塊
    { loader: "sass-loader" } // 將 Sass 編譯成 CSS
  ]
},
...

修改webpack.prod.js

...
plugins: [
  new HtmlWebpackPlugin({
    template: util.resolve('public/index.html'),
    filename: util.resolve('dist/index.html'),
    favicon: util.resolve('public/favicon.ico')
  }),
],
resolve: {
  extensions: [".js", ".json", ".jsx", ".css"],
  alias: {
    '@': util.resolve('src')//路徑別名 可添加 jsconfig.json 配合編輯器提供路徑提示功能
  }
},
...

分別添加webpack.prod.js webpack.dev.js文件

webpack.prod.js

const merge = require("webpack-merge");
const UglifyJSPlugin = require("uglifyjs-webpack-plugin");
const common = require("./webpack.common.js");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = merge(common, {
  mode: "production",
  plugins: [
    new UglifyJSPlugin(),
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: util.staticPath("style/[name].css"),
      chunkFilename: util.staticPath("style/[id].css")
    })
  ]
});

webpack.dev.js

const merge = require("webpack-merge");
const common = require("./webpack.common.js");
const webpack = require("webpack);

module.exports = merge(common, {
  mode: "development",
  devtool: "inline-source-map",
  devServer: {
    contentBase: "./dist"
  },
  pluging: [new webpack.HotModuleReplacementPlugin()]
});

4.2 修改scripts


"dev": "cross-env NODE_ENV=development webpack-dev-server --config ./build/webpack.dev.js"
"build": "cross-env NODE_ENV=production webpack --config ./build/webpack.prod.js"

現(xiàn)在執(zhí)行npm run dev將會(huì)得到一個(gè)簡(jiǎn)單的開發(fā)環(huán)境

五、功能的進(jìn)一步完善

到此為止我們完成了一個(gè)簡(jiǎn)單的配置聊品,在開發(fā)環(huán)境下實(shí)現(xiàn)熱重載飞蹂、加載樣式文件,生產(chǎn)環(huán)境下代碼壓縮翻屈、自動(dòng)拷貝index.html并注入script陈哑、打包自動(dòng)清理dist文件夾。下面繼續(xù)完善相關(guān)的功能伸眶。

配置devserver

配置如下惊窖,命令行只顯示警告或錯(cuò)誤信息,同時(shí)使用friendly-errors-webpack-plugin插件厘贼,自動(dòng)清除信息界酒,并自定義顯示信息內(nèi)容。

npm install -D friendly-errors-webpack-plugin

webpack.dev.js

const devServerConfig = {
  contentBase: util.resolve("dist"),
  clientLogLevel: "warning",
  port: 3000,
  hot: true,
  host: "localhost",
  open: false,
  quiet: true,
  overlay: {
    /**
     * Shows a full-screen overlay in the browser
     * when there are compiler errors or warnings.
     */
    warnings: false,
    errors: true
  },
  proxy: {
    // detail: https://www.webpackjs.com/configuration/dev-server/#devserver-proxy
    "/base": {
      target: "https://test.cn",
      secure: true,
      changeOrigin: true,
      pathRewrite: {
        "^/base": ""
      }
    }
  }
};

module.exports = merge(common, {
  mode: "development",
  plugins: [
    new webpack.DefinePlugin({
      "env.PRODUCTION": "false"
    }),
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new FriendlyErrorsPlugin({
      compilationSuccessInfo: {
        messages: [
          `You application is running here http://${devServerConfig.host}:${devServerConfig.port}`
        ]
      },
      clearConsole: true
    })
  ],
  devServer: devServerConfig,
  devtool: "source-map"
});

配置buils.js文件

安裝依賴

npm install -D chalk ora

新建build/build.js嘴秸,修改scripts.build cross-env NODE_ENV=production node ./build/build.js毁欣,ora是一個(gè)在命令行顯示的加載動(dòng)畫庇谆,chalk能夠輸出帶有顏色的文字或消息。

const webpack = require("webpack");
const webpackConfig = require("./webpack.prod");
const ora = require("ora");
const chalk = require("chalk");

const spinner = ora("buildind...");
spinner.start();

webpack(webpackConfig, (err, stats) => {
  spinner.stop();
  if (err) throw err;
  process.stdout.write(
    stats.toString({
      colors: true,
      modules: false,
      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
      chunks: false,
      chunkModules: false
    }) + "\n\n"
  );

  if (stats.hasErrors()) {
    console.log(chalk.red("  Build failed with errors.\n"));
    process.exit(1);
  }

  console.log(chalk.cyan("  Build complete.\n"));
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凭疮,一起剝皮案震驚了整個(gè)濱河市饭耳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哭尝,老刑警劉巖哥攘,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異材鹦,居然都是意外死亡逝淹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門桶唐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栅葡,“玉大人,你說我怎么就攤上這事尤泽⌒来兀” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵坯约,是天一觀的道長(zhǎng)熊咽。 經(jīng)常有香客問我,道長(zhǎng)闹丐,這世上最難降的妖魔是什么横殴? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮卿拴,結(jié)果婚禮上衫仑,老公的妹妹穿的比我還像新娘。我一直安慰自己堕花,他們只是感情好文狱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缘挽,像睡著了一般瞄崇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上壕曼,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天杠袱,我揣著相機(jī)與錄音,去河邊找鬼窝稿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛凿掂,可吹牛的內(nèi)容都是我干的伴榔。 我是一名探鬼主播纹蝴,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼踪少!你這毒婦竟也來了塘安?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤援奢,失蹤者是張志新(化名)和其女友劉穎兼犯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體集漾,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡切黔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了具篇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纬霞。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖驱显,靈堂內(nèi)的尸體忽然破棺而出诗芜,到底是詐尸還是另有隱情,我是刑警寧澤埃疫,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布伏恐,位于F島的核電站,受9級(jí)特大地震影響栓霜,放射性物質(zhì)發(fā)生泄漏翠桦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一叙淌、第九天 我趴在偏房一處隱蔽的房頂上張望秤掌。 院中可真熱鬧,春花似錦鹰霍、人聲如沸闻鉴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孟岛。三九已至,卻和暖如春督勺,著一層夾襖步出監(jiān)牢的瞬間渠羞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工智哀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留次询,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓瓷叫,卻偏偏與公主長(zhǎng)得像屯吊,于是被迫代替她去往敵國(guó)和親送巡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容