模块加载器会把装有的模块最后打包生成二个壮烈的,小白学react之页面BaseLayout框架及微信的坑

react-webpack.png

一步一步学WebPack2

不久前将webpack的施用计算一下,便于下一步的运用。本文通过若干的demo,让你一步一步学会使用webpack。webpack中一切都以模块,全部的全部(JS,CSS,图片,HTML)都能够被当作模块,通过require加载。模块加载器会把具有的模块最终打包生成三个光辉的“bundle.js”文件,并且会平昔不停实行加载!所以Webpack通过多量的表征去分割你的代码,生成几个“bundle”片段,并且异步地加载项目标两样部分。

npm install http-server -g

天地会邢台分舵注:随着微信应用号的维妙维肖,相信新一轮的APP变革即将爆发。作为行业内人员,大家很应该去拥抱那个方向。其中Reactjs相信是开发webapp的佼佼者,那段时光将会通过改建官方实例alt-tutorial来学习Reactjs相关的学问。

Demo1 – Start

  • 建立node项目:npm init ,名字为demo1,得到package.json文件

{
  "name": "demo1",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/fujusong/webpack-starter.git"
  },
  "keywords": [
    "webpack",
    "starter"
  ],
  "author": "sofu",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/fujusong/webpack-starter/issues"
  },
  "homepage": "https://github.com/fujusong/webpack-starter#readme",
  "devDependencies": {
    "webpack": "^2.6.1"
  }
}
  • 成立index.html ,并新建一个id为app的div。

#touch index.html
#vi index.html

<!DOCTYPE html> 
<head> 
<title></title> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></script> 
</head> 
<body> 
<div id="app"></div> 
</body> 
</html>
  • 创建index.js

#touch index.js

var app=document.getElementById('app'); 
app.innerHTML="Hello My WebPack App";
  • 设置webpack开发信赖

npm install webpack –-save-dev
  • 应用webpack将index.js文件打包为bundle.js文件

./node_modules/webpack/bin/webpack.js index.js bundle.js 
  • 修改index.html文件,加入bundle.js。

<!DOCTYPE html> 
<head> 
<title></title> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></script> 
</head> 
<body> 
<div id="app"></div> 
<script src="bundle.js"></script> 
</body> 
</html>
  • 运作http-server,打开浏览器查看页面

http-server -p 8000

然后在浏览器打开http://localhost:8000

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

Demo2 – Data Update

  • 开创src和dist五个公文夹,把index.js移动到src文件夹里,bundle.js是webpack打包生成出来的,使用先删除再生成的不二法门保障文件符合规律更新,未来会把dist作为转变文书存放的对象文件夹。
  • 安装rimraf 用于打包前去除旧的转变文书。

npm install rimraf –-save-dev
  • 修改package.json的script运维方式

{
  "name": "demo1",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build":"rimraf dist && webpack src/index.js dist/bundle.js"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/fujusong/webpack-starter.git"
  },
  "keywords": [
    "webpack",
    "starter"
  ],
  "author": "sofu",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/fujusong/webpack-starter/issues"
  },
  "homepage": "https://github.com/fujusong/webpack-starter#readme",
  "devDependencies": {
    "rimraf": "^2.6.1",
    "webpack": "^2.6.1"
  }
}
  • 运营 npm run build 打包一下,在dist目录下得到了bundle.js
  • 把index.html里面引用bundle.js的路线改成./dist/bundle.js,再运营http-server。

今天自身会尝试就融洽踩到的一个坑开首,通过对webpack做进一步的修改,来上学更高级点的webpack相关的知识点。

澳门永利备用网址,引入Module,文件监察和控制。

  • 接下去在src目录下新建messages.js文件

module.exports={ data:'Hello,World!', event:'APP Event'};
  • 在index.js文件引入messages.js,并实例到页面

var messages=require('./message');

var app=document.getElementById('app'); 
app.innerHTML = messages.data+"From "+ messages.event;
  • 把package.json修改一下,build的最后加上监视命令–watch

"build":"rimraf dist && webpack src/index.js dist/bundle.js --watch"
  • 运维npm run
    build重新打包,可以看来打包进度并不曾完毕跳出,依旧是待命状态。
  • 另起二个cli,运营http-server -p 七千,在浏览器输入localhost:九千
  • 修改messages.json音信内容,然后刷新浏览器,能够看来内容随即更新了。

