从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)

从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)

  • 前言
  • 一 准备工作
    • 1 建立项目目录
    • 2 安装webpack
    • 3 准备项目文件结构
  • 二 配置webpack的工作
    • 1 基础配置
    • 2 配置webpack-dev-server
  • 三 使用React开发页面
  • 四 使用Webpack、Babel和React开发页面
    • 1 安装react
    • 2 生成主入口文件
    • 3 生成我们的html
    • 4 引入Bable解析ES6语法和jsx
    • 5 使用Ant Design作为React的UI库
    • 6 使用webpack加载样式表
    • 7 配置按需加载
  • 五 其他配置
    • 1 使用less语法加载器
    • 2 在react中引用图片资源
    • 3 将样式表单独打包发布成css文件
  • 六 发布产品&配置产品环境
    • 1 打包发布时压缩css文件
    • 2 打包发布时压缩js文件
    • 3 资源文件夹优化
    • 4 关于调试代码(source-map)
  • 七 结语

前言

学习即进步。本人一直使用vue框架,对于react框架一直是得闻不如一见。在一些简单的网站学习了react框架的基本教程之后,参照本人一直使用的webpack+bable+vue+iview开发环境。对应着想搭建一个基于react的开发环境,借此来对比,看看到底是哪个框架比较好用,效率高。进过分析,比对,我选择了与react最为般配的ant-design作为前端ul框架。即模式确定为webpack+bable+react+ant-design;如果需要偷懒,可以直接下载我的github项目,开包即用。

一 准备工作

先挂一下我的package.json,小白可以先忽略。项目结束之后可以提供参考。注意 我使用的是webpack4.x的版本。与3.x的部分内容可能不兼容。

 "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-plugin-import": "^1.11.0",
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "css-loader": "^2.1.0",
    "file-loader": "^3.0.1",
    "html-webpack-plugin": "^3.2.0",
    "less": "^2.7.3",
    "less-loader": "^4.0.5",
    "mini-css-extract-plugin": "^0.5.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "webpack": "^4.29.5",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "^3.1.0",
    "webpack-merge": "^4.1.0",
    "uglifyjs-webpack-plugin": "^2.1.1"
  },
  "dependencies": {
    "react": "^16.0.0",
    "react-dom": "^16.0.0",
    "antd": "^3.13.5"
  }

1 建立项目目录

  • 新建项目文件夹E:\study\webpack 下面简写为 根目录
  • 命令行进入目录,使用npm init指令进行npm的初始化。按照提示依次键入信息,不知道的直接回车。

2 安装webpack

  • 不建议全局安装webpack
  • 局部安装webpack 根目录>cnpm i webpack --save-dev
  • 没有cnpm的话安装一下淘宝镜像,npm install -g cnpm --registry=https://registry.npm.taobao.org
  • 这时自动安装完毕。package.json中devDependencies自动添加了对webpack的依赖。
"devDependencies": {
  "webpack": "^4.0.0",
}

说明1: webpack版本只要是4之后都可以。我这里只是演示
说明2: devDependencies是开发依赖,只会在打包过程中用到,不会包含到最后的代码中
说明3: 如果想安装指定版本的webpack,使用npm install --save-dev webpack@<版本号>格式

3 准备项目文件结构

我们的项目需要脚本,html,样式,图片以及一些其他资源。

│   package.json
├───node_modules
│       └╌╌ 下面是npm包
├───build
│   ├╌╌╌╌╌ build.js
│   ├╌╌╌╌╌ webpack.base.conf.js
│   ├╌╌╌╌╌ webpack.dev.conf.js
│   └╌╌╌╌╌ webpack.prod.conf.js
├───src
│   ├╌╌╌╌╌ main.js
│   └╌╌╌╌╌template
│         └╌╌╌╌╌template.html // 首页的模板
│   └╌╌╌╌╌images
│         └╌╌╌╌╌logo.jpg  

对,暂时我们就准备这些。

二 配置webpack的工作

webpack的工作就一个。根据一个入口文件,通过import,require等建立目标文件之间的关联关系,调用对应文件后缀的loader实现按需加载。有关完整的配置,可以参考我的下一篇文章。我们今天讲的,都是基本的配置。

1 基础配置

首先我们配置文件,打开webpack.base.conf.js,填写如下内容。

module.exports = {
    entry: './src/main', //main.js中的.js可以省略,前面的./不能省
}

有些朋友也许会问,build目录下有那么多js。为什么是webpack.base.conf.js。

首先,我们知道开发一个项目。有开发阶段和打包发布阶段,所以webpack的工作配置,也分为dev(开发)阶段配置和prod(发布产品)配置。开发模式与产品模式的webpack配置最主要的区别就是开发时需要一个热更新的服务器。以便于我们写的代码能够保存一次就能看到最新效果。而发布之后就是生成静态html文件,由产品服务器托管了。还有很多其他的区别,在之后我们会一一讲到。但是,大部分的基本配置都是一样的,所以我们分了3个文件,webpack.base.conf.js中是webpack通用的配置组成,例如入口文件,这绝对是通用的部分。然后我们再把区分的配置分别写到webpack.dev.conf.jswebpack.prod.conf.js中,再通过webpack-merge去合并配置。

