银河网投[网址]www.308877.com-官网首页

您的位置:银河网投 > www.308877.com > 小白学react之由FOUC引发的一次webpack变革

小白学react之由FOUC引发的一次webpack变革

2019-10-31 20:26

react-webpack.png

天地会西宁分舵注:随着微信应用号的有板有眼,相信新意气风发轮的应用程式变革将在产生。作为行当内职员,我们很应该去拥抱这几个势头。此中Reactjs相信是开拓webapp的佼佼者,最近将会透过改建官方实例alt-tutorial来学学Reactjs相关的文化。

上一篇《小白学react之页面BaseLayout框架及微信的坑》我们上学了怎么为顺序Components提供贰个基础的父框架组件来管理区别页面包车型地铁Title的来得和Style样式的来得。

明印度人会尝试就和好踩到的二个坑先导,通过对webpack做进一步的纠正,来学习更加高档点的webpack相关的知识点。

十分重要供给歼灭的标题如下:

  • FOUC问题
  • 生育和开辟配置抽离
  • 自动生成index.html页面模版文件
  • 哈希文件名
  • 清理废品营造文件

1. SCSS导入引发的主题素材 - FOUC之坑

几天前在打理代码的时候蒙受一个难题。便是首先加载页面包车型客车时候页面会并发长期内的闪亮。也正是说,当咱们第一遍加载页面或然刷新首屏的时候,会在超级短的年月内先出示一下之类页面:

home_li_flash_bef.png

能够见见地点的多个li成分照旧在并未有运用上css此前的。然后超快的整整页面又回形成应用上css之后的页面:

home_li_flash_aft.png

作为小白,令人很慢的有个别是,遭受这种难题都不明了应该谷歌(Google)怎样首要字!尝试过各种" reactjs first page refresh flash page reload sass import issue scss apply issue..."等一大堆而无果。最后无意开采原本是二个叫作FOUC (Fash Of Unstyled Content)的标题。

flash of unstyled content (FOUC, also flash of unstyled text or FOUT)[1][2] is an instance where a web page appears briefly with the browser's default styles prior to loading an external CSS stylesheet, due to the web browser engine rendering the page before all information is retrieved. The page corrects itself as soon as the style rules are loaded and applied; however, the shift may be distracting. Related problems include flash of invisible text (FOIT) and flash of faux text (FOFT).

简短来讲就是当样式表晚于结构性html 加载,当加载到此体制表时,页面将结束在此之前的渲染。此样式表被下载和解析后,将再度渲染页面,也就现身了不久的闪亮现象。

据称诱因有三种:

1,使用import方法导入样式表。
2,将样式表放在页面尾部
3,有多少个样式表,放在html结构的不等岗位。

而消除方法正是:

化解方式:使用LINK标签将样式表放在文书档案HEAD中

因为大家的scss的样式确实是通过import的议程给导入到我们的次第页面包车型大巴,所以自身言听计从我们的诱因是率先种。以Home.jsx的样式表引进为例(上海教室中的三个li的渲染正是在Home页面中的):

import React from 'react'
import { Link } from 'react-router'
import  './Home.scss'
import BaseLayout from "./BaseLayout.jsx";

var Home = React.createClass({

    render() {
    return (
        <BaseLayout title="Home" style={{"backgroundColor":"white"}}>
          <div >
              <nav >
                <li className="home__tab__li"><Link to="/locations" >名胜古迹</Link></li>
                <li className="home__tab__li"><Link to="/about" >关于techgogogo</Link></li>
                  <div style={{clear:"both"}}></div>
                {this.props.children}
              </nav>
          </div>
        </BaseLayout>
    )
  }
})

module.exports = Home;

那么依据给出去的化解方案,大家是理所应当在运作的时候将scss提抽出来改成贰个独门的css文件,然后在index.html的页面模版中将其引进。

投入提收取来的css文件叫做style.css,那么index.html的页面代码就应该改为:

<!doctype html>
<html >
  <head>
    <link rel="stylesheet" type="text/css" href="style.css" />
  </head>
  <body>
    <div id="ReactApp"></div>
  </body>
  <script src="bundle.js"></script>
</html>

那这里的标题就造成是怎么生成这几个css文件?依照大家事先的实战,整个源码在webpack打包之后实际就独有一个bundle.js文件而已。

2. webpack如何将scss打包成单身的css文件

为了将css打包成单身的八个文本,大家能够借助八个叫做extract-text-webpack-plugin的webpack插件,大家能够从其github网页中查看见中央的音讯以致使用实例。

第风华正茂,大家需求将该模块安装上:

npm install extract-text-webpack-plugin --save-dev

接下来我们须求在大家的webpack.config.js文件中程导弹入该模块:

let ExtractTextPlugin = require('extract-text-webpack-plugin');