重中之重须要解决的问题如下:

Demo3 – Webpack-dev-server 1

  • 安装webpack-dev-server

npm install webpack-dev-server –-save-dev
  • 创建webpack.config.js文件,并加上基本配备

var path = require('path'); // 导入路径包 

module.exports={ 
    entry:'./src/index.js',//入口文件 
    output:{ 
        path:path.join(__dirname,'dist'),// 指定打包之后的文件夹 
        publicPath:'/dist/',// 指定资源文件引用的目录 
        filename:'bundle.js'// 指定打包为一个文件 bundle.js 
    }
}
  • 包装所需的不二法门都已在webpack.config.js配置后,package.json的build则去掉路径,并丰富webpack-dev-server启动:"dev":"webpack-dev-server"

... 
"scripts": { 
"test": "echo \"Error: no test specified\" && exit 1", 
"build": "rimraf dist && webpack --watch", 
"dev": "webpack-dev-server" 
}, 
...
  • 运作npm run
    dev运行webpack-dev-server进行打包,在浏览器输入localhost:8080直接打开。
  • 修改messages.json的内容,保存,能够见见浏览器实时更新了数码
  • FOUC问题
  • 生育和开发配置分离
  • 自动生成index.html页面模版文件
  • 哈希文件名
  • 理清垃圾堆创设文件

Demo4 – Webpack-dev-server 2

对于webpack-dev-server,每一趟修改代码后,webpack能够自动重新打包,webpack-dev-server有三个用于机动刷新方式:iframe和inline,浏览器能够响应代码变化并活动刷新(hot)。

iframe

页面被嵌套在一个iframe下,代码发生变动后,iframe会重新加载
应用此形式无需附加安插,只需访问http://localhost:8080/webpack-dev-server/index.html即可,鲜明webpack-dev-server暗中认可的形式正是iframe。

inline

为任何页面提供了“Live
reloading”效用。webpack官方提供的1个小型Express服务器。

hot

提供了“模块热重载”功效,它会尝试仅仅更新组件被转移的片段(而不是百分之百页面)。会尝试先去通过
HM宝马7系 更新然后只怕尝试刷新整个页面。只供给加上2个
webpack/hot/dev-server entry point,并且在 dev-server 调用时抬高级参谋数
–hot。若是我们把inline和hot那五个选项都写上,那么当文件被改成时,webpack-dev-server会先尝试HM讴歌ZDX,假诺那无论用,它就会再也加载整个页面。

1. SCSS导入引发的难题 – FOUC之坑

后天在整治代码的时候蒙受三个题材。正是第华为载页面包车型地铁时候页面会现出长期内的闪亮。也等于说,当我们首次加载页面或然刷新首屏的时候,会在很短的小运内先出示一下之类页面:

home_li_flash_bef.png

能够见到下面的八个li成分照旧在未曾应用上css此前的。然后快捷的一切页面又回变成应用上css之后的页面:

home_li_flash_aft.png

用作小白,令人诚惶诚惧的少数是,碰着那种难题都不明了应该谷歌何以首要字!尝试过种种”
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的艺术给导入到大家的次第页面包车型客车,所以小编深信不疑大家的诱因是第3种。以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提取出来改成3个单独的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打包之后实际就只有3个bundle.js文件而已。

hot(HM中华V)和inline使用有二种格局:CLI和Node.js API

CLI方式相比不难,只需修改package.json中scripts配置,添加 –inline –hot

"dev": "webpack-dev-server –inline –hot"

node.js API方式

  • 在主目录下,新建dev-server.js文件

var WebpackDevServer=require('webpack-dev-server'); 
var webpack=require('webpack'); 
var config=require('./webpack.config'); 
var path=require('path'); 
var compiler=webpack(config); 
var server=new WebpackDevServer(
    compiler,
    {//创建服务器实例 
        hot:true,//HMR配置 
        filename:config.output.filename, 
        publicPath:config.output.publicPath,//必填 
    stats:{ 
        colors:true 
        } 
    }
); 
server.listen(8080,'localhost',function(){});
  • 修改webpack.config.js配置