package.json中配置webpack的调用方式,在script标签栏内填入

  "scripts": {
    "build": "webpack --config ./build/webpack.prod.conf.js",
    "dev": "webpack-dev-server --config ./build/webpack.dev.conf.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

理所当然的,我们现在分成了两个指令:build负责打包生成产品文件,dev负责搭建热更新服务器,实时调试我们的代码。

所以,我们在webpack.dev.conf.js中配webpack-dev-server服务器。

2 配置webpack-dev-server

在这里说明一下,为了保证大家安装的包版本跟我一致,安装依赖包的方式为直接在devDependencies中添加相关的版本,然后再调用cnpm install.

找到package.json添加依赖项

 "webpack-dev-server": "^3.1.0",
 "webpack-cli": "^3.2.3"

注意。webpack-dev-server依赖了"webpack-cli中的相关内容,所以也需要添加依赖。

根目录下执行cnpm install.

完成之后,在webpack.dev.conf.js中填入如下内容

const path = require('path');
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf')
module.exports = merge(baseWebpackConfig, {
    devtool: 'cheap-module-eval-source-map',
    output: {
        filename: './dist/[hash]app.js', // dist文件夹不存在时,会自动创建
        hashDigestLength: 8 // 默认长度是20
    },
    devServer: {
        contentBase: path.join(__dirname, "../dist"), //网站的根目录为 根目录/dist,如果配置不对,会报Cannot GET /错误
        port: 9000, //端口改为9000
        open: true// 自动打开浏览器,适合懒人
    },
})

webpack-merge也是webpack的库,需要单独安装
找到package.json添加依赖项

 "webpack-merge": "^4.1.0"

根目录下执行cnpm install.

  • webpack.dev.conf.js中通过引用webpack.base.conf.js,再通过merge对比,有的继承,没有的覆盖,这样就实现了公用基础配置的方法。
  • devtool : cheap-module-eval-source-map, devtool的配置比较复杂。这里你们先这样填,表示我可以在dev模式下F12 定位到原始文件debug我的代码。
  • output其实也是webpack基本配置。配置了项目打包生成的文件的存放处。由于我的dev模式和prod模式不一样,所以写在了dev的配置环境下。
  • devserver的配置参数我已经注释了。

好了。现阶段用于dev模式的webpack已经配置好了,接下来我们就可以开始编写我们的应用了。

三 使用React开发页面

使用React框架编写页面的方法有两种,第一种是直接在html文件中直接引用react.js和react-dom.js,然后在后续的脚本中使用React带来的能力。

一个普通的html文件便可以做到。


  
    
    
  
  
    

Hello world

但是这并不能很好的发挥react的作用。我们要使用ES6、JSX、UI重用等特性,因此我们将使用下面的第二种方法。

四 使用Webpack、Babel和React开发页面

1 安装react

react是我们项目运行时需要用到的包,所以我们需要在package.json中添加依赖项。react最终会被打包进我们的app.js中,供应用程序运行。安装单页面react运行环境目前需要2个包 reactreact-dom。我这里安装的是16.x的react(为了适配之后提到的antd):

//--package.json
"dependencies": {
    "react": "^16.0.0",
    "react-dom": "^16.0.0"
  },

然后在根目录cnpm install;

2 生成主入口文件

react安装好了。接下来我们就可以使用它了。在我们上面建立好的src/main.js中填入按照上面的js修改后的如下内容:

//--main.js
import React from 'react';
import ReactDOM from 'react-dom';
var e = React.createElement('p', null, 'This is React');
ReactDOM.render(e, document.getElementById('main'));

这里我们引用了npm包中安装的react和react-dom。仔细一看,

ReactDOM.render(e, document.getElementById('main'));

噢、看来我们至少需要一个html作为父容器,毕竟没有dom,脚本不可能正常运行。

到这里我们发现,react跟Vue一样,需要一个html页面作为最大的容器,所有的内容最后都会被webpack各种loader编译为浏览器可执行的文件,放到html中。

3 生成我们的html

这时候我们就需要webpack的一个插件html-webpack-plugin,来生成html。首先我们需要安装他。这是在项目编译打包阶段需要使用的库,所以我们把他放在devDependencies中。

//--package.json
"devDependencies": {
    "webpack": "^4.0.0",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "^3.1.0",
    "webpack-merge": "^4.1.0",
    "html-webpack-plugin": "^3.2.0",
  }

根目录执行cnpm install.

接下来我们要使用它。这个配置属于通用的基础配置,所以我们继续打开刚才的基础配置文件webpack.base.conf.js,添加如下语句

//--webpack.base.conf.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); //先引入
module.exports = {
    entry: './src/main', //main.js中的.js可以省略,前面的./不能省
    plugins: [
        new HtmlWebpackPlugin()
    ]
}

现在服务器也好了这样我们应该就可以跑着看了。我们在根目录执行npm run dev,没错,由于我们对于webpack-dev-server的配置open:true,在执行完毕之后我们就可以看到自动打开了浏览器,访问了我们配置的9000端口。

当然我们发现我们的浏览器一片空白

我们打开F12调试工具,先不管报的那个错误。我们去source栏查看,发现webpack确实已经帮我们根据入口main.js打包好了能运行的html。dist中是我们打包生成的app.js,并且已经根据我们配置在webpack.dev.conf.js中的输出,即加上8位哈希值相匹配。但是这些文件都是在内存中生成的,本地并不能找到。生成的html中在body标签的下方引用了生成的js。

从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第1张图片

可以点开那个app.js查看一下。发现内部有我们配置在dependencies中的react已经被打包进去了。
从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第2张图片
但是,我们在main.js中的代码引用了html中的元素。然而这个html是webpack自动生成的。所以我们需要修改html-webpack-plugin的配置,用我们自己的html作为模板。

  • 打开webpack.base.conf.js添加对于HtmlWebpackPlugin的配置。关于配置的详解我已经注释。
const HtmlWebpackPlugin = require('html-webpack-plugin'); //第二步导入
module.exports = {
    entry: './src/main', //main.js中的.js可以省略,前面的./不能省
    plugins: [
        new HtmlWebpackPlugin(
            {
                title: 'SEIE5.0', // html5文件中部分
                filename: 'index.html', // 默认是index.html,服务器中设置的首页是index.html,如果这里改成其它名字,那么devServer.index改为和它一样,最终完整文件路径是output.path+filename,如果filename中有子文件夹形式,如`./ab/cd/front.html`,只取`./front.html`
                template: './src/template/template.html', //如果觉得插件默认生成的hmtl5文件不合要求,可以指定一个模板,模板文件如果不存在,会报错,默认是在项目根目录下找模板文件,才模板为样板,将打包的js文件注入到body结尾处
                inject: "body", // true|body|head|false,四种值,默认为true,true和body相同,是将js注入到body结束标签前,head将打包的js文件放在head结束前,false是不注入,这时得要手工在html中加js
            }
        )
    ]
}
</code></pre> 
  <ul> 
   <li>打开<code>src/template/template.html</code>添加如下内容:</li> 
  </ul> 
  <pre><code><html>
  <body>
    <p>Hello world</p>
    <div id='main'/>
    
  </body>
</html>
</code></pre> 
  <p>ok 现在我们已经配置了让webpack按照我们给定的模板作为根容器了。现在我们重新运行<code>npm run dev</code></p> 
  <p><a href="http://img.e-com-net.com/image/info8/9c21eca5bc1f42ce85880e646b177094.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/9c21eca5bc1f42ce85880e646b177094.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第3张图片" width="650" height="195" style="border:1px solid black;"></a></p> 
  <p>没错,已经完成了。现在react能够正常运行了。</p> 
  <blockquote> 
   <p>注意。inject配置的注入一定要在body。如果填写了head的话,react会报一个错误。找不到dom元素。因为加载react的时候,dom还未初始化完毕。</p> 
  </blockquote> 
  <h2>4 引入Bable解析ES6语法和jsx</h2> 
  <p>到这里,你会发现不需要使用Babel,我们就可以使用React开发页面内容了。但是你会注意到,除了import语句是webpack做了兼容性处理的,我所使用的其他语法都是ES5的语法。<br> 如果在main.js中使用JSX语法,webpack构建的时候就会报错。同样地,如果在main.js中添加ES6的语法,尽管webpack构建时不会报错,但生成的app.js文件末尾部分依旧可以找到这部分ES6语法的代码,这样的代码被用户加载到浏览器中执行,是否能被浏览器支持是无法得到保证的。<br> 为此,我们需要引入Babel,让其把所有浏览器可能不支持的语法转换成ES5的语法。</p> 
  <p>使用Babel的方法也有好多种,官网的帮助文档可以根据环境提供对应的帮助。本文是基于Webpack使用Babel,因此无论是增加的依赖库还是配置流程均只对Webpack的场景有效。我们将使用Webpack关于Babel的一个扩展加载器babel-loader关联这两者。</p> 
  <ul> 
   <li>打开<code>package.json</code> 添加安装依赖</li> 
  </ul> 
  <pre><code>//--package.json
 "devDependencies": {
    ...
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2"
  },
</code></pre> 
  <p>上文提到,Babel用于把新版本的JS代码翻译成大多数浏览器都支持的ES5版本的代码。要做到这些翻译,只需要使用对应的扩展即可。例如:</p> 
  <ul> 
   <li>babel-preset-env根据配置环境计算babel对代码填充何种等级的polyfill,已包括es2015的配置,但没有包括stage-x。官方首推。</li> 
   <li>babel-preset-[stage-0、stage-1、stage-2、stage-3]与ES7相关的配置;</li> 
   <li>除此之外,Babel还可以有其他扩展,比如我们希望使用JSX语法,这时需要引入babel-preset-react处理器。</li> 
  </ul> 
  <p>根据官方的推荐,我们暂时先使用这几个:</p> 
  <pre><code> "devDependencies": {
    ...
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
  },
</code></pre> 
  <p>所以bable的依赖包我们先安装5个。然后执行<code>cnpm install</code></p> 
  <ul> 
   <li>bable的配置属于通用的基本配置,所以我们打开刚才的<code>webpack.base.conf.js</code>,添加rules配置</li> 
  </ul> 
  <pre><code>const HtmlWebpackPlugin = require('html-webpack-plugin'); //第二步导入
module.exports = {
    entry: './src/main', //main.js中的.js可以省略,前面的./不能省
    plugins: [
  	    ...
    ],
    module: {
         rules: [
	      {
	        test: /\.js$/,
	        exclude: /node_modules/,
	        use: {
	          loader: 'babel-loader',
	          options: {
	            presets: ['env', 'stage-0', 'react'],
	            plugins: []
	          }
	        }
	      }
    	]
    }
}
</code></pre> 
  <p>这样我们就使用了bable-loader作为js的解析器。依次使用react、stage-0、env插件进行解析。</p> 
  <ul> 
   <li>修改我们的main.js 这时我们可以使用一些jsx语法试试了:</li> 
  </ul> 
  <pre><code>import React from 'react';
import ReactDOM from 'react-dom';
class Text extends React.Component {
  render() {
    return (
      <p>This is a react Component</p>
    );
  }
}
ReactDOM.render(<Text/>, document.getElementById('main'));
</code></pre> 
  <p>在根目录执行<code>npm run dev</code>查看效果</p> 
  <p><a href="http://img.e-com-net.com/image/info8/4d8fb05a929b40ac8cd5e5ec4969e9dc.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/4d8fb05a929b40ac8cd5e5ec4969e9dc.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第4张图片" width="650" height="191" style="border:1px solid black;"></a><br> 没错。这下子我们完成了jsx语法的打包!Babel很好地工作了。</p> 
  <h2>5 使用Ant Design作为React的UI库</h2> 
  <p>就跟iview一样。我们要的各种漂亮的组件不可能由我们自己去一个个实现,这在项目的开发周期限制下是不允许的。于是乎基于React的各种组件UI库相应而生,而我选择<code>Ant Design</code>是因为其与iview风格、api及管网样式几乎一致。可以减少很多学习的时间。<br> 在<code>package.json</code>中添加ant-design依赖,由于是运行时依赖,所以需要加在<code>dependencies</code>中</p> 
  <pre><code>"dependencies": {
    "antd": "^3.13.5",
    "react": "^16.0.0",
    "react-dom": "^16.0.0"
  }
</code></pre> 
  <p>执行<code>cnpm install</code> 安装依赖。</p> 
  <p>好了,现在我们可以直接使用Ant Design的UI了。修改main.js,引入<code>ant-design</code>的<code>DatePicker</code>:</p> 
  <pre><code>import React from 'react';
import ReactDOM from 'react-dom';
import { DatePicker } from 'antd';
class Text extends React.Component {
  render() {
    return (
      <div>
        <p>This is a react Component</p>
        <DatePicker/>
      </div>
    );
  }
}
ReactDOM.render(<Text/>, document.getElementById('main'));
</code></pre> 
  <p>执行<code>npm run dev</code>,在浏览器中可以看到多了个日期选择器,但是没有相应的样式。</p> 
  <h2>6 使用webpack加载样式表</h2> 
  <p>想要在js中引入css样式表,需要添加webpack的加载器,这样在js中引入的css样式将会被webpack构建成以动态方式插入到html文件中。</p> 
  <p>针对css样式,需要下面两个加载器:</p> 
  <ul> 
   <li>style-loader</li> 
   <li>css-loader</li> 
  </ul> 
  <p>我们在<code>package.json</code>中安装如下依赖包</p> 
  <pre><code>  "devDependencies": {
     ...
    "css-loader": "^2.1.0",
    "style-loader": "^0.23.1"
  },
</code></pre> 
  <p>执行<code>cnpm install</code>安装依赖。</p> 
  <p>css-loader的配置属于通用的基本配置,所以我们打开刚才的<code>webpack.base.conf.js</code>,添加css解析器:</p> 
  <pre><code> module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['env', 'stage-0', 'react'],
                        plugins: []
                    }
                }
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
</code></pre> 
  <blockquote> 
   <p>注意:因为antd的样式是放在node_modules中的,不要在css的loader中添加exclude命令刨除掉node_modules目录。</p> 
  </blockquote> 
  <p>然后我们在main.js中引入antd的样式表:</p> 
  <pre><code>//--main.js
...
import { DatePicker } from 'antd';
import 'antd/dist/antd.css';  // Add
...
</code></pre> 
  <p>再次执行热更新服务器查看效果。发现时间选择器已经有样式了。</p> 
  <h2>7 配置按需加载</h2> 
  <p>不知道大家有没有发现现在页面的加载速度明显变慢了。这里是因为上述方法实际上加载整个antd包到最终生成的app.js文件中了。控制台也会看到相应的警告:<br> <img src="http://img.e-com-net.com/image/info8/d3b3bcbc3ad0495fb2498c192887e02b.jpg" alt="在这里插入图片描述" width="650" height="15"><br> 这里很明显,我们需要配置按需加载。配置按需加载需要使用另外一个Babel的插件<code>babel-plugin-import</code>,在<code>package.json</code>中添加引用:</p> 
  <pre><code>"devDependencies": {
	...
    "babel-plugin-import": "^1.11.0"
    ...
  }
</code></pre> 
  <p>执行<code>cnpm install</code>安装依赖。</p> 
  <p>然后修改<code>webpack.base.conf.js</code>中bable加载的方式,使用插件<code>babel-plugin-import</code>:</p> 
  <pre><code>module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['env', 'stage-0', 'react'],
                        plugins: [['import', { "libraryName": "antd", "style": "css" }]]//--通过bable-plugin-import依赖 实现antd按需加载
                    }
                }
            }
        ]
    }
}
</code></pre> 
  <p>大工告成。打包生成的app.js由13w行缩小到了5w行。注意,配置完按需加载之后,<code>main.js</code>中就不需要在手动引入anti的css样式了,所以我们可以去掉这一行。发现时间选择器能够正常加载样式。</p> 
  <blockquote> 
   <p>import ‘antd/dist/antd.css’;</p> 
  </blockquote> 
  <h1>五 其他配置</h1> 
  <h2>1 使用less语法加载器</h2> 
  <p>less是比较主流的样式语法。我在项目中经常使用,同样的,如果你也想在该项目中使用less语法,那么就需要使用less-loader。</p> 
  <ul> 
   <li>在项目src文件夹下新建一个styles文件夹,专门放置我们项目中用到的各种样式,文件夹下新建一个<code>main.less</code></li> 
  </ul> 
  <pre><code>#main
{
    .my-image{
        width: 400px;
        height: 500px;
    }
}
</code></pre> 
  <ul> 
   <li>在<code>main.js</code>中增加一个类名为<code>my-image</code>的div元素,并且import<code>main.less</code></li> 
  </ul> 
  <pre><code>import React from 'react';
import ReactDOM from 'react-dom';
import { DatePicker } from 'antd';
import './styles/main.less'
// import 'antd/dist/antd.css';  // Add
class Text extends React.Component {

    render() {
        return (
            <div>
            <p>This is a react Component123</p>
            <div className = "my-image" ></div>
            <DatePicker/>
            </div>
        );
    }
}
ReactDOM.render(<Text />, document.getElementById('main'));
</code></pre> 
  <blockquote> 
   <p>注意: react语法中class被替换为了className</p> 
  </blockquote> 
  <p>当然,less是无法被webpack识别的。所以对应的,我们需要为less添加对应的加载器。这里我们就需要<code>less-loader</code>了,当然,less-loader依赖less</p> 
  <ul> 
   <li>在<code>package.json</code>中添加依赖:</li> 
  </ul> 
  <pre><code>//--package.json
  "devDependencies": {
	...
   "less": "^2.7.3",
    "less-loader": "^4.0.5",
    ...
  }