跟着实例化一个对象:

var extractSCSS = new ExtractTextPlugin('[name].css');

只顾这里的[name]是webpack上边包车型大巴三个重视字,代表entry中的块(chunk)的键。比如我们的entry的定义如下:

    entry: {
        app: path.resolve(__dirname, 'src/App.jsx'),
    },

那正是说这些[name]就是此处的“app”。缺省的话会是“main”。

接下来我们要求在plugins中参预那些实例:

 plugins: [
        new OpenBrowserPlugin({ url: 'http://localhost:8080' }),
        extractSCSS,
    ]

最终,将scss文件的loader改成如下:

{
    test: /.scss$/,
    //loaders: ["style", "css?sourceMap", "sass?sourceMap"]
    loader: extractSCSS.extract('style', 'css!sass?sourceMap'),
}

到此,大家的webpack.config.js配置文件固然辅助中将scss文件抽出成一个单身的css文件的行事了。我们在试行webpack打包的时候,那几个专门的学问就能够活动完结:

npm run build

事成之后你会发未来build目录下活动会变卦叁个叫做app.css的文书。

唯独,大家运营早前还必要做多二个作业,正是前方提到的内需将css文件放到index.html那么些模版文件的header部分:

<!doctype html>
<html >
  <head>
    <link rel="stylesheet" type="text/css" href="app.css" />
  </head>
  <body>
    <div id="ReactApp"></div>
  </body>
  <script src="bundle.js"></script>
</html>

最后我们运维下边从容不迫实行李包裹装和运转express服务器:

npm run prod

开垦浏览器就能够访谈到大家听得多了就能说的清楚的页面了。那时你会意识无论是你怎么刷新网页,再也不会现身FOUC难题了。

当然,你也足以在开采格局下运作,bundle.js和app.css文件会自动在内部存款和储蓄器中变化,其职能是平等的:

npm run dev

3. 分开开拓和生育布局

3.1 混乱的陈设

不过这里难题也光顾了,我们在做项指标进度中,开拓方式和生产格局的打包进度一再是不平等的。

诸如,大家付出方式中大家供给制定webpack-dev-server的局部参数,而在生养形式下我们是没有供给的。

只是我们后面将一长串的参数放到了package.json的scripts下边:

  "scripts": {
    "build": "webpack",
    "dev": "webpack-dev-server  --inline --devtool eval --host 0.0.0.0 --progress --colors --hot --content-base ./build --history-api-fallback",
    "prod": "npm run build & node server.js"
  },

实际更标准点的做法应该是将其一大串参数放到webpack.config.js里面,比方我们位于config上边:

    devServer: {
        historyApiFallback: true,
        //hot: true,
        inline: true,
        progress: true,
        // display only errors to reduce the amount of output
        stats: 'errors-only',
        devtool: eval,
        colors: true,
        contentBase: "./build",

        // parse host and port from env so this is easy
        // to customize
        host: "0.0.0.0",// process.env.HOST,
        port: process.env.PORT
    },

那正是说那就回去了我们地点谈起的难题,那几个devServer只是在支付方式才需求的,在生产情势下是没有必要的。

内部生产情势小编这里指的是package.json的scrip下的build命令,而支出形式指的是dev命令:

  "scripts": {
    "build": "webpack",
    "dev": "webpack-dev-server 
    "prod": "npm run build & node server.js"
  },

那正是说大家怎么技巧科学的将付出配置和生育布局分离开来吧?

3.2. 组别打包情形之npm_lifecycle_event

在webpack.config.js中要将开垦配置和生产安插分离开来,首先大家就要获取到当前的图景究竟是开垦照旧生产。

生育和开拓,主即便体未来我们跑的授命是 "npm run build" 依旧"npm run dev", 也便是体今后package.json的scripts脚本的一声令下上。

那么大家在wepack.config.js中倘使能看清到顾客跑的到底是哪个命令的话,大家就会达到那或多或少。

此刻,特殊的处境变量npm_lifecycle_event将要登上舞台了。

npm 正在推行哪个 npm script, npm_lifecycle_event 境况变量值就能够设为其值,比如

  • 施行 npm run dev 命令时,则其值为 "dev" ;
  • 执行 npm run build 命令时,其值为 "build" ;

所以,我们在webpack.config.js中首先必要做的正是得到到那一个变量:

const TARGET = process.env.npm_lifecycle_event;

区分别当前供给打包的是支付碰着依然生育境况之后,大家下一步要做的就是将它们的安排代码分开。

3.3. 配备分离之webpack-merge

布局分离我们会用到的是webpack-merge这几个包,我们先把它安装上:

npm install webpack-merge --save-dev

webpack-merge是特意用来拍卖webpack.config.js的布局文件分其余。它最首要提供贰个merge方法,来将次第分开的配置项给合併在同盟,详细情况请查看github。