var path=require('path');// 导入路径包 
var webpack=require('webpack'); 
module.exports={ 
    entry:[//入口文件 
        './src/index.js', 
        'webpack/hot/dev-server',//调用热重载 hot 
        'webpack-dev-server/client?http://localhost:8080'
        //添加webpack-dev-server客户端 
    ], 
    plugins:[ 
        new webpack.HotModuleReplacementPlugin()//全局开启热代码替换 
    ], 
    output:{ 
        path:path.join(__dirname,'dist'),// 指定打包之后的文件夹 
        publicPath:'/dist/',// 指定资源文件引用的目录 
        filename:'bundle.js'// 指定打包为一个文件 bundle.js 
    } 
}
  • 在index.js最上面添加hot调用

if(module.hot){//启用热重载 
    module.hot.accept();
}

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

为了将css打包成单身的1个文本,大家得以借助3个叫做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下面的1个关键字,代表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文件抽取成3个单独的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

– 修改package.json运营格局

... 
"scripts": { 
"build": "rimraf dist && webpack --watch", 
"dev": "node dev-server.js" 
}, 
...
  • 运作npm run dev
    ,在浏览器输入localhost:8080查阅,然后尝试修改index.jsmessages.json的数码,保存,浏览器自动刷新了

3. 分开开发和生产布局

Demo5 – Development and Production

在入口处区分生产环境和支付环境。

  • 修改package.json的script项,通过set NODE_ENV来安装环境变量

...
"scripts": { 
"build": "rimraf dist && set NODE_ENV=production&& webpack", 
"dev": "set NODE_ENV=development&& node dev-server.js" 
},
...
  • 修改webpack.config.js,在入口处添加NODE_ENV条件判断使用生产环境依然支付条件的进口文件及插件。process.env.NODE_ENV能够获得到运维文件的环境变量,nodejs的app.get('env')也能够赢得。

var path=require('path');
var webpack=require('webpack'); 
var DEVELOPMENT=process.env.NODE_ENV==='development'; 
var PRODUCTION=process.env.NODE_ENV==='production'; 
var entry=PRODUCTION ? ['./src/index.js'] : 
[ 
    './src/index.js', 
    'webpack/hot/dev-server',//开启热重载 hot 
    'webpack-dev-server/client?http://localhost:8080' 
    //添加webpack-dev-server客户端 
]; 
var plugins=PRODUCTION ? [] : 
    [ 
        new webpack.HotModuleReplacementPlugin()
        //全局开启代码热替换 如果是CLI这里则不用写 
    ]; 
module.exports={ 
    entry:entry,//入口文件 
    plugins:plugins, 
    output:{ 
        path:path.join(__dirname,'dist'),// 指定打包之后的文件夹 
        publicPath:'/dist/',// 指定资源文件引用的目录 
        filename:'bundle.js'// 指定打包为一个文件 bundle.js 
        } 
}

3.然后各自运营npm run dev 和npm run build。

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"
  },

那么我们什么才能科学的将支付配置和生产布局分离开来吗?

Demo6 – babel for es6/es7

  • 安装babel宗旨模块

npm install babel-core babel-loader babel-preset-es2015 babel-preset-stage-0 -save-dev

现实各模块的效能:

“babel-core” //转换器
“babel-loader” //转换器的加载器
“babel-preset-es二零一六” //ES2016转码规则
“babel-preset-stage-0”
//es7支撑,ES7分歧等级语法提案的转码规则(共有多少个等级),选装一个stage-0,stage-1,stage-2,stage-3

- 在项目文件添加.babelrc文件,加入转码规则