</code></pre> 
  <p>执行<code>cnpm install</code>安装依赖。</p> 
  <ul> 
   <li>在<code>webpack.base.conf.js</code>中添加less后缀文件的加载器:</li> 
  </ul> 
  <pre><code>...
    {
         test: /\.css$/,
         use: ['style-loader', 'css-loader']
     },
     {
         test: /\.less$/,
         use: ['style-loader', 'css-loader', 'less-loader']
     }
 ...
</code></pre> 
  <p>这样配置是因为<code>less-loader</code>依赖<code>css-loader</code>,而<code>css-loader</code>依赖于<code>style-loader</code>;<br> 运行服务器,发现样式表被正常应用到了html文件中。打开<code>F12</code>调试工具,发现所有的样式被编译后转化为了样式表被放在了<code>head</code>标签上:<br> <a href="http://img.e-com-net.com/image/info8/d583db3528764ccdbbb556bcbce1a6eb.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/d583db3528764ccdbbb556bcbce1a6eb.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第5张图片" width="650" height="230" style="border:1px solid black;"></a></p> 
  <h2>2 在react中引用图片资源</h2> 
  <p>我们在项目中必不可少的就是引用图片资源。对于图片资源,我们也需要使用对应的loader,来确保webpack对其能够进行正常的处理。为此我们需要引入<code>url-loader</code>对于图片资源进行处理。</p> 
  <ul> 
   <li>安装url-loader</li> 
  </ul> 
  <pre><code>"devDependencies": {
    ...
    "url-loader": "^1.1.2"
  }
</code></pre> 
  <p>然后执行<code>cnmp install</code></p> 
  <ul> 
   <li>在<code>webpack.base.conf.js</code>中添加对应的解析器</li> 
  </ul> 
  <pre><code>...
 {
     test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
     loader: 'url-loader',
     options: {
         limit: 10000,
         name: 'img/[name].[hash:7].[ext]'
     }
 }
 ...
</code></pre> 
  <p>表示对如上后缀资源的都采用url-loader处理。</p> 
  <p><code>limit</code> 属性表示,当资源文件的大小没有超过该值时(单位:字节),编译过后统一转换为base64编码在项目中引用。超过之后,按照<code>name</code>属性配置的目录生成在<code>打包根目录</code>下,以命名规则进行命名。我们这里先设置为10000.</p> 
  <p>这时我们修改原先的main.less,将div设置一个一个背景图片</p> 
  <pre><code>#main
{
    .my-image{
        width: 400px;
        height: 500px;
        background: url("../images/logo.png")
    }
}
</code></pre> 
  <p>打开<code>dev</code>服务器,发现图片能正常显示。打开<code>F12</code>查看图片,发现图片被转为了base64编码:</p> 
  <p><a href="http://img.e-com-net.com/image/info8/f300db5359db4918b0fe525538e7c93e.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/f300db5359db4918b0fe525538e7c93e.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第6张图片" width="650" height="135" style="border:1px solid black;"></a><br> 然后我们再修改limit属性,将其设置为很小的数字 8.再次重启服务器,查看对比结果。</p> 
  <p>嗷。居然报错了~</p> 
  <p><a href="http://img.e-com-net.com/image/info8/d18b88c4fe59447fac68017e2eeea6a7.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/d18b88c4fe59447fac68017e2eeea6a7.jpg" alt="在这里插入图片描述" width="650" height="73"></a></p> 
  <p>原因很简单,因为图片大小超过了设定的大小,url-loader需要调用<code>file-loader</code>进行文件复制和拷贝等操作,所以需要安装<code>file-loader</code></p> 
  <pre><code>//--package.json
 "devDependencies": {
    "file-loader": "^3.0.1"
  }
</code></pre> 
  <p>执行<code>cnpm install</code> 安装后重新执行,重启服务器,得到正确的结果:</p> 
  <p><a href="http://img.e-com-net.com/image/info8/529401bd616940d3a3869cb8d98c8dac.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/529401bd616940d3a3869cb8d98c8dac.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第7张图片" width="650" height="135" style="border:1px solid black;"></a></p> 
  <p>这时,dist下自动生成了img目录,将原有的图片拷贝了过来,并进行了重命名:</p> 
  <p><a href="http://img.e-com-net.com/image/info8/906fdc97e2b64c978b3b931a502840e2.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/906fdc97e2b64c978b3b931a502840e2.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第8张图片" width="650" height="147" style="border:1px solid black;"></a></p> 
  <h2>3 将样式表单独打包发布成css文件</h2> 
  <p>通过上面的例子我们发现,所有的样式都被放到了编译后的html的头部中,如果想将所有的样式统一打包到一个文件中,岂不是很美观。要做到这样,我们需要使用另外一个插件<code>mini-css-extract-plugin</code>.其实在webpack3.x的时候,大家都是采用的<code>extract-text-webpack-plugin</code>进行css的单独处理。但是在4.x,该插件并不支持,并且在4.x官网推荐使用的就是<code>mini-css-extract-plugin</code>,所以我们今天就以该插件为例。</p> 
  <ul> 
   <li>在<code>package.json</code>中安装依赖:</li> 
  </ul> 
  <pre><code> "devDependencies": {
    ...
    "mini-css-extract-plugin":"^0.5.0"
  },
</code></pre> 
  <p>执行<code>cnpm install</code>安装依赖。</p> 
  <ul> 
   <li>打开<code>webpack.base.conf.js</code>,先修改less文件的加载方式,将原先依赖的<code>style-loader</code>替换为<code>MiniCssExtractPlugin.loader</code></li> 
  </ul> 
  <pre><code>//--webpack.base.conf.js

 const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //--注意需要引入
  ...
  module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.less$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
            }
           ...
        ],
    }
</code></pre> 
  <ul> 
   <li>在<code>webpack.base.conf.js</code>的<code>plugins</code>配置选项中声明使用该plugin并且添加其配置</li> 
  </ul> 
  <pre><code>//--webpack.base.conf.js
plugins: [
        new HtmlWebpackPlugin({
           ...
        }),
        new MiniCssExtractPlugin({
            filename: "[name].css",
            chunkFilename: "[id].css"
        })
 ]
</code></pre> 
  <ul> 
   <li>执行npm run dev。</li> 
  </ul> 
  <p><a href="http://img.e-com-net.com/image/info8/16c2d67ce6ea44a09e9935aaf22f7e35.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/16c2d67ce6ea44a09e9935aaf22f7e35.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第9张图片" width="650" height="139" style="border:1px solid black;"></a><br> 没错!我们现在将css单独独立到了一个文件中了(暂时不管路径,会在下一节提及),并且查看html,在<code>head</code>部分注入了对main.css的引用,原先在<code>style</code>标签中引用的样式消失了。现在大家应该明白<code>style-loader</code>的作用了吧。由于被替换为了<code>MiniCssExtractPlugin.loader</code>,样式注入的流程被替代了。所以不会在html文件的<code>style</code>标签中注入样式了。</p> 
  <p><a href="http://img.e-com-net.com/image/info8/60274bee6aaf4822b0642a35aed9913a.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/60274bee6aaf4822b0642a35aed9913a.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第10张图片" width="650" height="115" style="border:1px solid black;"></a><br> 依葫芦画瓢,我们把anti-design的样式也修改注入方式,全部放到main.css中。</p> 
  <pre><code>//--webpack.base.conf.js

 const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //--注意需要引入
  ...
  module: {
        rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            },
            {
                test: /\.less$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
            }
           ...
        ],
    }
</code></pre> 
  <p>重新运行<code>npm run dev</code>。</p> 
  <p>完美。现在html中已经没有一大坨样式了,仅有对<code>main.css</code>的引用打开<code>main.css</code>,发现原来的样式都被放到了这里。<br> <a href="http://img.e-com-net.com/image/info8/25499cdc9a42466d842ce4960d7d85d5.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/25499cdc9a42466d842ce4960d7d85d5.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第11张图片" width="650" height="170" style="border:1px solid black;"></a></p> 
  <h1>六 发布产品&配置产品环境</h1> 
  <p>截止到上面为止,我们讨论的都是使用<code>webpack-dev-server</code>构建服务器,然后在内存中加载对于webpack编译生成的文件,主要用于开发阶段使用的。虽然配置的写法都在<code>webpack.base.conf.js</code>中,但是我们使用的指令<code>npm run dev</code>使用的都是<code>webpack.dev.conf.js</code>中的配置。当我们发布产品的时候,我们就需要一些不同于<code>dev</code>的配置选项了。</p> 
  <ul> 
   <li>打开<code>webpack.prod.conf.js</code> ,按照<code>webpack.dev.conf.js</code>填写如下内容:</li> 
  </ul> 
  <pre><code>const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf')

module.exports = merge(baseWebpackConfig, {

})
</code></pre> 
  <ul> 
   <li>在根目录执行<code>npm run build</code>;</li> 
  </ul> 
  <p>发现我们的项目根目录下多了一个<code>dist</code>文件夹,打开一看,哇塞。居然就是我们刚才所有在<code>dev</code>模式下的生成的文件结构:<br> <a href="http://img.e-com-net.com/image/info8/2d074e9019a843c8b5e46e6e6fa8b914.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/2d074e9019a843c8b5e46e6e6fa8b914.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第12张图片" width="400" height="133" style="border:1px solid black;"></a></p> 
  <p>我们双击<code>index.html</code> 完美,浏览器中也能呈现和<code>dev</code>模式下的一模一样的效果。注意,这里的所有资源都是可以被浏览器直接识别的,没有less,没有es6,也没有jsx等等,只有html,css,js。这就是编译发布的意义,这样所有的浏览器都能兼容运行我们的项目了。只需要一个服务器,将内容放上去托管,大家就可以访问我们的网页了。</p> 
  <p>到这里,其实你已经可以开始开发项目了。但是,还是有一些问题存在的,我们上面<code>prod</code>的配置是完全使用<code>base</code>的配置项。毕竟编译发布的配置和dev的配置还是有区别的。在这里,我列举几点问题和解决,其余的定制配置,还是需要大家自己去实现。只需要记得,在<code>webpack.prod.conf.js</code>中配置编译发布环境,在<code>webpack.dev.conf.js</code>中配置开发环境。在<code>webpack.base.conf.js</code>中配置两者共用的环境即可。</p> 
  <h2>1 打包发布时压缩css文件</h2> 
  <p>webpack5可能会内置CSS 压缩器,webpack4需要自己使用压缩器,可以使用 <code>optimize-css-assets-webpack-plugin</code>插件。 设置 <code>optimization.minimizer</code> 覆盖webpack默认提供的即可。</p> 
  <ul> 
   <li>安装<code>optimize-css-assets-webpack-plugin</code></li> 
  </ul> 
  <pre><code>  "devDependencies": {
	...
    "optimize-css-assets-webpack-plugin": "^5.0.1",
	...
  },