上边大家就足以参照其网址的示范,将开荒和生育的包裹配置给分离开来了,代码如下:

var path = require('path');
var OpenBrowserPlugin = require('open-browser-webpack-plugin');
const merge = require('webpack-merge');

const ExtractTextPlugin = require("extract-text-webpack-plugin");
var extractSCSS = new ExtractTextPlugin('[name].css');

const TARGET = process.env.npm_lifecycle_event;

var base = {
    entry: {
        app: path.resolve(__dirname, 'src/App.jsx'),
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname,"build"),
    },

    module: {

        loaders: [
            {
                test: /.(js|jsx)$/,
                loader: 'babel',
                query: {
                    presets: ['es2015', 'react','stage-2']
                }
            }
        ]
    }
};

if(TARGET === 'dev' || !TARGET) {

    module.exports = merge(base, {
        devServer: {
            historyApiFallback: true,
            //hot: true,
            inline: true,
            progress: true,
            // display only errors to reduce the amount of output
            stats: 'errors-only',
            devtool: eval,
            colors: true,
            contentBase: "./build",

            // parse host and port from env so this is easy
            // to customize
            host: "0.0.0.0",// process.env.HOST,
            port: process.env.PORT
        },
        module: {
            loaders: [
                {
                    test: /.scss$/,
                    loaders: ["style", "css?sourceMap", "sass?sourceMap"]
                }
            ]
        },

        plugins: [
            new OpenBrowserPlugin({url: 'http://localhost:8080'}),
        ]
    });
}

if(TARGET === 'build' || TARGET === 'prod') {

    module.exports = merge(base, {
        module: {
            loaders: [
                {
                    test: /.scss$/,
                    loader: extractSCSS.extract('style', 'css!sass?sourceMap'),
                }
            ]
        },
        plugins: [
            extractSCSS
        ]
    });
}

从代码能够看看,整个进程实际上正是将配备文件拆分,以便能拓宽更加灵敏的自由组合配置。这里有几点多少提一下的是:

  • 大家原本是唯有多少个称作config的配备项,今后因为要求做安顿分离,所以大家将该配置项改成base。意思是那是三个基本配备,由下边包车型客车支出和生产安插后续和扩充
  • 随行大家会咬定当前跑的是或不是是"npm run dev"命令只怕是此外未有特意在package.json中内定的吩咐,假使是的话,就能透过webpack-merge的merge方法,将开辟条件下打包所需求的特定配置项加入到地方的主导配备项地方,最终将配备给export出去。
  • 往下的生育情状安插抽离和支付条件的布局抽离相同,那就非常少说了。

配备分离消除后,大家下三个要缓和的主题材料就是index.html页面模版文件的变通。

4. 说了算index.html页面模版文件生成

干什么我们要求做那些事情啊?因为,在此以前大家的index.html文件是手动成立的,在此以前的css文件也未尝独立包装出来,那么大家后日有了单身的css文件之后,我们就供给手动的将以此css文件加到index.html文件之中了。

假若那些css文件的名字固定的话,那么我们只是修正三回也远非多大主题素材。不过,假使像往下就要讲到的,打包出来的这些css文件假诺老是都不均等的话,那么大家是不容许每一遍都去手动更新这几个html文件的了。

为了实现这么些目标,这里我们要求html-webpack-plugin的帮组。同理,大家先把那一个模块给安装上:

npm install html-webpack-plugin --save-dev

下一步便是任何时候github上的品类Readme去开展示公布局了。

先是,大家要求引进这么些模块:

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

接下来,因为大家往下的HtmlWebpackPlugin配置在生成index.html的时候需求一个模板,所以我们先将原本的index.html该名字为template.html,并改过内容如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  <body>
    <div id="ReactApp"></div>
  </body>
</html>

那边我们去掉了css和bundle脚本的引进,因为这个往下会自动生成并插入到那个模版中生成新的index.html文件。

往下一步大家就要求去在webpack.config.js文件中承袭陈设该怎么样根据模版生成新的index.html文件了。

那么些安插是要放松权利配置的plugins上的。咱们这里有base的配备,production的配备和development的布置,那么,大家那边只对生育情况调节新index.html文件的变迁,所以大家只要求在生养布局下进行plugins配置就好了:

if(TARGET === 'build' || TARGET === 'prod') {

    module.exports = merge(base, {
        module: {
            loaders: [
                {
                    test: /.scss$/,
                    loader: extractSCSS.extract('style', 'css!sass?sourceMap'),
                }
            ]
        },
        plugins: [
            extractSCSS,
            new HtmlWebpackPlugin({
                template: path.resolve(__dirname, "build/template.html"),
            })
        ]
    });
}