```json
{ "presets":["es2015","stage-0"]}
  • 修改webpack.config.js文件,添加module rules模块设置

...

module: { 
    rules:[ 
        { 
            test: /\.js$/, 
            use: ["babel-loader"], 
            exclude: path.resolve(__dirname, 'node_modules'),
        } 
    ] 
}

...
  • 在index.js中添加es6格式的格局

var messages=require('./message');
var newMessage = ()=>('<p>'+messages.data +' -From '+ messages.event+"</p>");
var app=document.getElementById('app'); 
app.innerHTML=newMessage(); 

if(module.hot){//启用热重载 
    module.hot.accept();
}
  • 运作npm run dev测试,可修改数据表明程序。

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;

区分别当前亟需打包的是支付条件依旧生产条件之后,我们下一步要做的正是将它们的安顿代码分开。

Demo7 – File Loader for Image

  • webpack.config.js的添加devtool:'source-map'
    ,用于在包装代码的同时生成2个sourcemap文件,并在卷入文件的末梢添加//#
    souceUWranglerL,注释会告诉JS引擎原始文件地点

  • 在src目录内新建img文件夹,复制二张图片进入供测试用。这里运用的一张名为s1.png的小图片,大小为9k。另一张名为s2.jpg,大小191k。

  • 在src目录内新建Icon.js文件

const icon=require('./img/s1.png'); 
const Image=`![](${icon})`; 
export default Image;
  • 在src目录内新建Img.js文件

const img=require('./img/s2.jpg'); 
const Image=`![](${img})`; 
export default Image;
  • 安装文件加载器

npm install file-loader –-save-dev
  • 修改webpack.config.js文件,添加file-loader加载器

... 
module: { 
    rules:[ 
        { 
            test: /\.js$/, 
            use: ["babel-loader"], 
            exclude: path.resolve(__dirname, 'node_modules'),
        },
        {
            test: /\.(jpe?g|png)$/,
            use: ['file-loader']
        },
    ] 
},
...
  • 修改index.js,通过import加载图片到页面

import icon from './Icon'; 
import img from './Img'; 


var messages=require('./message');
var newMessage = ()=>('<p>'+messages.data +' -From '+ messages.event+"</p>");
var newMessage2=()=>(
    `<p>${icon} ${img}</p>`
); 

var app=document.getElementById('app'); 
app.innerHTML=newMessage(); 
app.innerHTML+=newMessage2();

if(module.hot){//启用热重载 
    module.hot.accept();
}

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。意思是那是1个核心配置,由下边包车型地铁支付和生育布置后续和扩张
  • 跟随大家会判定当前跑的是还是不是是”npm run
    dev”命令或许是别的没有专门在package.json中钦赐的指令,假诺是的话,就会经过webpack-merge的merge方法,将付出环境下打包所供给的一定配置项进入到地方的骨干配置项地点,最终将计划给export出去。
  • 往下的生育环境安排分离和支出条件的布署分离类似,这就不多说了。

配备分离化解后,大家下3个要缓解的难题就是index.html页面模版文件的转移。

Demo8 – URL Loader for Images

动用U凯雷德L
Loader加载图片,limit参数能够采纳base64将小图片内联在代码中,收缩http请求。

  • 安装url-loader

npm install url-loader –-save-dev
  • 修改webpack.config.js,将图纸的loaders改为url-loader?limit=10000&name=images/[hash:12].[ext],小于10k的图样将会以base64的款式内联在代码中,并且图片打包到images文件内,以哈希值命名。

...
module: { 
    rules:[ 
        { 
            test: /\.js$/, 
            use: ["babel-loader"], 
            exclude: path.resolve(__dirname, 'node_modules'),
        },
        {
            test: /\.(jpe?g|png)$/,
            use: ['url-loader?limit=10000&name=images/[hash:12].[ext]']
        },
    ] 
},
...

3.输入npm run dev测试,能够看来s1.png已经被base64内联。s2.jpg文件名称也化为了hash名称。

4. 控制index.html页面模版文件生成

何以大家需求做这些业务呢?因为,从前我们的index.html文件是手动创设的,从前的css文件也并未独自包装出来,那么大家今日有了单独的css文件之后,大家就需求手动的将以此css文件加到index.html文件之中了。

要是那个css文件的名字固定的话,那么我们只是修改1次也从未多大难点。不过,要是像往下将要讲到的,打包出来的那个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>

Demo9 – Add Button

  • 在src文件目录新建button.js

const Button={ 
button:'<button id="myButton">Press me</button>', 
attachEl:()=>{ 
document.getElementById('myButton').addEventListener('click',()=>{ 
// debugger; 
console.log('clicked'); 
}) 
}}; 
export default Button;
  • 修改webpack.config.js,添加dev-tool:’sourse-map’,打包代码的还要生成一个sourcemap文件。

... 
module.exports={ 
    entry:entry,//入口文件
    devtool:'source-map',//打包代码的同时生成一个sourcemap文件,并在打包文件的末尾添加souceURL注释,注释会告诉JS引擎原始文件位置 
    module: { 
        rules:[ 
            { 
                test: /\.js$/, 
                use: ["babel-loader"], 
                exclude: path.resolve(__dirname, 'node_modules'),
            }
        ] 
    }, 
... 
  • 修改index.js文件,加载button模块并实例化。

import Button from './button'; 
var newMessage=()=>(Button.button); 
var app=document.getElementById('app'); 
app.innerHTML=newMessage(); 
Button.attachEl(); 

if(module.hot){
    module.hot.accept(); 
} 
  • 运转测试,点击页面中的按钮,能够看到控制台出口了测试文字

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>

Demo10 – compress source code

  • 修改webpack.config.js里的plugins变量,添加生产情势时加载插件。

var plugins = PRODUCTION ? [ 
    new webpack.optimize.UglifyJsPlugin(/*{//代码压缩 
        comments:true,//显示注释 
        mangle:false,//取消代码混淆 
        compress:{ 
            warnings:true//在UglifyJs删除没有用到的代码时不输出警告 
        } 
    }*/) 
    ] : [ 
            new webpack.HotModuleReplacementPlugin()//全局开启代码热替换 如果是CLI这里则不用写 
        ]; 
plugins.push( 
    new webpack.DefinePlugin({ 
        DEVELOPMENT:JSON.stringify(DEVELOPMENT), 
        PRODUCTION:JSON.stringify(PRODUCTION) 
    }) 
);
  • 修改index.js,将环境音讯输出到页面

var newMessage = ()=>{
    return `DEV:${DEVELOPMENT.toString()} <br> PRO:${PRODUCTION.toString()}`;
}


var app=document.getElementById('app'); 
app.innerHTML=newMessage(); 

if(DEVELOPMENT){ 
    if(module.hot){//启用热重载 
        module.hot.accept();
    }
}

3.分头运营npm run dev 和 npm run
build能够观望页面上显得的条件,再查看bundle.js,能够见到代码已经根据设置输出。

...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rimraf dist && NODE_ENV=production webpack && http-server -p 3000",
"dev": "NODE_ENV=development node dev-server.js"
},

...

4.重回webpack.config.js,把UglifyJsPlugin的参数都去掉,使用暗许参数

var plugins=PRODUCTION ? [ 
    new webpack.optimize.UglifyJsPlugin() 
    ] : [ 
    new webpack.HotModuleReplacementPlugin()//全局开启代码热替换 如果是CLI这里则不用 写 
    ];

5.重复运转npm run build打包,此时bundle.js已经被削减至最小化。

6. 清理垃圾堆塑造文件

将文件名实行hash的同时,会引入2个新的难点:每回当大家修改了文件后实行重复构建,因为文件内容变了,所以hash出来的文件名也一定产生改变。那么在创设多本次之后,我们的build目录下就会布满一大堆充满哈希值的文本名的垃圾文件。

此时大家很有必不可少在创设前将其清理掉,以保险build目录的清爽干爽。

那里引入多少个新的webpack插件clean-webpack-plugin,使用形式也卓殊简单。

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

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举行了相比大的转移,整个项指标创设也就更像模像样了。

Demo 11 – Load CSS

  • 安装css-loader和style-loader:npm install css-loader style-loader
    -save-dev。
  • css-loader 在js文件里,通过require的主意来引入css
  • style-loader 在html中以style的措施放置css

2.在src目录下,成立style文件夹,并创设一个css文件,那里命名为:globalStyle.css

body{ 
    background:#ddd; 
}

:local(.box){ 
    background-color:#ff0; 
    padding:1em; 
    border:1px solid #000; 
}

3.在webpack.config.js添加css的loader,webpack的loader的安顿是从右往左的,正是先使用css-loader之后利用style-loader

... 
module: { 
    rules:[ 
        { 
            test: /\.js$/, 
            use: ["babel-loader"], 
            exclude: path.resolve(__dirname, 'node_modules'),
        },
        {
            test: /\.css$/, 
            loaders: ["style-loader","css-loader"], 
            exclude: path.resolve(__dirname, 'node_modules'),
        }

    ] 
},
...
  • 修改index.js,引入css文件,并将相应的class添加进页面。

var style=require('./style/globalStyle.css'); 
const newMessage=()=>(
`<div class="${style.box}">    
    DEV:${DEVELOPMENT.toString()}<br>    
    PRO:${PRODUCTION.toString()}<br>    