</code></pre> 
  <p>执行<code>cnpm install</code></p> 
  <ul> 
   <li>这时我们需要配置<code>webpack.prod.conf.js</code>:</li> 
  </ul> 
  <pre><code>//--webpack.prod.conf.js
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = merge(baseWebpackConfig, {
    optimization: {
        minimizer: [
            new OptimizeCSSAssetsPlugin({})
        ]
    }
})
</code></pre> 
  <p>这里我们使用我们安装的插件,然后执行<code>npm run build</code>即可。没错,这时我们发现我们的<code>main.css</code>已经是压缩过的状态了~<br> <a href="http://img.e-com-net.com/image/info8/de8201ceee2046c8941c680af3d94410.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/de8201ceee2046c8941c680af3d94410.jpg" alt="在这里插入图片描述" width="650" height="56"></a></p> 
  <h2>2 打包发布时压缩js文件</h2> 
  <p>不知道大家有没有发现。在执行上一步之前,我们调用<code>npm run build</code>的时候,生成的<code>main.js</code>都是默认压缩的。那是因为webpack4.x的新特性、webpack4新的Mode,且默认值是production,所以都是默认调用其内置的<code>UglifyJsPlugin</code>进行压缩的。但是我们上一步复写了其默认配置。没有指定js压缩器,所以没有压缩js代码。这时候我们需要重新指定。</p> 
  <ul> 
   <li>下载安装<code>uglifyjs-webpack-plugin</code></li> 
  </ul> 
  <pre><code> "devDependencies": {
    "uglifyjs-webpack-plugin": "^2.1.1"
  },
</code></pre> 
  <p>执行<code>cnpm install</code>安装依赖</p> 
  <ul> 
   <li>打开<code>webpack.prod.conf.js</code> 修改<code>optimization</code>配置:</li> 
  </ul> 
  <pre><code>const UglifyJsPlugin = require('uglifyjs-webpack-plugin');  //--注意需要引入
...
optimization: {
        minimizer: [
            new OptimizeCSSAssetsPlugin({}),
            new UglifyJsPlugin({})
        ]
} 
...
</code></pre> 
  <p>这时 我们重新执行<code>npm run build</code>。ok js变成压缩过的版本了。这样可以打打减少我们项目打包出来文件的体积,提高网页加载的速度。<br> <a href="http://img.e-com-net.com/image/info8/f12776fb61354ca9bdbd293f8d0cd483.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/f12776fb61354ca9bdbd293f8d0cd483.jpg" alt="在这里插入图片描述" width="650" height="53"></a></p> 
  <h2>3 资源文件夹优化</h2> 
  <p>一般webpack打包出来的主流结构为一个static资源文件夹,然后是一个html文件。这样的结构合理,清晰。static文件夹内包含css,img,font等静态资源文件。这时候我们要修改我们项目的打包路径,使之符合这种审美。<br> <a href="http://img.e-com-net.com/image/info8/2b9e5f2d576f4f03bb37bfc81598d78c.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/2b9e5f2d576f4f03bb37bfc81598d78c.jpg" alt="在这里插入图片描述" width="320" height="70"></a></p> 
  <p>我们先来看看我们现在打包生成的目录结构:<br> <a href="http://img.e-com-net.com/image/info8/c960333e5978432c819ce737651babc0.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/c960333e5978432c819ce737651babc0.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第13张图片" width="321" height="147" style="border:1px solid black;"></a><br> 可以看到确实很丑。很乱,只有img文件夹是按照我们的想法的规则的。所以接下来我们要将其结构优化。</p> 
  <ul> 
   <li>首先我们要讲css的生成路径修改一下。改为由<code>css</code>文件夹包裹:<br> 理所当然的,我们想到了我们的<code>MiniCssExtractPlugin</code>,他是我们打包css最后一层调用的插件。于是我们修改他的配置:</li> 
  </ul> 
  <pre><code>//--webpack.base.conf.js
  ...
  new MiniCssExtractPlugin({
        filename: "css/[name].css",
        chunkFilename: "[id].css"
 })
</code></pre> 
  <p>因为官网说,<code>filename</code>的配置方式和<code>chunkFilename</code>的配置方式和<code>webpack</code>完全一致,所以我们尝试修改生成css的路径。<br> 保存之后,执行编译指令<code>npm run build</code>。<br> <a href="http://img.e-com-net.com/image/info8/c09d95e5364643a185f3f816ea3f9c03.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/c09d95e5364643a185f3f816ea3f9c03.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第14张图片" width="315" height="135" style="border:1px solid black;"></a><br> 没错,成功了,我们将<code>main.css</code>打包进了<code>css</code>文件夹下。</p> 
  <ul> 
   <li>由于生成目录是公用配置,<code>dev</code>和<code>prod</code>模式均要使用。所以修改<code>webpack.base.config.js</code>中配置<code>output</code> 优化js的生成目录,并且换个名叫app.js:</li> 
  </ul> 
  <pre><code>//--webpack.base.config.js
module.exports = merge(baseWebpackConfig, {
    output: {
        filename: 'js/app[hash].js', // dist文件夹不存在时,会自动创建
        hashDigestLength: 8 // 默认长度是20
    }
})
</code></pre> 
  <p>记得删除<code>webpack.dev.config.js</code>中<code>output</code>的配置,这样<code>dev</code>模式才能继承到。<br> 我们先运行<code>npm run build</code>编译。<br> <a href="http://img.e-com-net.com/image/info8/3a52428435c94200ba1c7c1324ce09d8.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/3a52428435c94200ba1c7c1324ce09d8.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第15张图片" width="345" height="176" style="border:1px solid black;"></a><br> 没错!现在js也被我们套了一层了。</p> 
  <ul> 
   <li>将所有的资源包裹进<code>static</code>文件夹</li> 
  </ul> 
  <p>这里我们需要了解一个<code>webpack</code>的2个属性<code>output.publicPath</code>和<code>output.path</code>。<code>output.path</code>该属性表示将所有资源打包进根目录下的对应路径内。而<code>output.publicPath</code>表示html在引用这些资源的时候,默认在前面添加的路径。</p> 
  <p><strong>第一步</strong></p> 
  <p>修改一下<code>output.publicPath</code>,由于这是基本配置,所以我们打开<code>webpack.base.config.js</code>,添加如下语句</p> 
  <pre><code>module.exports = {
     ...
    output: {
        filename: './js/app[hash].js', // dist文件夹不存在时,会自动创建
        hashDigestLength: 8,// 默认长度是20
        publicPath:"./static/"
    }
    ...
 }
</code></pre> 
  <p>执行一次<code>npm run build</code> 然后观察生成的html文件。<br> <a href="http://img.e-com-net.com/image/info8/d83d415f001743ef82e2a308a6935f97.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/d83d415f001743ef82e2a308a6935f97.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第16张图片" width="650" height="130" style="border:1px solid black;"></a><br> 大家应该猜到了?就是这个意思,引用资源的前缀都会添加这个。我们的目的达到了。接下来就是把资源放到<code>static</code>文件夹下。</p> 
  <p><strong>第二步</strong><br> 还是上述文件<code>webpack.base.config.js</code> 我们再添加<code>path</code>的配置</p> 
  <pre><code>var path = require('path');//--path是node包中的类。注意引用
module.exports = {
     ...
    output: {
        filename: './js/app[hash].js', // dist文件夹不存在时,会自动创建
        hashDigestLength: 8,// 默认长度是20
        publicPath:"./static/",
        path:path.resolve(__dirname, '../dist/static')
    }
    ...
 }
</code></pre> 
  <p>表示资源生成的路径为取相对路径的dist再拼上static。我们再编译一次。`npm run build</p> 
  <p><a href="http://img.e-com-net.com/image/info8/36ac95b5fc25462995576bb20660f3ef.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/36ac95b5fc25462995576bb20660f3ef.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第17张图片" width="362" height="144" style="border:1px solid black;"></a>`</p> 
  <p>ok。完美。现在只剩下最后一步,将<code>index.html</code>移到<code>static</code>外,与其同级。</p> 
  <p><strong>第三步</strong></p> 
  <p>还是上述文件<code>webpack.base.config.js</code> 我们修改<code>HtmlWebpackPlugin</code>的配置。将<code>filename</code>属性修改为当前目录上一层:</p> 
  <pre><code>...
plugins: [
        new HtmlWebpackPlugin(
            {
                title: 'SEIE5.0', // html5文件中<title>部分
                filename: '../index.html', 
                template: './src/template/template.html',
                inject: "body"
            }
        )
        ...
    ]
    ...
</code></pre> 
  <p><a href="http://img.e-com-net.com/image/info8/d4b0927f9bd648d08e8a47f31da7ffa2.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/d4b0927f9bd648d08e8a47f31da7ffa2.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第18张图片" width="346" height="146" style="border:1px solid black;"></a><br> 哈哈。大功告成。兴奋之余点击index.html查看效果,得意之余,突然发现引用的图片没了。没了。于是赶紧看控制台,果然。图片路径并不能正确找到。<br> <a href="http://img.e-com-net.com/image/info8/20132a49c73b451a877dd5fd11bdfa5d.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/20132a49c73b451a877dd5fd11bdfa5d.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第19张图片" width="650" height="137" style="border:1px solid black;"></a><br> 那一行小字是引用路径,截图的原因看不太清楚:</p> 
  <p><code>file:///E:/github/webpack_test/dist/static/css/static/img/logo.3a54fdd.png</code></p> 
  <p>明显路径不对。本能的,由于请求是在css文件中发出的,所以我们去看打包生成的css文件。虽然被压缩过了,最后一行还是能找到:<br> <a href="http://img.e-com-net.com/image/info8/14e4f249c9964865949841094711b259.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/14e4f249c9964865949841094711b259.jpg" alt="在这里插入图片描述" width="650" height="51"></a><br> 原来是css-loader的问题。由于是相对路径,所以这个url大家都知道,会再css文件夹下查找图片。这当然是找不到的,应该在上一层。所以肯定是<code>url-loader</code>的问题啦。于是我们打开<code>url-loader</code>的配置项,添加<code>publicPath</code>选项,让所有的图片引用都向上一层寻找,这跟webpack的<code>publicPath</code>表示的是同一个意义:</p> 
  <p>打开<code>webpack.base.config.js</code></p> 
  <pre><code>...
module: {
        rules: [
           ...
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 8,
                    name: 'img/[name].[hash:7].[ext]',
                    publicPath:"../"
                }
            },
        ],
    },
    ...
</code></pre> 
  <p>执行<code>npm run build</code>,再次打开浏览器查看最新的html。这次图片的路径就对了。</p> 
  <p><a href="http://img.e-com-net.com/image/info8/15bf079623d1435a8aac379b860de3af.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/15bf079623d1435a8aac379b860de3af.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第20张图片" width="650" height="129" style="border:1px solid black;"></a></p> 
  <p>最后我们来验证下dev是否正常 <code>npm run dev</code> 服务器开启成功,页面加载成功,内存中生成的文件结构也是我们预先设定的结构:</p> 
  <p><a href="http://img.e-com-net.com/image/info8/36c8b09000ac443da6327b7d450042f1.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/36c8b09000ac443da6327b7d450042f1.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第21张图片" width="650" height="112" style="border:1px solid black;"></a></p> 
  <h2>4 关于调试代码(source-map)</h2> 
  <p>执行<code>npm run dev</code>。假如我们现在需要调试代码怎么办?app.js已经被打包的密密麻麻的,根本没办法打断点。这个时候我们就需要配置<code>devtool</code>了。关于<code>devtool</code>的详细配置和各参数的区别,可以参考这篇文章。</p> 
  <pre><code>//-webpack.base.conf.js
module.exports = merge(baseWebpackConfig, {
   ...
    devtool: '#source-map',
   ...
})
</code></pre> 
  <p><code>#source-map</code>表示对应的js生成对应的map映射文件,方便调试。这里还有一个坑我已经帮你们趟了。当我们使用<code>UglifyJsPlugin</code>时,如果要使用<code>source-map</code>,必须要指定<code>sourceMap</code>为true;这是因为在webpack的官方文档中有下面一句话:</p> 
  <blockquote> 
   <p>When using the uglifyjs-webpack-plugin you must provide the sourceMap: true option to enable SourceMap support.</p> 
  </blockquote> 
  <p>也就是当使用了uglifyjs-webpack-plugin 插件时,sourceMap这个值的默认值是false,不开启map。如果要启用map,需要在插件中配置sourceMap值为true。</p> 
  <pre><code>//--webpack.prod.config.js
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = merge(baseWebpackConfig, {
    devtool: '#source-map',
    optimization: {
        minimizer: [
            new OptimizeCSSAssetsPlugin({}),
            new UglifyJsPlugin({sourceMap: true})
        ]
    } 
})
</code></pre> 
  <p>我们运行<code>npm run build</code>查看效果:</p> 
  <p><a href="http://img.e-com-net.com/image/info8/6206f1315f61410eba172cd30b8302b1.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/6206f1315f61410eba172cd30b8302b1.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第22张图片" width="290" height="176" style="border:1px solid black;"></a></p> 
  <p>在js中生成了对应的map文件。</p> 
  <p>我们再执行<code>npm run dev</code> 打开f12 这时候按下Ctrl + P,发现我们可以打开源码中的<code>main.js</code>,加上一个断点,刷新页面:</p> 
  <p><a href="http://img.e-com-net.com/image/info8/f2b71e5d1c58445693c198737441b813.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/f2b71e5d1c58445693c198737441b813.jpg" alt="从零开始使用webpack(4.x)+bable+react+ant-design配置单页面应用开发环境(附模板)_第23张图片" width="650" height="159" style="border:1px solid black;"></a><br> ok。现在可以进行调试了。</p> 
  <p>其实<code>dev</code>模式和<code>prod</code>模式应该采用不同的source-map以提高效率。这里我没有深入研究,希望懂的博友们可以留言给予帮助。</p> 
  <h1>七 结语</h1> 
  <p>终于写完了。这篇文章写的很长时间,也是项目一边搭建,一边写的。期间遇到了不少问题,查过很多解决方案。不过一句古话。磨刀不误砍柴工,作为一个通用的模板项目,多付出些心血也是值得的。况且在写这篇博客的同时,也温习并且回顾了webpack很多的知识点。虽然这篇博客涉及的只是一小部分基础的功能,但是应对一般的项目已经绰绰有余了。</p> 
  <p>还有,如果大家在搭建项目的过程中发现什么问题或者疑问,欢迎留言评论,同时也欢迎大牛们的批评指正~</p> 
  <p>github项目地址 https://github.com/worlddai/webpack_react.git</p> 
 </div> 
</div>
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1291655194135830528"></div>
                    <script type="text/javascript" src="/views/front/js/chanyan.js"></script>
                    <!-- 文章页-底部 动态广告位 -->
                    <div class="youdao-fixed-ad" id="detail_ad_bottom"></div>
                </div>
                <div class="col-md-3">
                    <div class="row" id="ad">
                        <!-- 文章页-右侧1 动态广告位 -->
                        <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_1"> </div>
                        </div>
                        <!-- 文章页-右侧2 动态广告位 -->
                        <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_2"></div>
                        </div>
                        <!-- 文章页-右侧3 动态广告位 -->
                        <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_3"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="container">
        <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(react,webpack)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1880473231786307584.htm"
                           title="TypeScript 学习笔记(七):TypeScript 与后端框架的结合应用" target="_blank">TypeScript 学习笔记(七):TypeScript 与后端框架的结合应用</a>
                        <span class="text-muted">Evaporator Core</span>
<a class="tag" taget="_blank" href="/search/typescript/1.htm">typescript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a>
                        <div>1.引言在前几篇学习笔记中,我们已经探讨了TypeScript的基础知识和在前端框架(如Angular和React)中的应用。本篇将重点介绍TypeScript在后端开发中的应用,特别是如何与Node.js和Express结合使用,以构建强类型、可维护的后端应用。2.TypeScript与Node.jsNode.js是一个基于ChromeV8引擎的JavaScript运行时,广泛用于构建后端应用。</div>
                    </li>
                    <li><a href="/article/1880358988575469568.htm"
                           title="掌握 React 高阶组件与高阶函数:构建可复用组件的新境界" target="_blank">掌握 React 高阶组件与高阶函数:构建可复用组件的新境界</a>
                        <span class="text-muted">风茫</span>
<a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a>
                        <div>一、引言在React开发中,代码复用性和逻辑分离是提高开发效率和维护性的重要手段。高阶组件(Higher-OrderComponent,HOC)和高阶函数(Higher-OrderFunction,HOF)是实现这一目标的两种强大工具。本文将详细介绍这两种技术的概念、应用场景及其实现方式,并通过具体示例帮助你更好地理解和应用它们。二、高阶函数(HOF)1.概念高阶函数是指以函数作为参数或返回值的函</div>
                    </li>
                    <li><a href="/article/1880285741624389632.htm"
                           title="ReactiveSwift 简单使用" target="_blank">ReactiveSwift 简单使用</a>
                        <span class="text-muted">Johnny Tong</span>
<a class="tag" taget="_blank" href="/search/iOS/1.htm">iOS</a><a class="tag" taget="_blank" href="/search/%E4%B9%8B%E6%97%85/1.htm">之旅</a><a class="tag" taget="_blank" href="/search/swift/1.htm">swift</a>
                        <div>记录ReactiveSwift简单使用导入ReactiveSwift库创建TestViewModel文件enumJKTypeType:Int{casecloudcasedevicecaseweater}//通过监听属性变化classTestViewModel:NSObject{lazyvarrecordType:Property={returnProperty(recordTypeProperty</div>
                    </li>
                    <li><a href="/article/1880278556446093312.htm"
                           title="停止在 React 组件回调中使用箭头函数!" target="_blank">停止在 React 组件回调中使用箭头函数!</a>
                        <span class="text-muted">@大迁世界</span>
<a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a>
                        <div>在构建React应用时,许多开发者都喜欢使用箭头函数,因为它们简洁易用。但你知道吗,在组件回调中直接使用箭头函数可能会导致一些性能问题?在本文中,我们将分析这种情况发生的原因,并探讨你应该考虑的最佳实践。什么是箭头函数?在深入讨论最佳实践之前,我们快速回顾一下箭头函数。箭头函数是ES6引入的特性,它为JavaScript中的函数书写提供了更简短的语法。相比使用更冗长的function关键字,你可以</div>
                    </li>
                    <li><a href="/article/1880275275095273472.htm"
                           title="react-quill报错Listener added for a ‘DOMNodeInserted‘ mutation event.Support for this event type has.." target="_blank">react-quill报错Listener added for a ‘DOMNodeInserted‘ mutation event.Support for this event type has..</a>
                        <span class="text-muted">lryh_</span>
<a class="tag" taget="_blank" href="/search/%E6%8F%92%E4%BB%B6/1.htm">插件</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>1、删除node_modules和package-lock.json2、重装依赖npmi3、找到node_modules中quill==》dist==》quill.js文件中修改代码//_this.domNode.addEventListener('DOMNodeInserted',function(){});newMutationObserver(()=>{}).observe(_this.do</div>
                    </li>
                    <li><a href="/article/1880274517469753344.htm"
                           title="React和Vue中暴露子组件的属性和方法给父组件用,并且控制子组件暴露的颗粒度的做法" target="_blank">React和Vue中暴露子组件的属性和方法给父组件用,并且控制子组件暴露的颗粒度的做法</a>
                        <span class="text-muted">向画</span>
<a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a>
                        <div>React在React中,forwardRef是一种高级技术,它允许你将ref从父组件传递到子组件,从而直接访问子组件的DOM节点或公开的方法。这对于需要操作子组件内部状态或DOM的场景非常有用。为了使子组件能够暴露其属性和方法给父组件,通常会结合useImperativeHandleHook使用forwardRef。如何使用forwardRef和useImperativeHandle创建一个带有</div>
                    </li>
                    <li><a href="/article/1880150627305189376.htm"
                           title="前端-跨端跨平台框架介绍" target="_blank">前端-跨端跨平台框架介绍</a>
                        <span class="text-muted">有哥来袭</span>
<a class="tag" taget="_blank" href="/search/%E8%B7%A8%E7%AB%AF%E8%B7%A8%E5%B9%B3%E5%8F%B0/1.htm">跨端跨平台</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>1.Taro官网:https://taro-docs.jd.com/docsTaro是一个开放式跨端跨框架解决方案,支持使用React/Vue/Nerv等框架来开发微信/京东/百度/支付宝/字节跳动/QQ/飞书小程序/H5/RN等应用。2.ReactNative中文文档:https://reactnative.cn/英文文档:https://reactnative.dev/docs/getting</div>
                    </li>
                    <li><a href="/article/1880134085528055808.htm"
                           title="你可能不知道的antd倒计时组件用法" target="_blank">你可能不知道的antd倒计时组件用法</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AFreactantd/1.htm">前端reactantd</a>
                        <div>前言ps:本文使用ant组件库和react技术栈,因此假定你导入了这些依赖包。如果让你实现一个显示当前日期的定时器组件,你会怎么做?如下图所示:初步实现探索碰到这样的需求,你是不是会使用定时器来实现,如下所示:importReact,{useEffect,useState}from'react';import{Statistic}from'antd';importdayjsfrom'dayjs';</div>
                    </li>
                    <li><a href="/article/1880108763076161536.htm"
                           title="Three.js实现动态水泡效果逐步解析GLSL着色器" target="_blank">Three.js实现动态水泡效果逐步解析GLSL着色器</a>
                        <span class="text-muted">贵州数擎科技有限公司</span>