实则从该plugin的github网站上得以看出,该插件是永葆广大布署项的。因为大家那边的alt-tutorial演示项目比较轻易,所以这里只用了template那一个布局项,别的项暗许。

私下认可的话,该插件会:

  • 因而template那一个设置项找到大家的template.html文件,并在内部存款和储蓄器中拷贝风度翩翩份到index.html文件之中,然后针对内部存款和储蓄器中的该index.html文件实行往下的调控
  • 将webpack生成的css文件引进到index.html的head部分
  • 将webpack生成的js文件引进到index.html的body部分
  • 保留index.html到硬盘上

为此,在大家运营上面包车型客车吩咐之后:

npm run build

大家会开掘贰个新的index.html文件将会在build目录下转移:

<!DOCTYPE html>
<html><head><link href="app.css" rel="stylesheet"></head>
  <head>
    <meta charset="UTF-8">
  <body>
    <div id="ReactApp"></div>
  <script type="text/javascript" src="bundle.js"></script></body>
</html>

5. Hash文件名以幸免浏览器Cashe导致难题

有了地方的html文件自动生成的体制之后,大家现在就足以将扭转的js文件和css文件给hash起来了。

缘何我们须要给那个文件的文本名做哈希呢?哈希的结果自然正是每一遍改造的文件的名字都会分化等了。可是名字分歧等又是为哪出呢?

那主借使因为要拍卖浏览器cache导致的文本矫正未有立时起效的主题素材。

比如,大家脚下经过浏览器访谈我们的开荒服务器机器的时候,会去加载bundle.js文件。那么后一次笔者有新的换代,重新编写翻译之后,我再去通过浏览器去访谈就能开采更新未有行使上。因为,此时浏览器发掘bundle.js文件名还未变,它就能够利用原来cache起来的bundle.js继续提供服务。那,就是干吗我们供给hash文件名。

实质上hash文件名在webpack的配置中极其轻便,我们只须要用上webpack中的别的二个重要字[chunkhash]就好了。

第意气风发,大家修改base配置下的ouput项,将原先生成的bundle.js那个文件的公文名如下:

    output: {
        filename: '[name].[chunkhash].js',
        path: path.resolve(__dirname,"build"),
    },

build后改造的公文老将会是"app.xxxxx.js",此中xxxxx代表的正是hash。

况兼,我们修正生成的css文件的文件名如下:

var extractSCSS = new ExtractTextPlugin('[name].[chunkhash].css');

这时候再运营:

npm run build

我们就能见到build文件夹下边会生成加多了哈希值的js和css文件,同期,我们会小心到index.html文件也会随着而变:

<!DOCTYPE html>
<html><head><link href="app.4f8080c8499588890c06.css" rel="stylesheet"></head>
  <head>
    <meta charset="UTF-8">
  <body>
    <div id="ReactApp"></div>
  <script type="text/javascript" src="app.4f8080c8499588890c06.js"></script></body>
</html>

6. 清理垃圾营造文件

www.308877.com,将文件名展开hash的还要,会引入多个新的标题:每一回当大家校订了文本后打开重新营造,因为文件内容变了,所以hash出来的公文名也终将发生转移。那么在塑造多此番之后,大家的build目录下就会布满一大堆充满哈希值的文书名的垃圾文件。

当时大家很有必要在营造前将其清理掉,以保障build目录的干干净净干爽。

此地引进叁个新的webpack插件clean-webpack-plugin,使用格局也极其轻松。

先是,大家跟过去一模一样将该插件给装上:

npm install clean-webpack-plugin --save-dev

然后,大家在webpack.config.js中导入该模块:

const CleanPlugin = require('clean-webpack-plugin');

末尾对生育布局的plugins进行修正。因为开荒条件中那么些文件都是在内存发生的,所以大家不要求实行其余配置。

new CleanPlugin(['build'], {
  root: path.resolve(__dirname,"./"),
  verbose: true,
  exclude: ['template.html','logo.png']
})

其中:

  • build: 所急需清理的文书夹。正是相持上边包车型大巴root路线下的build文件夹
  • root: webpack.config.js文件所在的相对路线
  • exclue: 无需免去的文件列表

由来,大家做到了对全部webpack.config.js实行了相当大的改换,整个项指标营造也就更郑重其事了。

7. 源码

git clone https://github.com/kzlathander/alt-tutorial-webpack.git
cd alt-tutorial-webpackgit
checkout 07
npm install
npm run prod

同时

正文由世界会揭阳分舵编写,转发需授权,喜欢点个赞,调侃请争辩,进一步调换请关切小编领域会宿迁分舵以及《微信小程序支付》主题。

《未完待续》

本文由银河网投发布于www.308877.com,转载请注明出处:小白学react之由FOUC引发的一次webpack变革

关键词: