<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「Webpack5 專題(三)」開發(fā)環(huán)境的設(shè)置

          共 8265字,需瀏覽 17分鐘

           ·

          2021-11-10 08:48


          一、前言

          上一篇講到如何處理靜態(tài)資源,本篇將更進(jìn)一步,介紹如何打造一個(gè)基礎(chǔ)而不失效率的開發(fā)環(huán)境。

          關(guān)鍵詞:HtmlWebpackPlugin、Source Map、Dev Server、Hot Module Replacement。

          二、Plugins - 快捷打包

          如果說,Loader 的作用是將不同的資源進(jìn)行轉(zhuǎn)換,那么 Plugin 則是在打包的過程中幫我們做一些事情,使打包過程更好管理。

          在之前的打包流程中,實(shí)際上存在兩個(gè)問題。

          第一,我們是不可以隨意刪除輸出文件夾(我設(shè)置的是 dist)下的 index.html 的,打包后的文件以此為 html 模板。

          第二,當(dāng)我們改變輸出文件名稱時(shí),打包后的新文件與之前沒有改名前的舊文件并存。

          為了快捷打包,我們需要解決這兩個(gè)問題。

          a) HtmlWebpackPlugin

          第一個(gè)問題的解決辦法就是讓 index.html 自動(dòng)生成。而 HtmlWebpackPlugin 這個(gè)插件就是干這個(gè)的,它會(huì)在打包完成后,在輸出目錄中自動(dòng)生成一個(gè) index.html 文件。

          在安裝插件前,需要在 src 下編寫一個(gè) index.html ,以此作為后續(xù)打包的模板。

          src/index.html


          <html?lang="en">
          ??<head>
          ????<meta?charset="UTF-8"?/>
          ????<meta?http-equiv="X-UA-Compatible"?content="IE=edge"?/>
          ????<meta?name="viewport"?content="width=device-width,?initial-scale=1.0"?/>
          ????<title>my?webpack?demotitle>

          ??head>

          ??<body>
          ????<div?id="root">div>
          ??body>
          html>
          復(fù)制代碼

          安裝插件:

          npm?install?--save-dev?html-webpack-plugin
          復(fù)制代碼

          webpack.config.js

          const?HtmlWebpackPlugin?=?require("html-webpack-plugin");
          module.exports?=?{
          ??//?...
          ??plugins:?[
          ????new?HtmlWebpackPlugin({
          ??????template:?"./src/index.html",?//?這里設(shè)置自己模板文件
          ????}),
          ??],
          };
          復(fù)制代碼

          b) CleanWebpackPlugin

          第二個(gè)問題的解決辦法是在打包之前清除輸出目錄中的內(nèi)容,然后讓它重新生成。CleanWebpackPlugin 插件雖然不是官方的,但是在 5.20.0 之前的版本中仍然值得推薦。

          它的 github 地址如下:github.com/johnagan/cl…[2]

          安裝插件:

          npm?install?--save-dev?clean-webpack-plugin
          復(fù)制代碼

          webpack.config.js

          const?{?CleanWebpackPlugin?}?=?require("clean-webpack-plugin");
          module.exports?=?{
          ??//?...
          ??plugins:?[
          ????new?CleanWebpackPlugin(),?//?在打包之前,清除輸入目錄下的文件
          ????new?HtmlWebpackPlugin({
          ??????template:?"./src/index.html",?//?這里設(shè)置自己模板文件
          ????}),
          ??],
          };
          復(fù)制代碼

          c) output.clean

          webpack.js.org/configurati…[3]

          還有一個(gè)更加方便的方法:在?webpack 5.20.0+?的版本中,內(nèi)置了清除輸出目錄內(nèi)容的功能,只要在 output 選項(xiàng)中配置一個(gè)參數(shù)即可。

          webpack.config.js

          module.exports?=?{
          ??//...
          ??output:?{
          ????clean:?true,?//?Clean?the?output?directory?before?emit.
          ??},
          };
          復(fù)制代碼

          三、Devtool

          現(xiàn)在嘗試寫一個(gè)錯(cuò)誤的語法,然后打包。

          consele.log(123)
          復(fù)制代碼

          雖然寫了錯(cuò)誤的語法,但是打包仍然會(huì)成功,接著在瀏覽器打開打包好的 index.html,控制臺(tái)中就會(huì)出現(xiàn)報(bào)錯(cuò)。

          image-20210810213451388.png

          當(dāng)你點(diǎn)擊右側(cè)的index.js:79時(shí),就會(huì)跳轉(zhuǎn)到出錯(cuò)的位置。

          但這個(gè)位置會(huì)和我們的正常邏輯不同,它會(huì)指引你到打包文件中的出錯(cuò)位置,而不是你的業(yè)務(wù)代碼出錯(cuò)的位置。

          顯然,我們作為開發(fā)者希望看到的是業(yè)務(wù)代碼中的位置。

          這時(shí),就需要用到 devtool 這個(gè)選項(xiàng)了。它可以在代碼出錯(cuò)時(shí),映射到業(yè)務(wù)代碼出錯(cuò)的位置上。

          在不同的環(huán)境中,配置是不同的。

          1. 開發(fā)環(huán)境中的 source map

          webpack.config.js

          module.exports?=?{
          ??mode:?'development',
          ??devtool:?'eval-cheap-module-source-map'?//?development
          }
          復(fù)制代碼

          2. 生產(chǎn)環(huán)境中的 source map

          module.exports?=?{
          ??mode:?'production',
          ??devtool:?'nosources-source-map',?//?production
          }
          復(fù)制代碼

          參考:webpack.js.org/configurati…[4]

          四、DevServer

          在通過 Loaders 處理完靜態(tài)資源以及 Plugins 快捷打包后,我們基本就能愉快地打包文件了。

          這時(shí),又遇到了新的問題,什么問題呢?那就是,我們只有在打包完之后,運(yùn)行代碼才能看到打包的結(jié)果。

          在開發(fā)過程中,我們希望的是自動(dòng)打包,讓我們邊寫代碼邊看到修改代碼后的效果,而不是每次都手動(dòng)打包。

          官方提供了三種方式:

          1. webpack's?Watch Mode[5]?(監(jiān)聽文件變動(dòng),變動(dòng)則重新打包,輸出目錄中可以看到新的打包文件。)
          2. webpack-dev-server[6]?(開啟本地開發(fā)服務(wù)器,默認(rèn)端口 8080,編譯后的文件存在內(nèi)存中,而非本地。)
          3. webpack-dev-middleware[7]?(將 webpack 作為 Node.js 的中間件)

          這些方式都是不錯(cuò)的開發(fā)工具,大部分情況下,用第二種就好。

          注意:這些工具僅對(duì)開發(fā)環(huán)境有益,在生產(chǎn)環(huán)境中請(qǐng)避免這樣的使用!?。?/strong>

          1. watch (監(jiān)聽模式)

          You can instruct webpack to "watch" all files within your dependency graph for changes. If one of these files is updated, the code will be recompiled so you don't have to run the full build manually.

          在 package.json 中設(shè)置腳本。

          package.json

          {
          ??"scripts":?{
          ????"watch":?"webpack?--watch",?//?監(jiān)聽打包
          ????"bundle":?"webpack"?//?普通打包
          ??},
          }
          復(fù)制代碼

          在終端中運(yùn)行npm run watch,你會(huì)發(fā)現(xiàn) webpack 是如何編譯你的代碼的,在打包完畢后它并不會(huì)消失,腳本會(huì)持續(xù)觀察你的文件變化。當(dāng)你對(duì)文件作出修改后,它會(huì)自動(dòng)重新編譯發(fā)生變化的模塊。(也就是說你改了文件內(nèi)容,它就幫你自動(dòng)打包。)

          2. webpack-dev-server (本地開發(fā)服務(wù)器)

          The?webpack-dev-server?provides you with a rudimentary web server and the ability to use live reloading.

          安裝:

          npm?install?--save-dev?webpack-dev-server
          復(fù)制代碼

          package.json

          {
          ??"scripts":?{
          ????"start":?"webpack?serve",?//?開啟本地服務(wù)器
          ????"watch":?"webpack?--watch",?//?監(jiān)聽打包
          ????"bundle":?"webpack"?//?普通打包
          ??},
          }
          復(fù)制代碼

          webpack.config.js

          const?path?=?require('path');
          const?HtmlWebpackPlugin?=?require('html-webpack-plugin');

          module.exports?=?{
          ??//?...
          ??mode:?'development',
          ??devtool:?'eval-cheap-module-source-map',
          ??devServer:?{
          ????contentBase:?path.join(__dirname,?'dist'),?//?指定被訪問html頁面所在目錄的路徑
          ????open:?true,?//?開啟服務(wù)器時(shí),自動(dòng)打開頁面
          ????compress:?true,?//?開啟?gzip?壓縮
          ????port:?9000,?//?自定義端口號(hào)
          ????publicPath:?'/'?//?服務(wù)器訪問靜態(tài)資源的默認(rèn)路徑,優(yōu)先級(jí)高于?output.publicPath
          ??},
          ??//?...
          }
          復(fù)制代碼

          注意:

          1. 在開發(fā)環(huán)境中,mode、devtool、devServer這三個(gè)配置是非常重要的!
          2. webpack-dev-server 在編譯后不會(huì)在輸出目錄寫入任何文件。相反,它會(huì)將打包的文件存在內(nèi)存中,就好像它們被安裝在服務(wù)器根路徑上的真實(shí)文件一樣。如果希望在其他路徑上找到打包的文件,可以通過使用 devServer 中的 publicPath 選項(xiàng)更改此設(shè)置。

          3. webpack-dev-middleware (中間件)— 此部分可略過

          webpack-dev-middleware?is a wrapper that will emit files processed by webpack to a server. This is used in?webpack-dev-server?internally, however it's available as a separate package to allow more custom setups if desired.

          安裝:

          npm?install?--save-dev?express?webpack-dev-middleware
          復(fù)制代碼

          package.json

          {
          ??"scripts":?{
          ????"server":?"node?server.js",?//?運(yùn)行?node?服務(wù)器
          ????"start":?"webpack?serve",?//?開啟本地服務(wù)器
          ????"watch":?"webpack?--watch",?//?監(jiān)聽打包
          ????"bundle":?"webpack"?//?普通打包
          ??},
          }
          復(fù)制代碼

          webpack.config.js

          module.exports?=?{
          ??//?...
          ??output:?{
          ????//?...
          ????publicPath:?'/'
          ??}
          }
          復(fù)制代碼

          在根目錄下添加一個(gè) server.js

          const?express?=?require('express');
          const?webpack?=?require('webpack');
          const?webpackMiddleware?=?require('webpack-dev-middleware');
          const?config?=?require('./webpack.config')
          const?compiler?=?webpack(config);?//?打包編譯器

          //?Tell?express?to?use?the?webpack-dev-middleware?and?use?the?webpack.config.js
          //?configuration?file?as?a?base.
          const?app?=?express();
          app.use(webpackMiddleware(compiler,?{
          ??publicPath:?config.output.publicPath,
          }));
          app.listen(3000,?()?=>?{
          ??console.log('Server?listening?on?port?3000');
          });
          復(fù)制代碼

          運(yùn)行 npm run server,即可看到效果,服務(wù)器在 3000 端口運(yùn)行:

          image-20210814102310053.png

          以上,我們實(shí)現(xiàn)了自動(dòng)打包。

          五、Hot Module Replacement(HMR) - 熱模塊替換(熱更新)

          運(yùn)行?npm run start,此時(shí),我們嘗試對(duì)文件進(jìn)行修改,然后回到頁面,你會(huì)發(fā)現(xiàn)終端內(nèi) webpack 幫我們重新編譯了代碼,然后它會(huì)自動(dòng)刷新,刷新后的頁面被重置,之前在頁面上的操作不見了,又要重新開始。

          我們想要的效果是,當(dāng)文件修改重新編譯后,頁面不要全部刷新,只是響應(yīng)發(fā)生變化的那一部分。這時(shí)候就要用到 HMR,熱模塊替換。

          注意:HMR 相當(dāng)于 dev Server 的輔助,同樣只用在開發(fā)環(huán)境,不要用在生產(chǎn)環(huán)境中?。?!

          1. HMR 之前

          現(xiàn)在看一下在設(shè)置 HMR 之前的情況

          index.js

          import?'./assets/styles/reset.css'
          import?'./assets/styles/global.scss'
          import?{?log?}?from?'./assets/js/log.js'

          const?root?=?document.getElementById('root');

          //?1.生成一個(gè)按鈕
          const?btn?=?document.createElement('button');
          btn.textContent?=?'Add?Item';
          btn.classList.add('btn');
          root.appendChild(btn);
          //?2.給按鈕添加事件,向?root?上追加?div?元素
          btn.addEventListener('click',?()?=>?{
          ??const?item?=?document.createElement('div');
          ??item.textContent?=?'Item?'?+?(root.children.length);
          ??item.classList.add('item');
          ??root.appendChild(item);
          });

          log('hello',?'world!');
          復(fù)制代碼

          ./assets/styles/global.scss

          //?自定義變量
          $color:?#ff4200;
          $fs:?14px;
          $ls:?1.2;

          //?自定義mixin
          @mixin?size?($w,?$h:?$w)?{
          ??width:?$w;
          ??height:?$h;
          }

          body?{
          ??font-size:?$fs;
          ??background-color:?#eaeaea;

          ??.btn?{
          ????@include?size(100px,?50px);
          ????background-color:?$color;
          ????border:?1px?solid?#000;
          ????color:?#fff;
          ????text-align:?center;
          ????padding:?10px;
          ????margin:?10px;
          ????&:hover?{
          ??????background-color:?#ff4200;
          ????}
          ??}
          ??.item?{
          ????@include?size(100px,?50px);
          ????background-color:?#ff4200;
          ????border:?1px?solid?#000;
          ????color:?#fff;
          ????text-align:?center;
          ????padding:?10px;
          ????margin:?10px;
          ????&:hover?{
          ??????background-color:?#ff4200;
          ????}
          ??}
          ??.item:nth-of-type(2n)?{
          ????background-color:?blueviolet
          ??}
          }
          復(fù)制代碼

          ./assets/js/log.js

          const?log?=?(...args)?=>?{
          ??console.log(...args);
          }

          export?{?log?};
          復(fù)制代碼

          效果:點(diǎn)擊 Add Item 按鈕時(shí),下方出現(xiàn) item。

          image-20210815152018031.png

          現(xiàn)在,改變樣式文件,讓偶數(shù)次創(chuàng)建的 item 換成黃綠色。

          global.scss

          //?...
          .item:nth-of-type(2n)?{
          ??//?background-color:?blueviolet;
          ??background-color:?yellowgreen;
          }
          復(fù)制代碼

          注意,當(dāng)我們改完,按下保存的那一刻,頁面刷新了,之前的 item 自然也都不見了,我們需要重新點(diǎn) btn 生成出 item,才能看到修改完的樣式效果。

          之后,讓我們改一下 log.js,

          const?log?=?(...args)?=>?{
          ??console.log(...args,?1);
          }

          export?{?log?};
          復(fù)制代碼

          同上,保存后頁面全局刷新。

          2. HMR 之后

          • 在 devServer 配置后,添加 hot 和 hotOnly,意思是開啟 HMR
          • 在 plugins 配置后,添加 HMR 插件。(它是 webpack 內(nèi)置的,記得要在最上面引入一下 webpack)

          webpack.config.js

          const?webpack?=?require('webpack');

          module.exports?=?{
          ??//?...
          ??devServer:?{
          ????contentBase:?path.join(__dirname,?'dist'),?//?指定被訪問html頁面所在目錄的路徑
          ????//?...
          ????hot:?true,?//?開啟熱更新
          ????hotOnly:?true,?//?強(qiáng)制熱更新,不會(huì)刷新頁面
          ??},
          ??plugins:?[
          ????//?...
          ????new?webpack.HotModuleReplacementPlugin()
          ??],
          }
          復(fù)制代碼

          在設(shè)置好后,重新執(zhí)行npm run start。

          重復(fù)上面的樣式修改,你會(huì)發(fā)現(xiàn),頁面并不會(huì)全部刷新,但修改的樣式已經(jīng)作用上去了。

          然而,對(duì) log.js 嘗試修改后,并沒有任何的變化。

          對(duì)于 js 文件來說,需要設(shè)置一些東西。

          在 index.js 中添加如下代碼:

          if?(module.hot)?{
          ??module.hot.accept('./assets/js/log.js',?(arr)?=>?{
          ????log('hello',?'world!');
          ??})
          }
          復(fù)制代碼

          意思是,如果 webpack 開啟了熱更新(也就是熱替代),那么,第一個(gè)參數(shù)是接受的發(fā)生更新的文件,第二個(gè)是當(dāng)文件更新后觸發(fā)的回調(diào)函數(shù)。

          如上,我們接收了 log.js 的變化,當(dāng)變化時(shí),就會(huì)執(zhí)行log('hello', 'world!')。

          此時(shí),重新執(zhí)行npm run start,就可以看到效果了。

          小結(jié)

          以上,是本篇的所有內(nèi)容。

          • 為了以模板為支撐更有效率地輸出打包文件,我們需要?HtmlWebpackPlugin;
          • 為了快速定位代碼錯(cuò)誤的位置,我們需要?source map;
          • 為了更好地模擬真實(shí)環(huán)境進(jìn)行開發(fā),我們需要?devServer(WDS);
          • 為了實(shí)時(shí)局部更新修改的內(nèi)容而非全局更新,我們需要?Hot Module Replacement(HMR)!

          關(guān)于本文

          本系列來自:EricKnight

          https://juejin.cn/user/2154698521972423/posts

          瀏覽 59
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩一区二区三区视频在线观看 | 美日韩中文在线 | 国产精品美女久久久久久 | 欧美一级网站 | aa一级黄色 |