<a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E7%9D%80%E8%89%B2%E5%99%A8/1.htm">着色器</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>大家好!我是[数擎AI],一位热爱探索新技术的前端开发者,在这里分享前端和Web3D、AI技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步!开发领域:前端开发|AI应用|Web3D|元宇宙技术栈:JavaScript、React、ThreeJs、WebGL、Go经验经验:6年+前端开发经验,专注于图形渲染和AI技术经验经验:演示地址开源项目:智简未来、晓智元宇宙、数字</div>
                    </li>
                    <li><a href="/article/1880076688830820352.htm"
                           title="基于 React 和 Vite 的前端项目自动化测试方案" target="_blank">基于 React 和 Vite 的前端项目自动化测试方案</a>
                        <span class="text-muted"></span>

                        <div>背景前端自动化测试在工程化的研发体系中不可或缺。前端领域的自动化测试常被忽略,原因在于人们认为编写测试用例成本高且意义不大,本质是觉得投资回报率低。但当收益大于支出时,引入前端自动化测试是必要的。例如在表单功能从简单到复杂的迭代过程中,手动测试成本会指数级增长且可能无法完成所有测试,此时引入自动化测试能提升效率、保证测试覆盖范围、减少误差和遗漏、实现用例重复使用等。成本初始成本,引入自动化测试框架</div>
                    </li>
                    <li><a href="/article/1880072762630926336.htm"
                           title="Next.js 15 重大更新解析" target="_blank">Next.js 15 重大更新解析</a>
                        <span class="text-muted"></span>

                        <div>作为React框架的佼佼者,Next.js的第15个版本带来了诸多激动人心的更新。这次更新重点优化了开发工作流程、性能表现,并加强了安全性。现在就来深入了解这些新特性。自动化升级工具Next.js15引入了全新的codemodCLI工具,大大简化了版本升级流程。只需要运行以下命令即可升级到最新版本:npx@next/codemod@canaryupgraderc该工具不仅能自动更新依赖,还会展示可</div>
                    </li>
                    <li><a href="/article/1880004512920432640.htm"
                           title="Vue 开发者的 React 实战指南:表单处理篇" target="_blank">Vue 开发者的 React 实战指南:表单处理篇</a>
                        <span class="text-muted"></span>

                        <div>作为Vue开发者,在迁移到React开发时,表单处理的差异是一个重要的适应点。本文将从Vue开发者熟悉的角度出发,详细介绍React中的表单处理方式和最佳实践。基础表单处理对比Vue的表单处理在Vue中,我们习惯使用v-model进行双向绑定:用户名:密码:记住我:登录exportdefault{data(){return{form:{username:'',password:'',remembe</div>
                    </li>
                    <li><a href="/article/1879947682043195392.htm"
                           title="Node.js、Vue 和 React 的关系和区别" target="_blank">Node.js、Vue 和 React 的关系和区别</a>
                        <span class="text-muted">佐木宥轩</span>
<a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a>
                        <div>Node.js、Vue和React是前端和后端开发中常用的技术,它们各自有不同的作用,但可以协同工作来构建现代化的Web应用。为了通俗易懂地理解它们的关系,我们可以用一个餐厅的比喻来说明。1.Node.js:厨房的后台Node.js是一个基于JavaScript的运行时环境,主要用于构建服务器端应用程序。它就像餐厅的厨房,负责处理数据和逻辑。作用:提供后端服务,比如处理数据库、用户认证、文件上传等</div>
                    </li>
                    <li><a href="/article/1879927634540949504.htm"
                           title="Vue 开发者的 React 实战指南:路由和导航篇" target="_blank">Vue 开发者的 React 实战指南:路由和导航篇</a>
                        <span class="text-muted"></span>

                        <div>作为Vue开发者,在迁移到React开发时,路由系统的差异是需要重点关注的部分。本文将从VueRouter的使用经验出发,详细介绍ReactRouter的使用方式和最佳实践。基础路由配置VueRouter配置在Vue中,我们通常这样配置路由://router/index.jsimport{createRouter,createWebHistory}from'vue-router';importHo</div>
                    </li>
                    <li><a href="/article/1879913253606322176.htm"
                           title="系统设计架构——互联网案例" target="_blank">系统设计架构——互联网案例</a>
                        <span class="text-muted">大猩猩爱分享</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a>
                        <div>Netflix的技术栈移动和网络:Netflix采用Swift和Kotlin来构建原生移动应用。对于其Web应用程序,它使用React。前端/服务器通信:Netflix使用GraphQL。后端服务:Netflix依赖ZUUL、Eureka、SpringBoot框架和其他技术。数据库:Netflix使用EV缓存、Cassandra、CockroachDB和其他数据库。消息传递/流媒体:Netflix</div>
                    </li>
                    <li><a href="/article/1879911486969671680.htm"
                           title="【学术会议论文投稿】前端框架巅峰对决:React、Vue与Angular的全面解析与实战指南" target="_blank">【学术会议论文投稿】前端框架巅峰对决:React、Vue与Angular的全面解析与实战指南</a>
                        <span class="text-muted">小周不想卷</span>
<a class="tag" taget="_blank" href="/search/%E8%89%BE%E6%80%9D%E7%A7%91%E8%93%9D%E5%AD%A6%E6%9C%AF%E4%BC%9A%E8%AE%AE%E6%8A%95%E7%A8%BF/1.htm">艾思科蓝学术会议投稿</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a>
                        <div>【JPCS独立出版】第三届能源与动力工程国际学术会议(EPE2024)_艾思科蓝_学术一站式服务平台更多学术会议请看:https://ais.cn/u/nuyAF3引言在快速发展的前端技术领域,选择合适的框架或库对于项目的成功至关重要。React、Vue和Angular作为当前最流行的三大前端框架/库,各自拥有独特的优势和适用场景。本文将通过深入的文字解析和代码讲解,帮助开发者理解这三者的差异,并</div>
                    </li>
                    <li><a href="/article/1879909912612499456.htm"
                           title="Vite VS Webpack,谁才是最强构建工具" target="_blank">Vite VS Webpack,谁才是最强构建工具</a>
                        <span class="text-muted"></span>

                        <div>ViteVSWebpack,谁才是最强构建工具前言大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。VitevsWebpack:哪个更适合您的项目?随着Web应用的不断发展,对更快、更高效的开发工具的需求也在日益增长。多年来,Webpack一直是复杂应用的首选打包工具,以其强大的功能和广泛的插</div>
                    </li>
                    <li><a href="/article/1879895379521105920.htm"
                           title="探讨 React 中的状态管理:选择合适的工具" target="_blank">探讨 React 中的状态管理:选择合适的工具</a>
                        <span class="text-muted"></span>

                        <div>随着React的流行,开发者在构建复杂应用时常常面临的一个重要问题是如何有效地管理组件的状态。状态管理不仅涉及到在应用内传递数据,还包括如何在不同的组件间同步状态、优化性能,以及保持代码的可维护性。在这一领域,有许多工具和方法可供选择,本文将深入探讨React状态管理的几个关键概念,并比较几种常见的状态管理工具。状态管理的基本概念在React中,状态是一个组件生命周期中可能随时间改变的数据。Rea</div>
                    </li>
                    <li><a href="/article/1879894243045076992.htm"
                           title="vue学习总结" target="_blank">vue学习总结</a>
                        <span class="text-muted"></span>

                        <div>一、transition和transition-group的区别:transition:针对的是一个元素,比如v-if,v-showtransition-group:针对是多个元素,比如使用v-for二、transition动画过渡的时候什么时候生效?1.v-if2.v-show3.动态组件4.组建根节点三、vue创建项目有两种方法:1.vueinitwebpack项目名称2.vuecreate项</div>
                    </li>
                    <li><a href="/article/1879883604239118336.htm"
                           title="小白:react antd 搭建框架关于 RangePicker DatePicker 时间组件使用记录 2" target="_blank">小白:react antd 搭建框架关于 RangePicker DatePicker 时间组件使用记录 2</a>
                        <span class="text-muted">LZQ <=小氣鬼=></span>
<a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/%2B/1.htm">+</a><a class="tag" taget="_blank" href="/search/antd/1.htm">antd</a>
                        <div>文章目录一、关于RangePicker组件返回的moment方法示例一、关于RangePicker组件返回的moment方法示例moment方法中日后开发有用的方法如下:form.getFieldsValue().date[0].weeksInWeekYear(),form.getFieldsValue().date[0].zoneName(),form.getFieldsValue().date</div>
                    </li>
                    <li><a href="/article/1879862407979921408.htm"
                           title="react Hooks 父组件调用子组件函数、获取子组件属性" target="_blank">react Hooks 父组件调用子组件函数、获取子组件属性</a>
                        <span class="text-muted">初遇你时动了情</span>
<a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>子组件import{forwardRef,useImperativeHandle}from'react'//定义子组件的ref类型exportinterfaceChildRef{childMethod:()=>voidchildValue:string}constChild=forwardRef((props,ref)=>{//暴露给父组件的方法和属性useImperativeHandle(ref</div>
                    </li>
                    <li><a href="/article/1879843750692319232.htm"
                           title="深度解析 React 中 setState 的原理:同步还是异步" target="_blank">深度解析 React 中 setState 的原理:同步还是异步</a>
                        <span class="text-muted"></span>

                        <div>在React框架的核心机制里,setState是实现动态交互与数据驱动视图更新的关键枢纽。深入理解setState的工作原理,尤其是其同步与异步的特性,对于编写高效、稳定且可预测的React应用至关重要。一、setState的基础认知在React组件中,状态(state)是驱动组件行为与渲染结果的核心数据。setState作为更新状态的唯一官方途径,负责触发组件的重新渲染,从而反映出状态的变化。以</div>
                    </li>
                    <li><a href="/article/1879839955467956224.htm"
                           title="从零开始学 MobX Store:简化 React 数据管理" target="_blank">从零开始学 MobX Store:简化 React 数据管理</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/javascriptreact/1.htm">javascriptreact</a>
                        <div>学习如何使用MobXStore在React应用中实现全局状态管理。本文通过简单的购物车功能示例,帮助你理解MobXStore的基本概念、使用方法以及如何高效共享和管理数据,解决多组件间的数据同步问题。适合所有想提升React开发效率的开发者。文章目录什么是MobXStore?先理解问题MobXStore提供哪些功能?MobX的两种写法1.装饰器写法(旧版本常见)2.makeObservable写法</div>
                    </li>
                    <li><a href="/article/1879839827071922176.htm"
                           title="掌握 React Router:构建你的 React 应用导航" target="_blank">掌握 React Router:构建你的 React 应用导航</a>
                        <span class="text-muted"></span>

                        <div>大家好,我是长林啊!一个Go、Rust爱好者,同时也是一名全栈开发者;致力于终生学习和技术分享。本文首发于微信公众号《全栈修炼之旅》,欢迎大家关注!在构建现代Web应用时,导航是连接用户界面的关键纽带。ReactRouter作为React生态中的核心路由库,为开发者提供了强大的工具来实现SPA(单页应用)的导航逻辑。它不仅简化了页面间的跳转,还支持动态路由匹配、懒加载和状态管理集成,让应用的导航更</div>
                    </li>
                    <li><a href="/article/1879836657792905216.htm"
                           title="回顾技术圈的2024尤雨溪喷React的“开年之战”" target="_blank">回顾技术圈的2024尤雨溪喷React的“开年之战”</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AFvue.jsreact/1.htm">前端vue.jsreact</a>
                        <div>在2024年初,前端开发社区的一场激烈讨论围绕着React新版文档展开。这场讨论的导火索来自于Vue.js的创始人尤雨溪,他在Twitter上发表了对React新版文档的批评,认为React将复杂性转嫁给用户,未能有效地减轻使用该框架的心智负担。尤雨溪的言论迅速在React和Vue社区间引发了广泛的讨论,许多开发者开始针对React文档的设计哲学展开辩论,这一事件引起了前端开发者对框架设计理念和用</div>
                    </li>
                    <li><a href="/article/1879833865678286848.htm"
                           title="Vue 开发者的 React 实战指南:部署与持续集成篇" target="_blank">Vue 开发者的 React 实战指南:部署与持续集成篇</a>
                        <span class="text-muted"></span>

                        <div>作为Vue开发者,在迁移到React开发时,除了开发过程中的差异,部署和持续集成的策略也需要相应调整。本文将详细介绍React项目的部署流程和持续集成最佳实践。构建流程对比Vue的构建流程在Vue项目中,我们通常使用:VueCLI或Vite构建工具npmrunbuild生成生产环境代码输出目录通常是dist#VueCLInpmrunbuild#输出到dist目录#Vitenpmrunbuild#输</div>
                    </li>
                    <li><a href="/article/1879833105091588096.htm"
                           title="Vue 开发者的 React 实战指南:测试篇" target="_blank">Vue 开发者的 React 实战指南:测试篇</a>
                        <span class="text-muted"></span>

                        <div>作为Vue开发者,在迁移到React开发时,测试策略和方法也需要相应调整。本文将从Vue开发者熟悉的角度出发,详细介绍React中的测试方法和最佳实践。测试工具对比Vue的测试工具在Vue生态中,我们通常使用:VueTestUtils:官方的组件测试工具Jest:单元测试框架Cypress:端到端测试工具//Vue组件测试示例import{mount}from'@vue/test-utils';i</div>
                    </li>
                    <li><a href="/article/1879832977995788288.htm"
                           title="Vue 开发者的 React 实战指南:性能优化篇" target="_blank">Vue 开发者的 React 实战指南:性能优化篇</a>
                        <span class="text-muted"></span>

                        <div>作为Vue开发者,在迁移到React开发时,性能优化的思路和方法会有所不同。本文将从Vue开发者熟悉的角度出发,详细介绍React中的性能优化策略。渲染优化对比Vue的响应式系统Vue通过响应式系统自动追踪依赖,只有在数据真正变化时才会触发重渲染{{title}}{{description}}点击次数:{{count}}+1exportdefault{data(){return{title:'标题</div>
                    </li>
                    <li><a href="/article/1879818029068513280.htm"
                           title="webpack多页面打包的一次尝试" target="_blank">webpack多页面打包的一次尝试</a>
                        <span class="text-muted"></span>

                        <div>初始化cd项目名webpackinit创建第二页面与其头文件touchpage2.htmltouchsrc/page2.js修改page2.jsconsole.log("success")修改webpack.config.js添加page2.html至plugins项,添加src/page2.js至entry项最终模板:constpath=require('path');constHtmlWebp</div>
                    </li>
                    <li><a href="/article/1879797269235036160.htm"
                           title="前端-从入门到入土" target="_blank">前端-从入门到入土</a>
                        <span class="text-muted"></span>

                        <div>前端学习路线基础部分(HTML+CSS+JS入门)快速了解,能够进行简单的页面布局,交互JS部分,可以写一些小demo来熟悉常见的API推荐教程:https://www.bilibili.com/video/BV1BT4y1W7Aw/?spm_id_from=333....框架部分这里推荐Vue框架,相对React会更容易上手,并且中文文档也相对友好推荐教程:https://www.bilibil</div>
                    </li>
                                <li><a href="/article/112.htm"
                                       title="HQL之投影查询" target="_blank">HQL之投影查询</a>
                                    <span class="text-muted">归来朝歌</span>
<a class="tag" taget="_blank" href="/search/HQL/1.htm">HQL</a><a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a><a class="tag" taget="_blank" href="/search/%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5/1.htm">查询语句</a><a class="tag" taget="_blank" href="/search/%E6%8A%95%E5%BD%B1%E6%9F%A5%E8%AF%A2/1.htm">投影查询</a>
                                    <div>        在HQL查询中,常常面临这样一个场景,对于多表查询,是要将一个表的对象查出来还是要只需要每个表中的几个字段,最后放在一起显示? 
针对上面的场景,如果需要将一个对象查出来: 
HQL语句写“from 对象”即可 
Session session = HibernateUtil.openSession();
		</div>
                                </li>
                                <li><a href="/article/239.htm"
                                       title="Spring整合redis" target="_blank">Spring整合redis</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/redis/1.htm">redis</a>
                                    <div>pom.xml 
 

<dependencies>
		<!-- Spring Data - Redis Library -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redi</div>
                                </li>
                                <li><a href="/article/366.htm"
                                       title="org.hibernate.NonUniqueResultException: query did not return a unique result: 2" target="_blank">org.hibernate.NonUniqueResultException: query did not return a unique result: 2</a>
                                    <span class="text-muted">0624chenhong</span>
<a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a>
                                    <div>参考:http://blog.csdn.net/qingfeilee/article/details/7052736 
org.hibernate.NonUniqueResultException: query did not return a unique result: 2 
        在项目中出现了org.hiber</div>
                                </li>
                                <li><a href="/article/493.htm"
                                       title="android动画效果" target="_blank">android动画效果</a>
                                    <span class="text-muted">不懂事的小屁孩</span>
<a class="tag" taget="_blank" href="/search/android%E5%8A%A8%E7%94%BB/1.htm">android动画</a>
                                    <div>前几天弄alertdialog和popupwindow的时候,用到了android的动画效果,今天专门研究了一下关于android的动画效果,列出来,方便以后使用。 
 
Android 平台提供了两类动画。 一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转、平移、放缩和渐变)。 
第二类就是 Frame动画,即顺序的播放事先做好的图像,与gif图片原理类似。 
 
</div>
                                </li>
                                <li><a href="/article/620.htm"
                                       title="js delete 删除机理以及它的内存泄露问题的解决方案" target="_blank">js delete 删除机理以及它的内存泄露问题的解决方案</a>
                                    <span class="text-muted">换个号韩国红果果</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a>
                                    <div>delete删除属性时只是解除了属性与对象的绑定,故当属性值为一个对象时,删除时会造成内存泄露  (其实还未删除) 
举例: 

var person={name:{firstname:'bob'}}
var p=person.name
delete person.name
p.firstname  -->'bob'
// 依然可以访问p.firstname,存在内存泄露</div>
                                </li>
                                <li><a href="/article/747.htm"
                                       title="Oracle将零干预分析加入网络即服务计划" target="_blank">Oracle将零干预分析加入网络即服务计划</a>
                                    <span class="text-muted">蓝儿唯美</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a>
                                    <div>由Oracle通信技术部门主导的演示项目并没有在本月较早前法国南斯举行的行业集团TM论坛大会中获得嘉奖。但是,Oracle通信官员解雇致力于打造一个支持零干预分配和编制功能的网络即服务(NaaS)平台,帮助企业以更灵活和更适合云的方式实现通信服务提供商(CSP)的连接产品。这个Oracle主导的项目属于TM Forum Live!活动上展示的Catalyst计划的19个项目之一。Catalyst计</div>
                                </li>
                                <li><a href="/article/874.htm"
                                       title="spring学习——springmvc(二)" target="_blank">spring学习——springmvc(二)</a>
                                    <span class="text-muted">a-john</span>
<a class="tag" taget="_blank" href="/search/springMVC/1.htm">springMVC</a>
                                    <div>Spring MVC提供了非常方便的文件上传功能。 
1,配置Spring支持文件上传: 
DispatcherServlet本身并不知道如何处理multipart的表单数据,需要一个multipart解析器把POST请求的multipart数据中抽取出来,这样DispatcherServlet就能将其传递给我们的控制器了。为了在Spring中注册multipart解析器,需要声明一个实现了Mul</div>
                                </li>
                                <li><a href="/article/1001.htm"
                                       title="POJ-2828-Buy Tickets" target="_blank">POJ-2828-Buy Tickets</a>
                                    <span class="text-muted">aijuans</span>
<a class="tag" taget="_blank" href="/search/ACM_POJ/1.htm">ACM_POJ</a>
                                    <div>POJ-2828-Buy Tickets 
http://poj.org/problem?id=2828 
线段树,逆序插入 
 
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>using namespace std;#define N 200010struct</div>
                                </li>
                                <li><a href="/article/1128.htm"
                                       title="Java Ant build.xml详解" target="_blank">Java Ant build.xml详解</a>
                                    <span class="text-muted">asia007</span>
<a class="tag" taget="_blank" href="/search/build.xml/1.htm">build.xml</a>
                                    <div>1,什么是antant是构建工具2,什么是构建概念到处可查到,形象来说,你要把代码从某个地方拿来,编译,再拷贝到某个地方去等等操作,当然不仅与此,但是主要用来干这个3,ant的好处跨平台   --因为ant是使用java实现的,所以它跨平台使用简单--与ant的兄弟make比起来语法清晰--同样是和make相比功能强大--ant能做的事情很多,可能你用了很久,你仍然不知道它能有</div>
                                </li>
                                <li><a href="/article/1255.htm"
                                       title="android按钮监听器的四种技术" target="_blank">android按钮监听器的四种技术</a>
                                    <span class="text-muted">百合不是茶</span>
<a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/xml%E9%85%8D%E7%BD%AE/1.htm">xml配置</a><a class="tag" taget="_blank" href="/search/%E7%9B%91%E5%90%AC%E5%99%A8/1.htm">监听器</a><a class="tag" taget="_blank" href="/search/%E5%AE%9E%E7%8E%B0%E6%8E%A5%E5%8F%A3/1.htm">实现接口</a>
                                    <div>android开发中经常会用到各种各样的监听器,android监听器的写法与java又有不同的地方;  
  
1,activity中使用内部类实现接口 ,创建内部类实例  使用add方法  与java类似 
  
创建监听器的实例 
myLis lis = new myLis(); 
  
使用add方法给按钮添加监听器 
 </div>
                                </li>
                                <li><a href="/article/1382.htm"
                                       title="软件架构师不等同于资深程序员" target="_blank">软件架构师不等同于资深程序员</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84%E5%B8%88/1.htm">架构师</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/1.htm">架构设计</a>
                                    <div>        本文的作者Armel Nene是ETAPIX Global公司的首席架构师,他居住在伦敦,他参与过的开源项目包括 Apache Lucene,,Apache Nutch, Liferay 和 Pentaho等。 
        如今很多的公司</div>
                                </li>
                                <li><a href="/article/1509.htm"
                                       title="TeamForge Wiki Syntax & CollabNet User Information Center" target="_blank">TeamForge Wiki Syntax & CollabNet User Information Center</a>
                                    <span class="text-muted">sunjing</span>
<a class="tag" taget="_blank" href="/search/TeamForge/1.htm">TeamForge</a><a class="tag" taget="_blank" href="/search/How+do/1.htm">How do</a><a class="tag" taget="_blank" href="/search/Attachement/1.htm">Attachement</a><a class="tag" taget="_blank" href="/search/Anchor/1.htm">Anchor</a><a class="tag" taget="_blank" href="/search/Wiki+Syntax/1.htm">Wiki Syntax</a>
                                    <div>the CollabNet user information center http://help.collab.net/ 
  
How do I create a new Wiki page? 
A CollabNet TeamForge project can have any number of Wiki pages. All Wiki pages are linked, and</div>
                                </li>
                                <li><a href="/article/1636.htm"
                                       title="【Redis四】Redis数据类型" target="_blank">【Redis四】Redis数据类型</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/redis/1.htm">redis</a>
                                    <div>概述 
Redis是一个高性能的数据结构服务器,称之为数据结构服务器的原因是,它提供了丰富的数据类型以满足不同的应用场景,本文对Redis的数据类型以及对这些类型可能的操作进行总结。 
Redis常用的数据类型包括string、set、list、hash以及sorted set.Redis本身是K/V系统,这里的数据类型指的是value的类型,而不是key的类型,key的类型只有一种即string</div>
                                </li>
                                <li><a href="/article/1763.htm"
                                       title="SSH2整合-附源码" target="_blank">SSH2整合-附源码</a>
                                    <span class="text-muted">白糖_</span>
<a class="tag" taget="_blank" href="/search/eclipse/1.htm">eclipse</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/tomcat/1.htm">tomcat</a><a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a><a class="tag" taget="_blank" href="/search/Google/1.htm">Google</a>
                                    <div>今天用eclipse终于整合出了struts2+hibernate+spring框架。 
我创建的是tomcat项目,需要有tomcat插件。导入项目以后,鼠标右键选择属性,然后再找到“tomcat”项,勾选一下“Is a tomcat project”即可。具体方法见源码里的jsp图片,sql也在源码里。 
  
  
补充1:项目中部分jar包不是最新版的,可能导</div>
                                </li>
                                <li><a href="/article/1890.htm"
                                       title="[转]开源项目代码的学习方法" target="_blank">[转]开源项目代码的学习方法</a>
                                    <span class="text-muted">braveCS</span>
<a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95/1.htm">学习方法</a>
                                    <div>转自: 
http://blog.sina.com.cn/s/blog_693458530100lk5m.html 
http://www.cnblogs.com/west-link/archive/2011/06/07/2074466.html 
  
1)阅读features。以此来搞清楚该项目有哪些特性2)思考。想想如果自己来做有这些features的项目该如何构架3)下载并安装d</div>
                                </li>
                                <li><a href="/article/2017.htm"
                                       title="编程之美-子数组的最大和(二维)" target="_blank">编程之美-子数组的最大和(二维)</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BE%8E/1.htm">编程之美</a>
                                    <div>package beautyOfCoding;

import java.util.Arrays;
import java.util.Random;

public class MaxSubArraySum2 {

	/**
	 * 编程之美 子数组之和的最大值(二维)
	 */
	private static final int ROW = 5;
	private stat</div>
                                </li>
                                <li><a href="/article/2144.htm"
                                       title="读书笔记-3" target="_blank">读书笔记-3</a>
                                    <span class="text-muted">chengxuyuancsdn</span>
<a class="tag" taget="_blank" href="/search/jquery%E7%AC%94%E8%AE%B0/1.htm">jquery笔记</a><a class="tag" taget="_blank" href="/search/resultMap%E9%85%8D%E7%BD%AE/1.htm">resultMap配置</a><a class="tag" taget="_blank" href="/search/ibatis%E4%B8%80%E5%AF%B9%E5%A4%9A%E9%85%8D%E7%BD%AE/1.htm">ibatis一对多配置</a>
                                    <div>1、resultMap配置 
2、ibatis一对多配置 
3、jquery笔记 
 
1、resultMap配置
当<select resultMap="topic_data">
<resultMap id="topic_data">必须一一对应。
(1)<resultMap class="tblTopic&q</div>
                                </li>
                                <li><a href="/article/2271.htm"
                                       title="[物理与天文]物理学新进展" target="_blank">[物理与天文]物理学新进展</a>
                                    <span class="text-muted">comsci</span>

                                    <div> 
 
      如果我们必须获得某种地球上没有的矿石,才能够进行某些能量输出装置的设计和建造,而要获得这种矿石,又必须首先进行深空探测,而要进行深空探测,又必须获得这种能量输出装置,这个矛盾的循环,会导致地球联盟在与宇宙文明建立关系的时候,陷入困境 
 
      怎么办呢? 
 
 </div>
                                </li>
                                <li><a href="/article/2398.htm"
                                       title="Oracle 11g新特性:Automatic Diagnostic Repository" target="_blank">Oracle 11g新特性:Automatic Diagnostic Repository</a>
                                    <span class="text-muted">daizj</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/ADR/1.htm">ADR</a>
                                    <div>Oracle Database 11g的FDI(Fault Diagnosability Infrastructure)是自动化诊断方面的又一增强。 
FDI的一个关键组件是自动诊断库(Automatic Diagnostic Repository-ADR)。 
 
在oracle 11g中,alert文件的信息是以xml的文件格式存在的,另外提供了普通文本格式的alert文件。 
这两份log文</div>
                                </li>
                                <li><a href="/article/2525.htm"
                                       title="简单排序:选择排序" target="_blank">简单排序:选择排序</a>
                                    <span class="text-muted">dieslrae</span>
<a class="tag" taget="_blank" href="/search/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F/1.htm">选择排序</a>
                                    <div>
    public void selectSort(int[] array){
        int select;
        
        for(int i=0;i<array.length;i++){
            select = i;
            
            for(int k=i+1;k<array.leng</div>
                                </li>
                                <li><a href="/article/2652.htm"
                                       title="C语言学习六指针的经典程序,互换两个数字" target="_blank">C语言学习六指针的经典程序,互换两个数字</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/c/1.htm">c</a>
                                    <div>示例程序,swap_1和swap_2都是错误的,推理从1开始推到2,2没完成,推到3就完成了 
# include <stdio.h>

void swap_1(int, int);
void swap_2(int *, int *);
void swap_3(int *, int *);

int main(void)
{
	int a = 3;
	int b = </div>
                                </li>
                                <li><a href="/article/2779.htm"
                                       title="php 5.4中php-fpm 的重启、终止操作命令" target="_blank">php 5.4中php-fpm 的重启、终止操作命令</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a>
                                    <div>php 5.4中php-fpm 的重启、终止操作命令: 
查看php运行目录命令:which php/usr/bin/php 
查看php-fpm进程数:ps aux | grep -c php-fpm 
查看运行内存/usr/bin/php  -i|grep mem 
重启php-fpm/etc/init.d/php-fpm restart 
在phpinfo()输出内容可以看到php</div>
                                </li>
                                <li><a href="/article/2906.htm"
                                       title="线程同步工具类" target="_blank">线程同步工具类</a>
                                    <span class="text-muted">shuizhaosi888</span>
<a class="tag" taget="_blank" href="/search/%E5%90%8C%E6%AD%A5%E5%B7%A5%E5%85%B7%E7%B1%BB/1.htm">同步工具类</a>
                                    <div>同步工具类包括信号量(Semaphore)、栅栏(barrier)、闭锁(CountDownLatch) 
  
闭锁(CountDownLatch) 
public class RunMain {
	public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
		fin</div>
                                </li>
                                <li><a href="/article/3033.htm"
                                       title="bleeding edge是什么意思" target="_blank">bleeding edge是什么意思</a>
                                    <span class="text-muted">haojinghua</span>
<a class="tag" taget="_blank" href="/search/DI/1.htm">DI</a>
                                    <div>不止一次,看到很多讲技术的文章里面出现过这个词语。今天终于弄懂了——通过朋友给的浏览软件,上了wiki。  
我再一次感到,没有辞典能像WiKi一样,给出这样体贴人心、一清二楚的解释了。为了表达我对WiKi的喜爱,只好在此一一中英对照,给大家上次课。 
  
In computer science, bleeding edge is a term that </div>
                                </li>
                                <li><a href="/article/3160.htm"
                                       title="c中实现utf8和gbk的互转" target="_blank">c中实现utf8和gbk的互转</a>
                                    <span class="text-muted">jimmee</span>
<a class="tag" taget="_blank" href="/search/c/1.htm">c</a><a class="tag" taget="_blank" href="/search/iconv/1.htm">iconv</a><a class="tag" taget="_blank" href="/search/utf8%26gbk%E7%BC%96%E7%A0%81/1.htm">utf8&gbk编码</a>
                                    <div>#include <iconv.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>

int code_c</div>
                                </li>
                                <li><a href="/article/3287.htm"
                                       title="大型分布式网站架构设计与实践" target="_blank">大型分布式网站架构设计与实践</a>
                                    <span class="text-muted">lilin530</span>
<a class="tag" taget="_blank" href="/search/%E5%BA%94%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">应用服务器</a><a class="tag" taget="_blank" href="/search/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/1.htm">搜索引擎</a>
                                    <div>1.大型网站软件系统的特点? 
a.高并发,大流量。 
b.高可用。 
c.海量数据。 
d.用户分布广泛,网络情况复杂。 
e.安全环境恶劣。 
f.需求快速变更,发布频繁。 
g.渐进式发展。 
 
2.大型网站架构演化发展历程? 
a.初始阶段的网站架构。 
应用程序,数据库,文件等所有的资源都在一台服务器上。 
b.应用服务器和数据服务器分离。 
c.使用缓存改善网站性能。 
d.使用应用</div>
                                </li>
                                <li><a href="/article/3414.htm"
                                       title="在代码中获取Android theme中的attr属性值" target="_blank">在代码中获取Android theme中的attr属性值</a>
                                    <span class="text-muted">OliveExcel</span>
<a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/theme/1.htm">theme</a>
                                    <div>Android的Theme是由各种attr组合而成, 每个attr对应了这个属性的一个引用, 这个引用又可以是各种东西. 
  
在某些情况下, 我们需要获取非自定义的主题下某个属性的内容 (比如拿到系统默认的配色colorAccent), 操作方式举例一则: 
int defaultColor = 0xFF000000;
int[] attrsArray = { andorid.r.</div>
                                </li>
                                <li><a href="/article/3541.htm"
                                       title="基于Zookeeper的分布式共享锁" target="_blank">基于Zookeeper的分布式共享锁</a>
                                    <span class="text-muted">roadrunners</span>
<a class="tag" taget="_blank" href="/search/zookeeper/1.htm">zookeeper</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F/1.htm">分布式</a><a class="tag" taget="_blank" href="/search/%E5%85%B1%E4%BA%AB%E9%94%81/1.htm">共享锁</a>
                                    <div>首先,说说我们的场景,订单服务是做成集群的,当两个以上结点同时收到一个相同订单的创建指令,这时并发就产生了,系统就会重复创建订单。等等......场景。这时,分布式共享锁就闪亮登场了。 
  
共享锁在同一个进程中是很容易实现的,但在跨进程或者在不同Server之间就不好实现了。Zookeeper就很容易实现。具体的实现原理官网和其它网站也有翻译,这里就不在赘述了。 
  
官</div>
                                </li>
                                <li><a href="/article/3668.htm"
                                       title="两个容易被忽略的MySQL知识" target="_blank">两个容易被忽略的MySQL知识</a>
                                    <span class="text-muted">tomcat_oracle</span>
<a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a>
                                    <div>1、varchar(5)可以存储多少个汉字,多少个字母数字?     相信有好多人应该跟我一样,对这个已经很熟悉了,根据经验我们能很快的做出决定,比如说用varchar(200)去存储url等等,但是,即使你用了很多次也很熟悉了,也有可能对上面的问题做出错误的回答。     这个问题我查了好多资料,有的人说是可以存储5个字符,2.5个汉字(每个汉字占用两个字节的话),有的人说这个要区分版本,5.0</div>
                                </li>
                                <li><a href="/article/3795.htm"
                                       title="zoj 3827 Information Entropy(水题)" target="_blank">zoj 3827 Information Entropy(水题)</a>
                                    <span class="text-muted">阿尔萨斯</span>
<a class="tag" taget="_blank" href="/search/format/1.htm">format</a>
                                    <div> 题目链接:zoj 3827 Information Entropy 
 题目大意:三种底,计算和。 
 解题思路:调用库函数就可以直接算了,不过要注意Pi = 0的时候,不过它题目里居然也讲了。。。limp→0+plogb(p)=0,因为p是logp的高阶。 
#include <cstdio>
#include <cstring>
#include <cmath&</div>
                                </li>
                </ul>
            </div>
        </div>
    </div>

<div>
    <div class="container">
        <div class="indexes">
            <strong>按字母分类:</strong>
            <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a
                href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a
                href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a
                href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a
                href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a
                href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a
                href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a
                href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a
                href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a>
        </div>
    </div>
</div>
<footer id="footer" class="mb30 mt30">
    <div class="container">
        <div class="footBglm">
            <a target="_blank" href="/">首页</a> -
            <a target="_blank" href="/custom/about.htm">关于我们</a> -
            <a target="_blank" href="/search/Java/1.htm">站内搜索</a> -
            <a target="_blank" href="/sitemap.txt">Sitemap</a> -
            <a target="_blank" href="/custom/delete.htm">侵权投诉</a>
        </div>
        <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.
<!--            <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>-->
        </div>
    </div>
</footer>
<!-- 代码高亮 -->
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script>
<link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/>
<script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script>





</body>

</html>