1. ant.design能不能直接编译成浏览器直接引用便可用
肯定是可以的,但是官方不建议这样做,但如果题主真想这么做的话可以按照下面方法:
1. 下载并编译ant-design
git clone https://github.com/ant-design/ant-design.git
cd ant-design
npm i --registry=http://registry.npm.taobao.org
npm run just-deploy
2. 使用方法
编译完成后在dist目录下antd.js和demo.css就是它的js和css文件,但是antd.js依赖react和react-dom,所以要引用node_moles/react/dist/react.js和node_moles/react-dom/dist/react-dom.js。(外加一些es5-shim等)
在ant-design根目录下建立测试文件antd-test.html,内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="./dist/demo.css">
<script src="https://as.alipayobjects.com/??component/console-polyfill/0.2.2/index.js,component/es5-shim/4.1.14/es5-shim.min.js,component/es5-shim/4.1.14/es5-sham.min.js,component/html5shiv/3.7.2/html5shiv.min.js,g/component/media-match/2.0.2/media.match.min.js"></script>
<script src="./node_moles/react/dist/react.js"></script>
<script src="./node_moles/react-dom/dist/react-dom.js"></script>
<script src="./dist/antd.js"></script>
</head>
<body>
<div id="components-calendar-demo-basic"></div>
<script>
(function(){
'use strict';
function onPanelChange(value, mode) {
console.log(value, mode);
}
ReactDOM.render(React.createElement(antd.Calendar, {
onPanelChange: onPanelChange
}), document.getElementById('components-calendar-demo-basic'));})();
</script>
</body>
</html>
2. node+react后台用webpack怎么做实时更新
每个模块相关的 css、img、js 文件都放在一起,比较直观,删除模块时也会方便许多。测试文件也同样放在一起,哪些模块有没有写测试,哪些测试应该一起随模块删除,一目了然。
build
|-- webpack.config.js # 公共配置
|-- webpack.dev.js # 开发配置
|-- webpack.release.js # 发布配置
docs # 项目文档
node_moles
src # 项目源码
|-- conf # 配置文件
|-- pages # 页面目录
| |-- page1
| | |-- index.js # 页面逻辑
| | |-- index.scss # 页面样式
| | |-- img # 页面图片
| | | |-- xx.png
| | |-- __tests__ # 测试文件
| | | |-- xx.js
| |-- app.html # 入口页
| |-- app.js # 入口JS
|-- components # 组件目录
| |-- loading
| | |-- index.js
| | |-- index.scss
| | |-- __tests__
| | | |-- xx.js
|-- js
| |-- actions
| | |-- index.js
| | |-- __tests__
| | | |-- xx.js
| |-- recers
| | |-- index.js
| | |-- __tests__
| | | |-- xx.js
| |-- xx.js
|-- css # 公共CSS目录
| |-- common.scss
|-- img # 公共图片目录
| |-- xx.png
tests # 其他测试文件
package.json
READNE.md
要完成的功能
编译 jsx、es6、scss 等资源
自动引入静态资源到相应 html 页面
实时编译和刷新浏览器
按指定模块化规范自动包装模块
自动给 css 添加浏览器内核前缀
按需打包合并 js、css
压缩 js、css、html
图片路径处理、压缩、CssSprite
对文件使用 hash 命名,做强缓存
语法检查
全局替换指定字符串
本地接口模拟服务
发布到远端机
针对以上的几点功能,接下来将一步一步的来完成这个
boilerplate 项目, 并记录下每一步的要点。
准备工作
1、根据前面的项目结构规划创建项目骨架
$ make dir webpack-react-rex-es6-boilerplate
$ cd webpack-react-rex-es6-boilerplate
$ mkdir build docs src mock tests
$ touch build/webpack.config.js build/webpack.dev.js build/webpack.release.js
// 创建 package.json
$ npm init
$ ...
2、安装最基本的几个 npm 包
$ npm i webpack webpack-dev-server --save-dev
$ npm i react react-dom react-router rex react-rex rex-thunk --save
3、编写示例代码,最终代码直接查看
boilerplate
4、根据
webpack 文档编写最基本的 webpack 配置,直接使用 NODE API 的方式
/* webpack.config.js */
var webpack = require('webpack');
// 辅助函数
var utils = require('./utils');
var fullPath = utils.fullPath;
var pickFiles = utils.pickFiles;
// 项目根路径
var ROOT_PATH = fullPath('../');
// 项目源码路径
var SRC_PATH = ROOT_PATH + '/src';
// 产出路径
var DIST_PATH = ROOT_PATH + '/dist';
// 是否是开发环境
var __DEV__ = process.env.NODE_ENV !== 'proction';
// conf
var alias = pickFiles({
id: /(conf\/[^\/]+).js$/,
pattern: SRC_PATH + '/conf/*.js'
});
// components
alias = Object.assign(alias, pickFiles({
id: /(components\/[^\/]+)/,
pattern: SRC_PATH + '/components/*/index.js'
}));
// recers
alias = Object.assign(alias, pickFiles({
id: /(recers\/[^\/]+).js/,
pattern: SRC_PATH + '/js/recers/*'
}));
// actions
alias = Object.assign(alias, pickFiles({
id: /(actions\/[^\/]+).js/,
pattern: SRC_PATH + '/js/actions/*'
}));
var config = {
context: SRC_PATH,
entry: {
app: ['./pages/app.js']
},
output: {
path: DIST_PATH,
filename: 'js/bundle.js'
},
mole: {},
resolve: {
alias: alias
},
plugins: [
new webpack.DefinePlugin({
// http://stackoverflow.com/questions/30030031/passing-environment-dependent-variables-in-webpack
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || 'development')
})
]
};
mole.exports = config;
/* webpack.dev.js */
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
var utils = require('./utils');
var PORT = 8080;
var HOST = utils.getIP();
var args = process.argv;
var hot = args.indexOf('--hot') > -1;
var deploy = args.indexOf('--deploy') > -1;
// 本地环境静态资源路径
var localPublicPath = 'http://' + HOST + ':' + PORT + '/';
config.output.publicPath = localPublicPath;
config.entry.app.unshift('webpack-dev-server/client?' + localPublicPath);
new WebpackDevServer(webpack(config), {
hot: hot,
inline: true,
compress: true,
stats: {
chunks: false,
children: false,
colors: true
},
// Set this as true if you want to access dev server from arbitrary url.
// This is handy if you are using a html5 router.
historyApiFallback: true,
}).listen(PORT, HOST, function() {
console.log(localPublicPath);
});
上面的配置写好后就可以开始构建了
$ node build/webpack.dev.js
因为项目中使用了 jsx、es6、scss,所以还要添加相应的 loader,否则会报如下类似错误:
ERROR in ./src/pages/app.js
Mole parse failed: /Users/xiaoyan/working/webpack-react-rex-es6-boilerplate/src/pages/app.js Unexpected token (18:6)
You may need an appropriate loader to handle this file type.
编译 jsx、es6、scss 等资源
使用 bael 和
babel-loader 编译 jsx、es6
安装插件:
babel-preset-es2015 用于解析 es6
安装插件:babel-preset-react 用于解析
jsx
// 首先需要安装 babel
$ npm i babel-core --save-dev
// 安装插件
$ npm i babel-preset-es2015 babel-preset-react --save-dev
// 安装 loader
$ npm i babel-loader --save-dev
在项目根目录创建 .babelrc 文件:
{
"presets": ["es2015", "react"]
}
在 webpack.config.js 里添加:
// 使用缓存
var CACHE_PATH = ROOT_PATH + '/cache';
// loaders
config.mole.loaders = [];
// 使用 babel 编译 jsx、es6
config.mole.loaders.push({
test: /\.js$/,
exclude: /node_moles/,
include: SRC_PATH,
// 这里使用 loaders ,因为后面还需要添加 loader
loaders: ['babel?cacheDirectory=' + CACHE_PATH]
});
3. express框架怎么用react框架作为前端框架
不要设置视图引擎
app.set('views','./views')
app.set('view engine','jade');
//Don't do this
然后你需要引入静态资源
如果你使用webpack,需要把dist里面打包好的文件作为静态资源引入
否则需要把所有的components目录作为静态资源引入
你的React就是简单的静态资源
app.use(express.static(path.join(__dirname,'src')));
最后直接在路由返回文件
app.get('/',function(req,res){
res.sendFile(path.join(__dirname,'index.html'))
})
4. 如何解决webpack打包后,dist文件过大的问题
去除不必要的插件
刚开始用 webpack 的时候,开发环境和生产环境用的是同一个 webpack 配置文件,导致生产环境打包的 JS 文件包含了一大堆没必要的插件,比如 HotMoleReplacementPlugin, NoErrorsPlugin... 这时候不管用什么优化方式,都没多大效果。所以,如果你打包后的文件非常大的话,先检查下是不是包含了这些插件。
提取第三方库
像 react 这个库的核心代码就有 627 KB,这样和我们的源代码放在一起打包,体积肯定会很大。所以可以在 webpack 中设置
{
entry: {
bundle: 'app'
vendor: ['react']
}
plugins: {
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js')
}
}
这样打包之后就会多出一个 vendor.js 文件,之后在引入我们自己的代码之前,都要先引入这个文件。比如在 index.html 中
<script src="/build/vendor.js"></script>
<script src="/build/bundle.js"></script>
除了这种方式之外,还可以通过引用外部文件的方式引入第三方库,比如像下面的配置
{
externals: {
'react': 'React'
}
}
externals 对象的 key 是给 require 时用的,比如 require('react'),对象的 value 表示的是如何在 global 中访问到该对象,这里是 window.React。这时候 index.html 就变成下面这样
<script src="//cdn.bootcss.com/react/0.14.7/react.min.js"></script>
<script src="/build/bundle.js"></script>
当然,个人更推荐第一种方式。
代码压缩
webpack 自带了一个压缩插件 UglifyJsPlugin,只需要在配置文件中引入即可。
{
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
}
加入了这个插件之后,编译的速度会明显变慢,所以一般只在生产环境启用。
另外,服务器端还可以开启 gzip 压缩,优化的效果更明显。
代码分割
什么是代码分割呢?我们知道,一般加载一个网页都会把全部的 js 代码都加载下来。但是对于 web app 来说,我们更想要的是只加载当前 UI 的代码,没有点击的部分不加载。
看起来好像挺麻烦,但是通过 webpack 的 code split 以及配合 react router 就可以方便实现。具体的例子可以看下 react router 的官方示例 huge apps。不过这里还是讲下之前配置踩过的坑。
code split 是不支持 ES6 的模块系统的,所以在导入和导出的时候千万要注意,特别是导出。如果你导出组件的时候用 ES6 的方式,这时候不管导入是用 CommomJs 还是 AMD,都会失败,而且还不会报错!
当然会踩到这个坑也是因为我刚刚才用 NodeJS,而且一入门就是用 ES6 的风格。除了这个之外,还有一点也要注意,在生产环境的 webpack 配置文件中,要加上 publicPath
output: {
path: xxx,
publicPath: yyy,
filename: 'bundle.js'
}
不然的话,webpack 在加载 chunk 的时候,路径会出错。
设置缓存
开始这个小节之前,可以先看下大神的一篇文章:大公司里怎样开发和部署前端代码。
对于静态文件,第一次获取之后,文件内容没改变的话,浏览器直接读取缓存文件即可。那如果缓存设置过长,文件要更新怎么办呢?嗯,以文件内容的 MD5 作为文件名就是一个不错的解决方案。来看下用 webpack 应该怎样实现
output: {
path: xxx,
publicPath: yyy,
filename: '[name]-[chunkhash:6].js'
}
打包后的文件名加入了 hash 值
const bundler = webpack(config)
bundler.run((err, stats) => {
let assets = stats.toJson().assets
let name
for (let i = 0; i < assets.length; i++) {
if (assets[i].name.startsWith('main')) {
name = assets[i].name
break
}
}
fs.stat(config.buildTemplatePath, (err, stats) => {
if (err) {
fs.mkdirSync(config.buildTemplatePath)
}
writeTemplate(name)
})
})
手动调用 webpack 的 API,获取打包后的文件名,通过 writeTemplate 更新 html 代码。完整代码猛戳 gitst。
5. 如何用原生的react,webpack,es6来使用蚂蚁金服的ant design组件库
1.准备:
npm安装以下组件
a.安装react/antd:
npm install react react-dom antd --save
b.安装webpack/less:
npm install webpack less --save-dev
webpack根据需要选择使用-g安装
c.安装babel-loader以及其他相关package:
npm install babel-loader babel-core babel-preset-es2015 babel-preset-react --save-dev
d.选择安装style-loader/css-loader
npm install style-loader css-loader --save-dev
2. 配置webpack.config.js
具体配置可以查看webpack提供的例子,主要依赖的是babel-loader
babel-loader上也有webpack.config.js应该如何编写的例子,传送门: babel-loader
3. 编写我们的文件(例如: demo-antd.jsx)
只使用了antd提供的Button组件。只使用了antd提供的Button组件。
ps: 对比
import { Button } from 'antd';
和
import Button from 'antd/lib/button';
后者不会将antd中所有的内容都引入,如果你只是需要Button这么一种组件的话,推荐使用后一种写法。
4. 执行构建
webpack ./demo-antd.jsx demo-antd-bundle.js
将生成demo-antd-bundle.js文件
5. 在页面中引入bundle文件(demo-antd-bundle.js)
执行到这一步,在浏览器中查看页面可以应该可以看到一个原生样式的button元素,因为antd并没有将样式使用内联style的方式写入js文件中。
这里我们暂时将问题一搁置,来看看问题二:组件库的内部机制。
因为没有深入去看过antd的源代码,没法详细说明antd的在代码编写上的一些....怎么说,就是‘代码为什么这样写’这个问题,有兴趣的话,可以去查看源码,正如 @陈吉浩 所说,查看github上的代码比npm下载后的代码更舒服。
6. webpack+react能转成java吗
第一步:
mkdir react-demo
cd react-demo
npm init -y
npm i webpack webpack-dev-server html-webpack-plugin webpack-merge babel-loader babel-core css-loader style-loader babel-preset-react-hmre babel-preset-es2015 babel-preset-react -D
mkdir app
mkdir dist
mkdir assets
touch assets/index.tmpl.html
第二步,编辑index.tmpl.html为如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
第二步,打开你的 package.json 文件,添加如下字符串:
...
"scripts": {
"build": "webpack",
"start": "webpack-dev-server"
},
"babel":{
"presets": [
"es2015",
"react"
],
"env": {
"start": {
"presets": [
"react-hmre"
]
}
}
}
...
第三步:在根目录新建一个 webpack.config.js 的文件,写入如下配置
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const merge = require('webpack-merge');
const TARGET = process.env.npm_lifecycle_event;
process.env.BABEL_ENV = TARGET;
const PATHS = {
app: path.join(__dirname, 'app'),
build: path.join(__dirname, 'dist'),
template: path.resolve(__dirname, 'assets', 'index.tmpl.html'),
};
const common = {
entry: {
app: PATHS.app,
},
output: {
path: PATHS.build,
filename: 'bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
title: 'react demo',
template: PATHS.template,
inject: 'body',
}),
],
mole: {
loaders: [{
test: /\.jsx?$/,
loaders: ['babel?cacheDirectory'],
include: PATHS.app,
}, {
test: /\.css$/,
loaders: ['style', 'css'],
include: PATHS.app,
}],
},
resolve: {
extensions: ['', '.js', '.jsx'],
},
};
if (TARGET === 'start' || !TARGET) {
mole.exports = merge(common, {
devtool: 'eval-source-map',
devServer: {
contentBase: '/dist',
historyApiFallback: true,
hot: true,
inline: true,
progress: true,
stats: 'errors-only',
},
plugins: [
new webpack.HotMoleReplacementPlugin(),
],
});
}
if (TARGET === 'build') {
mole.exports = merge(common, {});
}
第四步:到这里,关于react的需要的webpack方面的配置就结束了,接下来我们来写一个很小的示例来生成一个真正的react文件。
npm i react react-dom react-router -S
touch app/App.jsx
touch app/index.jsx
编辑 App.jsx 文件如下:
import React, { Component } from 'react';
import {
Router,
Route,
Link,
IndexLink,
IndexRoute,
hashHistory,
} from 'react-router';
const activeStyle = {
color: '#53acff',
};
const Nav = () => (
<div>
<IndexLink onlyActiveOnIndex activeStyle={activeStyle} to="/">主页</IndexLink>
<IndexLink onlyActiveOnIndex activeStyle={activeStyle} to="/address">地址</IndexLink>
</div>
);
const Container = (props) => <div>
<Nav /> { props.children }
</div>;
const Twitter = () => <div>@xiaomingplus twitter</div>;
const Instagram = () => <div>@xiaomingplus instagram</div>;
const NotFound = () => (
<h1>404.. 找不到该页面!</h1>
);
const Home = () => <h1>你好,这是主页。</h1>;
const Address = (props) => <div>
<br />
<Link activeStyle={{ color: '#53acff' }} to="/address">这是Twitter</Link>
<Link to="/address/instagram">这是Instagram</Link>
<h1>欢迎互关!</h1>
{ props.children }
</div>;
class App extends Component {
construct() {
}
render() {
return (
<Router history={hashHistory}>
<Route path="/" component={Container}>
<IndexRoute component={Home} />
<Route path="/address" component={Address}>
<IndexRoute component={Twitter} />
<Route path="instagram" component={Instagram} />
</Route>
<Route path="*" component={NotFound} />
</Route>
</Router>
);
}
}
export default App;
编辑 index.jsx 文件:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';
ReactDOM.render(
<App />, document.getElementById('root'));
ok,到这里你已经实用react-router构建了一个有路由的应用,接下来启动这个应用吧。
npm start
用浏览器访问: http://localhost:8080 ,你将看到如下界面