</div>`

var app=document.getElementById(‘app’); 
app.innerHTML=newMessage(); 

if(DEVELOPMENT){ 
    if(module.hot){//启用热重载 
        module.hot.accept(); 
    } 
}
  • 测试页面,能够看到页面包车型客车体制已经更新,查看源码,原本div的classs为box的,已经被hash名称所替代。hash名称能够在webpack.config.js里css的加载器里自定义

...
test: /\.css$/, 
use: ["style-loader","css-loader?localIdentName=[path][name]--[local]"], 
...
  • 当供给将生产条件和耗费环境命名实行区分时,能够写在贰个变量或常量里

... 
const cssIdentifier=PRODUCTION? '[hash:base64:10]' : '[path][name]---[local]'; 
...
...
use: ["style-loader","css-loader?localIdentName=" + cssIdentifier], 
...
...

查阅页面源码时,能够看看webpack打包时,是把体制文件以style的艺术嵌在head里的

7. 源码

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

同时

正文由世界会遵义分舵编写,转发需授权,喜欢点个赞,吐槽请评论,进一步交换请关切自笔者领域会沧州分舵以及《微信小程序开发》主题。

《未完待续》

Demo12 – CSS Load Seprate

  • 安装插件用于将css样式打包成单身的公文。

npm install extract-text-webpack-plugin -save-dev
  • 要求是在支付条件样式依然嵌在页面上不变,只在包装到生育环境时,才单独打包到3个叫style.css的公文里,因而webpack.config.js里,先引入extract-text-webpack-plugin插件,然后在插件栏设置打包时的名号以及提取css加载时的不二法门

...
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var DEVELOPMENT=process.env.NODE_ENV==='development'; 
var PRODUCTION=process.env.NODE_ENV==='production'; 

var entry=PRODUCTION ? ['./src/index.js'] : [ 
    './src/index.js', 
    'webpack/hot/dev-server',//开启热重载 hot 
    'webpack-dev-server/client?http://localhost:8080'//添加webpack-dev-server客户端 
]; 
var plugins = PRODUCTION ? [ 
    new webpack.optimize.UglifyJsPlugin(),
    new ExtractTextPlugin('style.css'),
    ] : 
    [ 
        new webpack.HotModuleReplacementPlugin()//全局开启代码热替换 如果是CLI这里则不用写 
    ]; 
plugins.push( 
    new webpack.DefinePlugin({ 
        DEVELOPMENT:JSON.stringify(DEVELOPMENT), 
        PRODUCTION:JSON.stringify(PRODUCTION) 
    }) 
);

const cssIdentifier=PRODUCTION? '[hash:base64:10]' : '[path][name]--[local]'; 

const cssLoader=PRODUCTION ? ExtractTextPlugin.extract('css-loader?localIdentName=' + cssIdentifier) : 
    ['style-loader','css-loader?localIdentName=' + cssIdentifier];

module.exports={ 
    entry:entry,//入口文件
    module: { 
        rules:[ 
            { 
                test: /\.js$/, 
                use: ["babel-loader"], 
                exclude: path.resolve(__dirname, 'node_modules'),
            },
            {
                test: /\.css$/, 
                //use: ["style-loader","css-loader"], 
                use: cssLoader, 
                exclude: path.resolve(__dirname, 'node_modules'),
            }

        ] 
    }, 
...
  • index.html页面要独立加载打包生成的体裁文件style.css

<link rel="stylesheet" href="./dist/style.css">
  • 然后运营运转npm run build 查看,此时style.css是单独生成的。

  • style.css的称谓也足以用hash表示

new ExtractTextPlugin( 
'style-[contenthash:10].css'//根据内容生成hash值 
,{allChunks: true}//所有分离文件的样式也会全部压缩到一个文件上 
)

Demo13 – HTML Template

  • 设置模板插件

npm install html-webpack-plugin -save-dev

2.创建html模版:index-template.html

<!DOCTYPE html>
<head>    
<title></title>    
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>    
<div id="app"></div>
</body>
</html>
  • webpack.config.js顶部导入模板插件

var HTMLWebpackPlugin=require('html-webpack-plugin');
  • 在plugins处实例化,并将模版文件设置为index-template.html

var plugins=PRODUCTION ? [ 
    new webpack.optimize.UglifyJsPlugin(), 
    new ExtractTextPlugin( 
        'style-[contenthash:10].css'//根据内容生成hash值 
    ), 
    new HTMLWebpackPlugin({// webpack 指定目录(package内设置)生成静态HTML文件 
    template:'index-template.html' 
    }) 
] : [ 
new webpack.HotModuleReplacementPlugin()//全局开启代码热替换 如果是CLI这里则不用写
  • 静态文件在dist内生成名为index.html的文书,其余能源路径将和支出环境不相同,所以供给安装区分判断。

output:{ 
path:path.join(__dirname,'dist'),// 指定打包之后的文件夹 
publicPath: PRODUCTION ? '/' : '/dist/', 
filename: PRODUCTION ? 'bundle.[hash:12].min.js' : 'bundle.js'// 指定打包为一个文件 bundle.js 
}
  • 修改package.json,运维npm run build打包测试。

...
"scripts": {
    "build": "rimraf dist && NODE_ENV=production webpack && http-server ./dist -p 3000 ",
    "dev": "NODE_ENV=development node dev-server.js"
  },

...

demo14 – Tabs Pages

  • 在src文件内新建page1.js

const page=`<h1>页面1</h1>`;
export default page;
  • 在src文件内新建page2.js

const page=`<h1>页面2</h1>`;
export default page;
  • 修改index.js,创制多个按钮,并丰盛相应的点击事件,事件触发时使用System导入页面并将页面包车型大巴的剧情复制到content内。

var app=document.getElementById('app');
app.innerHTML=`    
    <div id="menu">        
        <button id="loadPage1">Load1</button>        
        <button id="loadPage2">Load2</button>    
    </div>    
    <div id="content">        
        <h1>home</h1>    
    </div>`;
document.getElementById('loadPage1').addEventListener('click',()=>{
//System.import 会令每个可能的模块都产生一个独立的块(chunk)。    
System.import('./page1').then(pageModule=>{        
    document.getElementById('content').innerHTML=pageModule.default;    
})
});
document.getElementById('loadPage2').addEventListener('click',()=>{    
System.import('./page2').then(pageModule=>{        
    document.getElementById('content').innerHTML=pageModule.default;    
})
});

if(DEVELOPMENT){    
    if(module.hot){//启用热重载       
        module.hot.accept();    
}}
  • 运转npm ren
    dev测试,在这以前,别忘记把index.html引用css和js的门路改回来
  • 开拓浏览器的network,来回点击按钮1和按钮2,阅览network加载的始末,能够发现,0.bandle.js和1.bandle.js是异步加载,并且不会被再一次加载。

Demo15 – Jquery

  • 安装jquery插件

npm install jquery –-save-dev
  • 在index.js中导入jquery,并创造多个jquery实例

import $ from 'jquery'; 
$('#app').css('background','#ff0');
  • 运作测试时,app背景已经发出变更。运转打包后,jquery也被打包进了bundle.js,那并不是大家想要的。而且,jquery并非全局,仅可在index.js使用,想要将jquery加载为全局模块,必要在webpack.config.js中设置externals

... 
module.exports={ 
    externals:{ 
        'jquery':'jQuery' 
    }, 
devtool:'source-map', 
entry:entry,//入口文件 
plugins:plugins, 
... 
  • 下一场jquery须求从表面加载进来,分别添加到index.htmlindex-template.html的head中,建议采用网上的jquery的CDN。如:

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
  • 个别运营开发环境和生产条件查看,jquery从外表加载,没有被打包进bundle.js。