', {
62 | 'href': gitbook.state.basePath + '/' + item.url + '?h=' + encodeURIComponent(res.query),
63 | 'text': item.title,
64 | 'data-is-search': 1
65 | })
66 |
67 | if ($link[0].href.split('?')[0] === window.location.href.split('?')[0]) {
68 | $link[0].setAttribute('data-need-reload', 1)
69 | }
70 |
71 | var content = item.body.trim()
72 | if (content.length > MAX_DESCRIPTION_SIZE) {
73 | content = content + '...'
74 | }
75 | var $content = $('').html(content)
76 |
77 | $link.appendTo($title)
78 | $title.appendTo($li)
79 | $content.appendTo($li)
80 | $li.appendTo($searchList)
81 | })
82 | $('.body-inner').scrollTop(0)
83 | }
84 |
85 | function escapeRegExp (keyword) {
86 | // escape regexp prevserve word
87 | return String(keyword).replace(/([-.*+?^${}()|[\]/\\])/g, '\\$1')
88 | }
89 |
90 | function query (originKeyword) {
91 | if (originKeyword == null || originKeyword.trim() === '') return
92 |
93 | var results = []
94 | var index = -1
95 | for (var page in INDEX_DATA) {
96 | var store = INDEX_DATA[page]
97 | var keyword = originKeyword.toLowerCase() // ignore case
98 | var hit = false
99 | if (store.keywords && ~store.keywords.split(/\s+/).indexOf(keyword.split(':').pop())) {
100 | if (/.:./.test(keyword)) {
101 | keyword = keyword.split(':').slice(0, -1).join(':')
102 | } else {
103 | hit = true
104 | }
105 | }
106 | var keywordRe = new RegExp('(' + escapeRegExp(keyword) + ')', 'gi')
107 | if (
108 | hit || ~(index = store.body.toLowerCase().indexOf(keyword))
109 | ) {
110 | results.push({
111 | url: page,
112 | title: store.title,
113 | body: store.body.substr(Math.max(0, index - 50), MAX_DESCRIPTION_SIZE)
114 | .replace(/^[^\s,.]+./, '').replace(/(..*)[\s,.].*/, '$1') // prevent break word
115 | .replace(keywordRe, '$1 ')
116 | })
117 | }
118 | }
119 | displayResults({
120 | count: results.length,
121 | query: keyword,
122 | results: results
123 | })
124 | }
125 |
126 | function launchSearch (keyword) {
127 | // Add class for loading
128 | $body.addClass('with-search')
129 | $body.addClass('search-loading')
130 |
131 | function doSearch () {
132 | query(keyword)
133 | $body.removeClass('search-loading')
134 | }
135 |
136 | throttle(doSearch)()
137 | }
138 |
139 | function closeSearch () {
140 | $body.removeClass('with-search')
141 | $('#book-search-results').removeClass('open')
142 | }
143 |
144 | function bindSearch () {
145 | // Bind DOM
146 | var $body = $('body')
147 |
148 | // Launch query based on input content
149 | function handleUpdate () {
150 | var $searchInput = $('#book-search-input input')
151 | var keyword = $searchInput.val()
152 |
153 | if (keyword.length === 0) {
154 | closeSearch()
155 | } else {
156 | launchSearch(keyword)
157 | }
158 | }
159 |
160 | $body.on('keyup', '#book-search-input input', function (e) {
161 | if (e.keyCode === 13) {
162 | if (usePushState) {
163 | var uri = updateQueryString('q', $(this).val())
164 | window.history.pushState({
165 | path: uri
166 | }, null, uri)
167 | }
168 | }
169 | handleUpdate()
170 | })
171 |
172 | // Push to history on blur
173 | $body.on('blur', '#book-search-input input', function (e) {
174 | // Update history state
175 | if (usePushState) {
176 | var uri = updateQueryString('q', $(this).val())
177 | window.history.pushState({
178 | path: uri
179 | }, null, uri)
180 | }
181 | })
182 | }
183 |
184 | gitbook.events.on('start', function () {
185 | bindSearch()
186 | $.getJSON(state.basePath + '/search_plus_index.json').then(function (data) {
187 | INDEX_DATA = data
188 | showResult()
189 | closeSearch()
190 | })
191 | })
192 |
193 | var markConfig = {
194 | 'ignoreJoiners': true,
195 | 'acrossElements': true,
196 | 'separateWordSearch': false
197 | }
198 | // highlight
199 | var highLightPageInner = function (keyword) {
200 | var pageInner = $('.page-inner')
201 | if (/(?:(.+)?\:)(.+)/.test(keyword)) {
202 | pageInner.mark(RegExp.$1, markConfig)
203 | }
204 | pageInner.mark(keyword, markConfig)
205 |
206 | setTimeout(function () {
207 | var mark = $('mark[data-markjs="true"]')
208 | if (mark.length) {
209 | mark[0].scrollIntoView()
210 | }
211 | }, 100)
212 | }
213 |
214 | function showResult () {
215 | var keyword, type
216 | if (/\b(q|h)=([^&]+)/.test(window.location.search)) {
217 | type = RegExp.$1
218 | keyword = decodeURIComponent(RegExp.$2)
219 | if (type === 'q') {
220 | launchSearch(keyword)
221 | } else {
222 | highLightPageInner(keyword)
223 | }
224 | $('#book-search-input input').val(keyword)
225 | }
226 | }
227 |
228 | gitbook.events.on('page.change', showResult)
229 |
230 | function updateQueryString (key, value) {
231 | value = encodeURIComponent(value)
232 |
233 | var url = window.location.href.replace(/([?&])(?:q|h)=([^&]+)(&|$)/, function (all, pre, value, end) {
234 | if (end === '&') {
235 | return pre
236 | }
237 | return ''
238 | })
239 | var re = new RegExp('([?&])' + key + '=.*?(&|#|$)(.*)', 'gi')
240 | var hash
241 |
242 | if (re.test(url)) {
243 | if (typeof value !== 'undefined' && value !== null) { return url.replace(re, '$1' + key + '=' + value + '$2$3') } else {
244 | hash = url.split('#')
245 | url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '')
246 | if (typeof hash[1] !== 'undefined' && hash[1] !== null) { url += '#' + hash[1] }
247 | return url
248 | }
249 | } else {
250 | if (typeof value !== 'undefined' && value !== null) {
251 | var separator = url.indexOf('?') !== -1 ? '&' : '?'
252 | hash = url.split('#')
253 | url = hash[0] + separator + key + '=' + value
254 | if (typeof hash[1] !== 'undefined' && hash[1] !== null) { url += '#' + hash[1] }
255 | return url
256 | } else { return url }
257 | }
258 | }
259 | window.addEventListener('click', function (e) {
260 | if (e.target.tagName === 'A' && e.target.getAttribute('data-need-reload')) {
261 | setTimeout(function () {
262 | window.location.reload()
263 | }, 100)
264 | }
265 | }, true)
266 | })
267 |
--------------------------------------------------------------------------------
/examples/book/gitbook/gitbook-plugin-sharing/buttons.js:
--------------------------------------------------------------------------------
1 | require(['gitbook', 'jquery'], function(gitbook, $) {
2 | var SITES = {
3 | 'facebook': {
4 | 'label': 'Facebook',
5 | 'icon': 'fa fa-facebook',
6 | 'onClick': function(e) {
7 | e.preventDefault();
8 | window.open('http://www.facebook.com/sharer/sharer.php?s=100&p[url]='+encodeURIComponent(location.href));
9 | }
10 | },
11 | 'twitter': {
12 | 'label': 'Twitter',
13 | 'icon': 'fa fa-twitter',
14 | 'onClick': function(e) {
15 | e.preventDefault();
16 | window.open('http://twitter.com/home?status='+encodeURIComponent(document.title+' '+location.href));
17 | }
18 | },
19 | 'google': {
20 | 'label': 'Google+',
21 | 'icon': 'fa fa-google-plus',
22 | 'onClick': function(e) {
23 | e.preventDefault();
24 | window.open('https://plus.google.com/share?url='+encodeURIComponent(location.href));
25 | }
26 | },
27 | 'weibo': {
28 | 'label': 'Weibo',
29 | 'icon': 'fa fa-weibo',
30 | 'onClick': function(e) {
31 | e.preventDefault();
32 | window.open('http://service.weibo.com/share/share.php?content=utf-8&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title));
33 | }
34 | },
35 | 'instapaper': {
36 | 'label': 'Instapaper',
37 | 'icon': 'fa fa-instapaper',
38 | 'onClick': function(e) {
39 | e.preventDefault();
40 | window.open('http://www.instapaper.com/text?u='+encodeURIComponent(location.href));
41 | }
42 | },
43 | 'vk': {
44 | 'label': 'VK',
45 | 'icon': 'fa fa-vk',
46 | 'onClick': function(e) {
47 | e.preventDefault();
48 | window.open('http://vkontakte.ru/share.php?url='+encodeURIComponent(location.href));
49 | }
50 | }
51 | };
52 |
53 |
54 |
55 | gitbook.events.bind('start', function(e, config) {
56 | var opts = config.sharing;
57 |
58 | // Create dropdown menu
59 | var menu = $.map(opts.all, function(id) {
60 | var site = SITES[id];
61 |
62 | return {
63 | text: site.label,
64 | onClick: site.onClick
65 | };
66 | });
67 |
68 | // Create main button with dropdown
69 | if (menu.length > 0) {
70 | gitbook.toolbar.createButton({
71 | icon: 'fa fa-share-alt',
72 | label: 'Share',
73 | position: 'right',
74 | dropdown: [menu]
75 | });
76 | }
77 |
78 | // Direct actions to share
79 | $.each(SITES, function(sideId, site) {
80 | if (!opts[sideId]) return;
81 |
82 | gitbook.toolbar.createButton({
83 | icon: site.icon,
84 | label: site.text,
85 | position: 'right',
86 | onClick: site.onClick
87 | });
88 | });
89 | });
90 | });
91 |
--------------------------------------------------------------------------------
/examples/book/gitbook/images/apple-touch-icon-precomposed-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lwdgit/gitbook-plugin-search-plus/4be5e093436adb80fbd3c95a8ebc497588ee3522/examples/book/gitbook/images/apple-touch-icon-precomposed-152.png
--------------------------------------------------------------------------------
/examples/book/gitbook/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lwdgit/gitbook-plugin-search-plus/4be5e093436adb80fbd3c95a8ebc497588ee3522/examples/book/gitbook/images/favicon.ico
--------------------------------------------------------------------------------
/examples/cli.js:
--------------------------------------------------------------------------------
1 | var cli = require.resolve('gitbook-cli')
2 | console.log('node ' + cli + ' ' + process.argv.slice(2).join(' '))
3 | var proc = require('child_process').exec('node ' + cli + ' ' + process.argv.slice(2).join(' '))
4 | proc.stdout.on('data', (info) => {
5 | process.stdout.write(info)
6 | })
7 | proc.stderr.on('data', (err) => {
8 | process.stdout.write(err)
9 | })
10 |
--------------------------------------------------------------------------------
/examples/content/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | gh-pages/
3 | wiki/
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/examples/content/Assets.md:
--------------------------------------------------------------------------------
1 | Historically web frontends have been split in three separate parts: structure markup (ie. HTML), style (ie. CSS) and logic (ie. JavaScript). You end up with something functional once you have these together. A well designed site should work even without JavaScript enabled and the content should make sense even without CSS. In practice this isn't always true and depending on your requirements you may be able to flex here.
2 |
3 | I won't go into detail to explain why we ended up with HTML, CSS and JavaScript. This is the triad what you'll build will most likely be using given that's what browsers support. In case of JavaScript you might compile down to something that's ES5 compatible and set up shims where needed. Shims can come in handy if you need to patch functionality for old browsers (IE 8 and such) and can help to an extent. A site such as [caniuse.com](http://caniuse.com/) can be helpful in figuring out what works and where and whether shims exist.
4 |
5 | ## CSS
6 |
7 | In its essence CSS is aspect oriented programming. It will allow you attach some behavior to selected features. Sometimes the boundary between CSS and JavaScript can be quite fuzzy and at times people have achieved amazing feats just by using CSS. That doesn't mean it should be used that way but it's always fun to push the envelope a bit.
8 |
9 | These days CSS incorporates a powerful selector syntax, media queries (customize per resolution), animation capabilities, whatnot. Depending on what you are doing you may whether love or hate its layout capabilities. Originally CSS was designed page layout in mind. These days we live more and more in the world of apps so you might need to struggle every once in a while a bit.
10 |
11 | Understanding the box model of CSS can help a lot. In addition the usage of CSS reset can be helpful. That eliminates some of the rendering differences between various browsers and provides more consistent results. In addition settings attributes such as `box-sizing: border-box;` can make the language more intuitive to use.
12 |
13 | > Instead of CSS we could be writing something like JavaScript, namely [JSS](https://en.wikipedia.org/wiki/JavaScript_Style_Sheets), if things had gone differently.
14 |
15 | ### Missing Features
16 |
17 | The core language is missing a lot of power programmers take granted. You won't have things such as variables or functions. This is the main reason why various preprocessors have appeared. They add some new functionality that has great potential to simplify your work as a developer. It isn't very [hard to write a system of your own](http://www.nixtu.info/2011/12/how-to-write-css-preprocessor-using.html). That said these days people like to stick with something like [Sass](http://sass-lang.com/), [Less](http://lesscss.org/) or [Stylus](http://learnboost.github.io/stylus/). Each to his own.
18 |
19 | Using webpack makes it easy to utilize these solutions. Often all you need to do is to set up a loader and then just `require` the assets you need. Images, fonts and such take extra setup but that's what this chapter is about so read on.
20 |
21 | ### Conventions
22 |
23 | There isn't single right way to develop CSS. As a result many approaches have appeared. Examples: [SMACSS](https://smacss.com/), [Suit CSS](http://suitcss.github.io/), [BEM](https://bem.info/).
24 |
25 | On macro level there are entire schools of design such as [Responsive Web Design](https://en.wikipedia.org/wiki/Responsive_web_design), Mobile First Design or [Atomic Web Design](http://bradfrost.com/blog/post/atomic-web-design/).
26 |
27 | With React we might be forced to rethink some of our approaches as highlighted by [a presentation by @vjeux](https://speakerdeck.com/vjeux/react-css-in-js). There are already tools such as [react-style](https://github.com/js-next/react-style) and [JSS](https://github.com/jsstyles/jss) which allow us to author CSS within components.
28 |
29 | You could say moving declarations back to markup is backwards. After all, inline styles have been frowned upon a long time. Every once in a while it is a good idea to challenge the dogma and move ahead. Maybe it can be useful to have all relevant information on component level. Even if you have basic style declarations on component level this doesn't mean you couldn't inject customizations from higher level if you design your components right.
30 |
31 | Of course there are questions such are these kind of ideas compatible with CSS frameworks such as [Bootstrap](http://getbootstrap.com/), [Foundation](http://foundation.zurb.com/) or [Pure](http://purecss.io/) but that's another topic.
32 |
33 | ## Fonts
34 |
35 | The simplest way to make your page look nicer is to set
36 |
37 | ```css
38 | body {
39 | font-family: Sans-Serif;
40 | }
41 | ```
42 |
43 | Of course CSS provides [a ton of other options](https://developer.mozilla.org/en/docs/Web/CSS/font). Even more interesting these days we have [web fonts](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face) which provide additional options for designers.
44 |
45 | ## Images
46 |
47 | A large amount of content we consume is image based. Especially thanks to the introduction of high resolution displays on mobile devices, there are additional challenges available. You could say the situation is still not ideal but we are getting there thanks to initiatives such as [Responsive Images Community Group](http://responsiveimages.org/). It will take a little bit of effort to serve the correct images for various devices but in the end if you want to provide the best service, you should go for the extra mile.
48 |
--------------------------------------------------------------------------------
/examples/content/Authoring-libraries.md:
--------------------------------------------------------------------------------
1 | Webpack can be handy for packaging your library for general consumption. You can use it to output UMD, a format that's compatible with various module loaders (CommonJS, AMD) and globals.
2 |
3 | Webpack 可以非常方便地打包和生成你的库,你可以用它输出 UMD,一种可以兼容很多模块加载器(CommonJS、AMD)和全局变量的格式。
4 |
5 | ## 如何把库输出成 UMD?
6 |
7 | Especially if you are creating a library, it can be useful to output an UMD version of your library. This can be achieved using the following snippet:
8 |
9 | 尤其是如果你创建了一个库,那么输出一个 UMD 版本是非常有用的,就像下面的片段一样实现:
10 |
11 | ```javascript
12 | output: {
13 | path: './dist',
14 | filename: 'mylibrary.js',
15 | libraryTarget: 'umd',
16 | library: 'MyLibrary',
17 | },
18 | ```
19 |
20 | In order to avoid bundling big dependencies like React, you'll want to use a configuration like this in addition:
21 |
22 | 为了避免去合并类似 React 的大型依赖,你可以使用下面这样的设置:
23 |
24 | ```javascript
25 | externals: {
26 | react: 'react',
27 | 'react/addons': 'react'
28 | },
29 | ```
30 |
31 | ## 如何输出压缩版?
32 |
33 | Here's the basic idea:
34 |
35 | 这里是一个简单的方案:
36 |
37 | ```javascript
38 | output: {
39 | path: './dist',
40 | filename: 'awesomemular.min.js',
41 | libraryTarget: 'umd',
42 | library: 'Awesomemular',
43 | },
44 | plugins: [
45 | new webpack.optimize.UglifyJsPlugin({
46 | compress: {
47 | warnings: false
48 | },
49 | }),
50 | ]
51 | ```
--------------------------------------------------------------------------------
/examples/content/Automatic-CSS-refresh.md:
--------------------------------------------------------------------------------
1 | When **webpack-dev-server** is running with [Automatic browser refresh](Automatic-browser-refresh) the CSS will also update, but a bit differently. When you do a change to a CSS file the style tag belonging to that file will be updated with the new content... without a refresh!
2 |
3 | 当 **Webpack-dev-server** 在 [浏览器自动刷新](Automatic-browser-refresh) 下运行的时候,CSS 也会自动更新,不过有点不同的是,当你改变了一个 CSS 文件,属于那个文件的标签会更新新的内容但不会刷新。
--------------------------------------------------------------------------------
/examples/content/Automatic-browser-refresh.md:
--------------------------------------------------------------------------------
1 | When **webpack-dev-server** is running it will watch your files for changes. When that happens it rebundles your project and notifies browsers listening to refresh. To trigger this behavior you need to change your *index.html* file in the `build/` folder.
2 |
3 |
4 | 当运行 **webpack-dev-server** 的时候,它会监听你的文件修改。当项目重新合并之后,会通知浏览器刷新。为了能够触发这样的行为,你需要把你的 *index.html* 放到 `build/` 文件夹下,然后做这样的修改:
5 |
6 | **build/index.html**
7 |
8 | ```html
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | ```
19 |
20 | We added a script that refreshes the application when a change occurs. You will also need to add an entry point to your configuration:
21 |
22 | 我们需要增加一个脚本当发生改动的时候去自动刷新应用,你需要在配置中增加一个入口点。
23 |
24 | **webpack.config.js**
25 |
26 |
27 | ```javascript
28 | var path = require('path');
29 |
30 | module.exports = {
31 | entry: [
32 | 'webpack/hot/dev-server',
33 | 'webpack-dev-server/client?http://localhost:8080',
34 | path.resolve(__dirname, 'app/main.js')
35 | ],
36 | output: {
37 | path: path.resolve(__dirname, 'build'),
38 | filename: 'bundle.js',
39 | },
40 | };
41 | ```
42 |
43 | Thats it! Now your application will automatically refresh on file changes.
44 |
45 | 就是这样!现在你的应用就可以在文件修改之后自动刷新了。
46 |
47 | ## 默认环境
48 |
49 | In the example above we created our own *index.html* file to give more freedom and control. It is also possible to run the application from **http://localhost:8080/webpack-dev-server/bundle**. This will fire up a default *index.html* file that you do not control. It also fires this file up in an iFrame allowing for a status bar to indicate the status of the rebundling process.
50 |
51 | 在上面的例子中我们创建了 *index.html* 文件来获取更多的自由和控制。同样也可以从 **http://localhost:8080/webpack-dev-server/bundle** 运行应用。这会触发一个默认的你不能控制的 *index.html* ,它同样会触发一个允许iFrame中显示重合并的过程。
52 |
53 |
54 | > I discuss an alternative, `inline` based approach at the [Developing with Webpack](http://survivejs.com/webpack_react/developing_with_webpack/) chapter of *SurviveJS - Webpack and React*.
55 |
56 | > 我探讨了一个可供代替的方法,`inline` 是基于 [Developing with Webpack](http://survivejs.com/webpack_react/developing_with_webpack/) 中 *SurviveJS - Webpack and React* 章节的方案。
57 |
--------------------------------------------------------------------------------
/examples/content/Basics.md:
--------------------------------------------------------------------------------
1 | ## Why use Webpack?
2 | - Minimal configuration for the common workflow
3 | - Analyzes your project code as chunks that can be rearranged to optimize user experience
4 | - Especially useful with React JS
5 | - Powerful features like automatically inlining images and fonts
6 | - ES6 support right out of the box
--------------------------------------------------------------------------------
/examples/content/Configuring-react-js.md:
--------------------------------------------------------------------------------
1 | ## 安装 React JS
2 |
3 | `npm install react --save`
4 |
5 | There is really nothing more to it. You can now start using React JS in your code.
6 |
7 | 没什么好讲的,接下来就可以在你的代码中使用 React JS 了。
8 |
9 | ## 在代码中使用 ReactJS
10 |
11 | **component.jsx**
12 |
13 | ```javascript
14 | import React from 'react';
15 |
16 | export default class Hello extends React.Component {
17 | render() {
18 | return Hello world ;
19 | }
20 | }
21 | ```
22 |
23 | **main.js**
24 |
25 | ```javascript
26 | import React from 'react';
27 | import Hello from './component.jsx';
28 |
29 | main();
30 |
31 | function main() {
32 | React.render( , document.getElementById('app'));
33 | }
34 | ```
35 |
36 | **build/index.html**
37 |
38 | ```javascript
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | ```
52 |
53 | ## 转换 JSX
54 |
55 | To use the JSX syntax you will need webpack to transform your JavaScript. This is the job of a loader. We'll use [Babel](https://babeljs.io/) as it's nice and has plenty of features.
56 |
57 | 为了能够使用 JSX 语法,你需要用 Webpack 来转码你的 JavaScript,这是加载器的工作,我们可以使用一个很好用也有很多功能的 [Babel](https://babeljs.io/)。
58 |
59 | `npm install babel-loader babel-core --save-dev`
60 |
61 | Now we have to configure webpack to use this loader.
62 |
63 | 现在我们需要去配置 Webpack 来使用加载器。
64 |
65 | *webpack.config.js*
66 | ```javascript
67 | var path = require('path');
68 | var config = {
69 | entry: path.resolve(__dirname, 'app/main.js'),
70 | output: {
71 | path: path.resolve(__dirname, 'build'),
72 | filename: 'bundle.js'
73 | },
74 | module: {
75 | loaders: [{
76 | test: /\.jsx?$/, // 用正则来匹配文件路径,这段意思是匹配 js 或者 jsx
77 | loader: 'babel' // 加载模块 "babel" 是 "babel-loader" 的缩写
78 | }]
79 | }
80 | };
81 |
82 | module.exports = config;
83 | ```
84 |
85 | Webpack will test each path required in your code. In this project we are using ES6 module loader syntax, which means that the require path of `import MyComponent from './Component.jsx';` is `'./Component.jsx'`.
86 |
87 | Webpack 会在你的项目中测试所有路径,如果我们项目中使用 ES6 模块加载器语法,比如 `import MyComponent from './Component.jsx';` 是会去匹配 `'./Component.jsx'`。
88 |
89 | Run `npm run dev` in the console and refresh the page to see something.
90 |
91 | 在命令行中运行 `npm run dev`,然后刷新页面就可以看到修改。
--------------------------------------------------------------------------------
/examples/content/Creating-a-dev-and-production-config.md:
--------------------------------------------------------------------------------
1 | - Split configuration into two files
--------------------------------------------------------------------------------
/examples/content/Custom-workflow-entry.md:
--------------------------------------------------------------------------------
1 | When running your workflow from **http://localhost:8080/web-dev-server/bundle** you do not control the *index.html* file where the scripts are loaded.
2 |
3 | ## Running your own index.html file
4 | In your *package.json* you have your *dev* script. `"webpack-dev-server --devtool eval --progress --colors --content-base build/"`. The *--content-base build/* parameter tells webpack-dev-server where to load your application from. In this example that would be `build/`.
5 |
6 | ## Create the index.html file
7 | In the `build/` folder create a new *index.html* with this content.
--------------------------------------------------------------------------------
/examples/content/Getting-started.md:
--------------------------------------------------------------------------------
1 | > Before getting started you should make sure you have a recent version of Node.js and NPM installed. See [nodejs.org](http://nodejs.org/) for installation details. We'll use NPM to set up various tools.
2 |
3 | > 在开始之前,你需要把你的 Node.js 和 NPM 都更新到最新的版本。访问 [nodejs.org](http://nodejs.org/) 查看安装详情。我们将会使用 NPM 安装一些工具。
4 |
5 | Getting started with Webpack is straightforward. I'll show you how to set up a simple project based on it. As a first step, set a directory for your project and hit `npm init` and fill in some answers. That will create a `package.json` for you. Don't worry if some fields don't look ok, you can modify those later.
6 |
7 | 开始使用 Webpack 非常简单,我会展示给你看使用它的一个简单的项目。第一步,为你的项目新建一个文件夹,然后输入 `npm init`,然后填写相关问题。这样会为你创建了 `package.json`,不用担心填错,你可以之后修改它。
8 |
9 | ## 安装 Webpack
10 |
11 | Next you should get Webpack installed. We'll do a local install and save it as a project dependency. This way you can invoke the build anywhere (build server, whatnot). Run `npm i webpack --save-dev`. If you want to run the tool, hit `node_modules/.bin/webpack`.
12 |
13 | 接下来我们安装 Webpack,我们要把它安装在本地,然后把它作为项目依赖保存下来。这样你可以在任何地方编译(服务端编译之类的)。输入 `npm i webpack --save-dev`。如果你想运行它,就输入 `node_modules/.bin/webpack`。
14 |
15 | ## 目录结构
16 |
17 | Structure your project like this:
18 |
19 | 项目的目录结构长这样:
20 |
21 | - /app
22 | - main.js
23 | - component.js
24 | - /build
25 | - bundle.js (自动创建)
26 | - index.html
27 | - package.json
28 | - webpack.config.js
29 |
30 | In this case we'll create `bundle.js` using Webpack based on our `/app`. To make this possible, let's set up `webpack.config.js`.
31 |
32 | 我们会使用 Webpack 在我们的 `/app` 里来自动创建 `bundle.js` 。接下来,我们来设置 `webpack.config.js`。
33 |
34 | ## 设置 Webpack
35 |
36 | Webpack 的配置文件长这样:
37 |
38 | *webpack.config.js*
39 |
40 | ```javascript
41 | var path = require('path');
42 |
43 |
44 | module.exports = {
45 | entry: path.resolve(__dirname, 'app/main.js'),
46 | output: {
47 | path: path.resolve(__dirname, 'build'),
48 | filename: 'bundle.js',
49 | },
50 | };
51 | ```
52 |
53 | ## 运行你的第一个编译
54 |
55 | Now that we have basic configuration in place, we'll need something to build. Let's start with a classic `Hello World` type of app. Set up `/app` like this:
56 |
57 | 现在我们有了一个最简单的配置,我们需要有什么东西去编译,让我们开始一个经典的 `Hello World`,设置 `/app` 像这样:
58 |
59 | *app/component.js*
60 |
61 | ```javascript
62 | 'use strict';
63 |
64 |
65 | module.exports = function () {
66 | var element = document.createElement('h1');
67 |
68 | element.innerHTML = 'Hello world';
69 |
70 | return element;
71 | };
72 | ```
73 |
74 | *app/main.js*
75 |
76 | ```javascript
77 | 'use strict';
78 | var component = require('./component.js');
79 |
80 |
81 | document.body.appendChild(component());
82 |
83 | ```
84 |
85 | Now run `webpack` in your terminal and your application will be built. A *bundle.js* file will appear in your `/build` folder. Your *index.html* file in the `build/` folder will need to load up the application.
86 |
87 | 现在在你的命令行运行 `webpack`,然后你的应用会开始编译,一个 `bundle.js` 文件就这样出现在你的 `/build` 文件夹下,需要在 `build/` 下的 *index.html* 去启动项目。
88 |
89 | *build/index.html*
90 |
91 | ```html
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | ```
102 |
103 | > It would be possible to generate this file with Webpack using [html-webpack-plugin](https://www.npmjs.com/package/html-webpack-plugin). You can give it a go if you are feeling adventurous. It is mostly a matter of configuration. Generally this is the way you work with Webpack.
104 |
105 | > 这个文件可以用 [html-webpack-plugin](https://www.npmjs.com/package/html-webpack-plugin) 来生成。如果你觉得冒险,那就把剩下的工具交给它来做。使用它就只有一个配置的问题。一般来说使用 Webpack 来工作就是这么个套路。
106 |
107 | ## 运行应用
108 |
109 | Just double-click the *index.html* file or set up a web server pointing to the `build/` folder.
110 |
111 | 只要双击 *index.html* 或者设置一个 Web 服务指向 `build/` 文件夹。
112 |
113 | ## 设置 `package.json` *scripts*
114 |
115 | It can be useful to run build, serve and such commands through `npm`. That way you don't have to worry about the technology used in the project. You just invoke the commands. This can be achieved easily by setting up a `scripts` section to `package.json`.
116 |
117 | `npm` 是一个非常好用的用来编译的指令,通过 `npm` 你可以不用去担心项目中使用了什么技术,你只要调用这个指令就可以了,只要你在 `package.json` 中设置 `scripts` 的值就可以了。
118 |
119 | In this case we can move the build step behind `npm run build` like this:
120 |
121 | 在这个案例中我们把编译步骤放到 `npm run build` 中是这样:
122 |
123 | 1. `npm i webpack --save` - If you want to install Webpack just a development dependency, you can use `--save-dev`. This is handy if you are developing a library and don't want it to depend on the tool (bad idea!).
124 | 2. Add the following to `package.json`:
125 |
126 |
127 | 1. `npm i webpack --save` - 如果你只是想要作为一个开发依赖安装 Webpack,你可以使用 `--save-dev` 参数。当你开发的项目中不依赖这个工具的时候这个命令是非常便利的。(不是个好主意!)
128 | 2. 把下面的内容添加到 `package.json`中。
129 |
130 | ```json
131 | "scripts": {
132 | "build": "webpack"
133 | }
134 | ```
135 |
136 | To invoke a build, you can hit `npm run build` now.
137 |
138 | 现在你可以输入 `npm run build` 就可以编译了。
139 |
140 | Later on this approach will become more powerful as project complexity grows. You can hide the complexity within `scripts` while keeping the interface simple.
141 |
142 | 当项目越发复杂的时候,这样的方法会变得越来越有效。你可以把所有复杂的操作隐藏在 `scripts` 里面来保证界面的简洁。
143 |
144 | The potential problem with this approach is that it can tie you to a Unix environment in case you use environment specific commands. If so, you may want to consider using something environment agnostic, such as [gulp-webpack](https://www.npmjs.com/package/gulp-webpack).
145 |
146 | 不过潜在的问题是这种方法会导致如果你使用一些特殊的指令的时候只能在 Unix 环境中使用。所以如果你需要考虑一些未知的环境中的话,那么 [gulp-webpack](https://www.npmjs.com/package/gulp-webpack) 会是一个好的解决方案。
147 |
148 | > Note that NPM will find Webpack. `npm run` adds it to the `PATH` temporarily so our simple incantation will work.
149 |
150 | > 注意 NPM 会找到 Webpack,`npm run` 会把他临时加到 `PATH`来让我们这个神奇的命令工作。
151 |
--------------------------------------------------------------------------------
/examples/content/Hot-loading-components.md:
--------------------------------------------------------------------------------
1 | So this part is just freakin' awesome. With React JS and the react-hot-loader you can change the class code of your component and see the instances update live in the DOM, without loosing their state! This is pretty much exactly how CSS updates behave, only that it is your components.
2 |
3 | 所以这个章节就是他妈的屌。使用 React JS 和 react-hot-loader 可以让你去改变组件中的 class 代码,然后可以在 DOM 上看到实时更新了实例,没有修改他们的状态!看起来就像 CSS 更新一样,不过是换成了组件。
4 |
5 | ## 设置
6 | This setup requires that you use the **webpack-dev-server** as introduced in earlier chapters. Now we just have to install the loader with `npm install react-hot-loader --save-dev`, do a small config change:
7 |
8 | 这个设置需要你使用前面章节中介绍的 **webpack-dev-server**,现在我们需要去安装加载器 `npm install react-hot-loader --save-dev`,然后做一点配置:
9 |
10 | ```javascript
11 | var webpack = require('webpack');
12 | var path = require('path');
13 |
14 | var config = {
15 | entry: ['webpack/hot/dev-server', './app/main.js'],
16 | output: {
17 | path: path.resolve(__dirname, './build'),
18 | filename: 'bundle.js'
19 | },
20 | module: {
21 | loaders: [{
22 | test: /\.js$/,
23 |
24 | // Use the property "loaders" instead of "loader" and
25 | // add "react-hot" in front of your existing "jsx" loader
26 | // 使用 "loaders" 属性代替 "loader"
27 | // 然后在 "jsx" 加载器之前添加 "react-hot"
28 | loaders: ['react-hot', 'babel']
29 | }]
30 | }
31 | };
32 |
33 | module.exports = config;
34 | ```
35 |
36 | And you will also need a small snippet of code in your main entry file. In the example above that would be the *main.js* file located in the `app/` folder.
37 |
38 | 同时你也需要在你的主入口文件做一些修改,例子中,在 `app/` 文件夹中的 *main.js* 像下面那样修改:
39 |
40 | *app/main.js*
41 | ```javascript
42 | // You probably already bring in your main root component,
43 | // maybe it is your component using react-router
44 | // 你可能已经把你的根组件引入了
45 | // 组件可能用了 react-router
46 | var RootComponent = require('./RootComponent.jsx');
47 |
48 | // When you render it, assign it to a variable
49 | // 当你渲染它的时候,让它赋值给一个变量
50 | var rootInstance = React.render(RootComponent(), document.body);
51 |
52 | // Then just copy and paste this part at the bottom of
53 | // the file
54 | // 然后在文件的最底部复制粘帖
55 | if (module.hot) {
56 | require('react-hot-loader/Injection').RootInstanceProvider.injectProvider({
57 | getRootInstances: function () {
58 | // Help React Hot Loader figure out the root component instances on the page:
59 | // 帮助 React Hot Loader 识别出页面中的根组件
60 | return [rootInstance];
61 | }
62 | });
63 | }
64 |
65 | ```
66 |
67 | It is that simple. Render a component to the DOM and make a code change on the class of that component. It will render itself again, keeping the existing state. Cool?
68 |
69 | 就是这么简单,在 DOM 中渲染一个组件,然后修改一些组件中的代码,它会自动渲染,却保存了已经存在了的状态,屌不屌?
70 |
71 | Read more about the [react-hot-loader](http://gaearon.github.io/react-hot-loader/getstarted/).
72 |
73 | 可以到 [react-hot-loader](http://gaearon.github.io/react-hot-loader/getstarted/) 了解更多。
--------------------------------------------------------------------------------
/examples/content/Inlining-fonts.md:
--------------------------------------------------------------------------------
1 | Fonts can be really difficult to get right. First of all we have typically 4 different formats, but only one of them will be used by the respective browser. You do not want to inline all 4 formats, as that will just bloat your CSS file and in no way be an optimization.
2 |
3 | 字体实在是非常难引入正确,首先,通常我们有 4 种不一样的格式,但是只有其中一种会被对应的浏览器使用到。你肯定不会想引入全部四种格式,这样只会让 CSS 文件更加膨胀,然后又没办法优化。
4 |
5 | ## 选择一种格式
6 |
7 | Depending on your project you might be able to get away with one font format. If you exclude Opera Mini, all browsers support the .woff and .svg format. The thing is that fonts can look a little bit different in the different formats, on the different browsers. So try out .woff and .svg and choose the one that looks the best in all browsers.
8 |
9 | 取决与你的项目,你可能可以选择出一种字体格式,如果你不考略 Opera Mini,所有的浏览器都支持 .woff 和 .svg 格式。问题是不同格式下在各种浏览器下字体看起来会有一点点不同。所以测试 .woff 和 .svg,然后找出能够在所有浏览器中看起来最好的那个。
10 |
11 | There are probably other strategies here too, so please share by creating an issue or pull request.
12 |
13 | 如果有其他更好的策略,那请通过创建 issue 或者提 PullRequest 来分享。
14 |
15 | ## 实践
16 |
17 |
18 | You do this exactly like you do when inlining images.
19 |
20 | 就像内联图片一样来内联字体。
21 |
22 | ```javascript
23 | var path = require('path');
24 | var config = {
25 | entry: path.resolve(__dirname, 'app/main.js')
26 | output: {
27 | path: path.resolve(__dirname, 'build'),
28 | filename: 'bundle.js'
29 | },
30 | module: {
31 | loaders: [{
32 | test: /\.jsx$/,
33 | loader: 'babel'
34 | }, {
35 | test: /\.woff$/,
36 | loader: 'url?limit=100000'
37 | }]
38 | }
39 | };
40 | ```
41 |
42 | Just make sure you have a limit above the size of the fonts, or they will of course not be inlined.
43 |
--------------------------------------------------------------------------------
/examples/content/Inlining-images.md:
--------------------------------------------------------------------------------
1 | Until HTTP/2 is here you want to avoid setting up too many HTTP requests when your application is loading. Depending on the browser you have a set number of requests that can run in parallel. If you load a lot of images in your CSS it is possible to automatically inline these images as BASE64 strings to lower the number of requests required. This can be based on the size of the image. There is a balance of size of download and number of downloads that you have to figure out for your project, and Webpack makes that balance easy to adjust.
2 |
3 | 直到 HTTP/2 你才能在应用加载的时候避免设置太多 HTTP 请求。根据浏览器不同你必须设置你的并行请求数,如果你在你的 CSS 中加载了太多图片的话,可以自动把这些图片转成 BASE64 字符串然后内联到 CSS 里来降低必要的请求数,这个方法取决与你的图片大小。你需要为你的应用平衡下载的大小和下载的数量,不过 Webpack 可以让这个平衡十分轻松适应。
4 |
5 | ## 安装 url-loader
6 | `npm install url-loader --save-dev` will install the loader that can convert resolved paths as BASE64 strings. As mentioned in other sections of this cookbook Webpack will resolve "url()" statements in your CSS as any other require or import statements. This means that if we test on image file extensions for this loader we can run them through it.
7 |
8 | `npm install url-loader --save-dev` 来安装加载器,它会把需要转换的路径变成 BASE64 字符串,在其他的 Webpack 书中提到的这方面会把你 CSS 中的 “url()” 像其他 require 或者 import 来处理。意味着如果我们可以通过它来处理我们的图片文件。
9 |
10 | ```javascript
11 | var path = require('path');
12 | var config = {
13 | entry: path.resolve(__dirname, 'app/main.js')
14 | output: {
15 | path: path.resolve(__dirname, 'build'),
16 | filename: 'bundle.js'
17 | },
18 | module: {
19 | loaders: [{
20 | test: /\.jsx$/,
21 | loader: 'babel'
22 | }, {
23 | test: /\.(png|jpg)$/,
24 | loader: 'url?limit=25000'
25 | }]
26 | }
27 | };
28 | ```
29 |
30 | The limit is an argument passed to the url-loader. It tells it that images that er 25KB or smaller in size will be converted to a BASE64 string and included in the CSS file where it is defined.
31 |
32 | url-loader 传入的 limit 参数是告诉它图片如果不大于 25KB 的话要自动在它从属的 css 文件中转成 BASE64 字符串。
33 |
34 |
--------------------------------------------------------------------------------
/examples/content/Introduction-to-React-JS.md:
--------------------------------------------------------------------------------
1 | ---
2 | search:
3 | keywords: ['meta', 'react']
4 |
5 | ---
6 |
7 | I remember when I saw React the first time around the time it was announced I was skeptical. Particularly mixing some sort of HTML within your code seemed against good conventions. It just felt like a "bad idea"®.
8 |
9 | 我记得当我第一次看到 React 的时候是十分怀疑的,特别是把 HTML 揉进代码里违背了传统的那些约定,看起来像是一个 “坏主意”。
10 |
11 | But that's what React and similar approaches are doing. They challenge some of the conventions and replace them with something more palatable. Sometimes a bigger change in thinking is needed for you to move forward as a developer. That's what React did for me. It takes some powerful ideas from the world of functional programming and then builds on top of those.
12 |
13 | 但是这就是 React,他们挑战了一些约定,然后用这种方式代替了。作为一个开发者,有时候为了能够改变思考方式是你向前走的一个必经之路。这就是 React 对我的影响,它建立在函数式编程上带给了我很多有意思的想法。
14 |
15 | ## 基础功能
16 |
17 | Before you can understand React and how it changes web development, there are a few things you should know about it. React itself won't be enough. It solves only the problem of views. You still need to complement it with something else. But that's a good thing.
18 |
19 | 在你能理解 React 是如何改变 Web 开发之前,这里有一点东西你需要知道的。React 它本身是不够丰富的,它只能解决一些视图上的问题,你仍然需要一些东西去帮助它完成事情。
20 |
21 | The greatest and worst feature of frameworks is that they sort of cage you in. As long as you are doing what they expect you to do within their boundaries, everything is fine. It is only after you start to reach beyond those boundaries that problems begin to appear. In a library driven approach you aren't as bound. Initially you might not be as fast or efficient but over time as problems become harder, you will have more choices available.
22 |
23 | 最伟大的和最差劲的框架总是企图给你建立一个笼子,当你在他们划定的地盘里能够完成任何需求,一切都是很好的,但是,当你需要跨出边界的时候,开始有问题了,在一个库驱动方法里你是不被限制的,最初你可能是高效地完成需求,但是伴随时间的推进,问题开始变得严峻起来,你需要更多可行的选择。
24 |
25 | ### JSX 的基础
26 |
27 | React provides a component centric approach to frontend development. You will design your application as smaller components, each of which has it own purpose. Taken to the extreme a component may contain its logic, layout and basic styling. To give you an example of JSX:
28 |
29 | React 为前端开发提供了一个组件为中心的方法,你可以为你的应用设计一个更小的组件,所有组件有各自的目的,甚至极端来说,一个组件可能包含它自身的逻辑,结构和基本的样式。这里有个 JSX 的例子:
30 | ```html
31 | ...
32 |
33 | ...
34 | ```
35 |
36 | You can see a couple of basic features of JSX here. Instead of using `class`, we'll use the JavaScript equivalent. In addition we have defined a couple of custom properties in form of `owner` and `task`. `owner` is something that is injected from a variable named `owner` that's within the same scope as our JSX. For `task` we provide a fixed value.
37 |
38 | 你可以看到一个基本功能的 JSX,我们用 `className` 替代了使用 `class`。此外,我们定义了一些自定义属性 `owner` 和 `task`,`owner` 的值是从 JSX 同环境中一个变量叫 `owner` 注入,而我们为 `task` 提供了一个固定的值。
39 |
40 | In practice you would most likely structure this a little differently to fit your data model better. That goes a little beyond basic React, though.
41 |
42 | 在实践中,你可以根据你的数据模型结构来稍微调整目录结构会更好,虽然是 React 进阶的知识点了。
43 |
44 | We can mix normal JavaScript code within those \{\}'s. We can use this idea to render a list of `TodoItem`s like this (ES syntax):
45 |
46 | 我们可以用那些 `{}` 来混合普通 JavaScript 代码,我们可以用这个点像这样去去渲染一个 `TodoItem` 列表(ES 语法):
47 |
48 | ```html
49 | {todoItems.map((todoItem, i) =>
50 |
51 | )}
52 | ```
53 | You probably noticed something special here. What is that `key` property about? It is something that tells React the exact ordering of your items. If you don't provide unique keys for list items like this, React will warn you as it won't be able to guarantee the correct ordering otherwise.
54 |
55 | 你可能注意到这里有些特殊的地方,什么是 `key` 属性?这是告诉 React 这个项的准确顺序。如果你不需要像这样需要提供列表项的唯一 Key 的话,否则 React 会警告你这样它没办法保证是正确的顺序。
56 |
57 | This has to do with the fact that React actually implements something known as Virtual DOM (VDOM for short) on top of actual DOM. It is a subset of DOM that allows React to optimize its rendering. The primary advantage of this approach is that it allows React to eschew a lot of legacy our good old DOM has gained through years. This is the secret to React's high performance.
58 |
59 | 需要了解的事实是 React 实际上在真实 DOM 上实现了虚拟 DOM(简称 VDOM),这是一个 DOM 的子集,能够让 React 能够优化它的渲染。这个优化的方法是它让 React 能够避开困恼我们多年的 DOM 性能损耗。这就是 React 高性能的原因。
60 |
61 | ### 整体组件
62 |
63 | To give you a better idea of what components look like, let's expand our `TodoItem` example into code (ES6 + JSX). I've done this below and will walk you through it:
64 |
65 | 为了能够让你更加清楚组件长什么样子,让我们拓展 `TodoItem` 例子来感受一下(ES6 + JSX),我已经搞完了,然后我们来过一遍看看:
66 |
67 | ```javascript
68 | var React = require('react');
69 |
70 |
71 | module.exports = React.createClass({
72 | getInitialState() {
73 | return {
74 | // 让我们保持追踪看看我们给项点了多少次赞
75 | likes: 0,
76 | };
77 | },
78 | render() {
79 | var owner = this.props.owner;
80 | var task = this.props.task;
81 | var likes = this.state.likes;
82 |
83 | return
84 | {owner}
85 | {task}
86 | {likes}
87 | Like
88 |
;
89 | },
90 | like() {
91 | this.setState({
92 | likes: this.state.likes + 1
93 | });
94 | },
95 | });
96 | ```
97 |
98 | You can see some basic features of a React component above. First we create a class for our component. After that we define some initial state for it, then we render and finally we define some custom callbacks for our handlers if they exist. In this case I decided to implement an extra feature, liking. The current implementation just keeps track of the amount of likes per component.
99 |
100 | 你可以在上面看到一些基础的 React 组件的功能,一开始我们创建了一个组件的类,然后我们在初始化的时候定义一些状态,然后我们渲染,最后我们定制了一些回调。在这个例子中,我决定去实施一个额外的功能,点赞。这个工作只是保持了一个跟踪点赞组件的计数。
101 |
102 | In practice you would transmit like amounts to a backend and add some validation there but this is a good starting point for understanding how state works in React.
103 |
104 | 在实践中,你需要把点赞计数传输给后端,然后添加一些验证,不过目前这个阶段对于理解 State 在 React 中的是如何使用的已经是一个非常好的开端了。
105 |
106 | `getInitialState` and `render` are a part of a [React component's lifecycle as documented officially](http://facebook.github.io/react/docs/component-specs.html). There are additional hooks that allow you to do things like set up adapters for `jQuery` plugins and such.
107 |
108 | `getInitialState` 和 `render` 是 [React 组件的生命周期官方文档](http://facebook.github.io/react/docs/component-specs.html) 的一部分。也有额外的能够让你去设置加载 `jQuery` 插件之类的适配器的钩子。
109 |
110 | In this example CSS naming has been modeled after [Suit CSS](http://suitcss.github.io/) conventions as those look clean to me. That's just one way to deal with it.
111 |
112 | 在例子中的 CSS 的命名是根据 [Suit CSS](http://suitcss.github.io/) 约定处理后的,这样对我来说看起来非常干净,这只是一种解决方案而已。
113 |
114 | ### 处理操作
115 |
116 | Let's say we want to modify the owner of our TodoItems. For the sake of simplicity let's expect it's just a string and owner is the same for all TodoItems. Based on this design it would make sense to have an input for owner at our user interface. A naive implementation would look something like this:
117 |
118 | 让我们来开始修改我们的 TodoItems 的 owner,为了简化这个目的,我们假设 owner 只是一个字符串而且只有一个,基于这个设计,在用户界面里增加一个输入框给用户来修改用户名,改动是这样的:
119 |
120 | ```javascript
121 | var React = require('react');
122 | var TodoItem = require('./TodoItem.jsx');
123 |
124 |
125 | module.exports = React.createClass({
126 | getInitialState() {
127 | return {
128 | todoItems: [
129 | {
130 | task: 'Learn React',
131 | },
132 | {
133 | task: 'Learn Webpack',
134 | },
135 | {
136 | task: 'Conquer World',
137 | }
138 | ],
139 | owner: 'John Doe',
140 | };
141 | },
142 |
143 | render() {
144 | var todoItems = this.state.todoItems;
145 | var owner = this.state.owner;
146 |
147 | return
148 |
149 |
150 |
151 |
152 |
153 |
{todoItems.map((todoItem, i) =>
154 |
155 |
156 |
157 | )}
158 |
159 |
;
160 | },
161 |
162 | updateOwner() {
163 | this.setState({
164 | owner: e.target.value,
165 | });
166 | },
167 | });
168 | ```
169 |
170 | We could push `TodoItems` and `ChangeOwner` to separate components but I've kept it all in the same for now. Given React has one way binding by default, we get some extra noise compared to some other setups. React provides [ReactLink](http://facebook.github.io/react/docs/two-way-binding-helpers.html) helper to help deal with this particular case.
171 |
172 | 我们可以把 `TodoItems` 和 `ChangeOwner` 分离出去,但是我暂时不这么做了。React 默认提供了单向数据绑定,我们可以通过设置来调整,React 提供了 [ReactLink](http://facebook.github.io/react/docs/two-way-binding-helpers.html) 来提供双向数据绑定。
173 |
174 | Even though lack of two way binding might sound like a downer, it actually isn't that bad a thing. It makes it easier to reason about the system. You simply have to follow the flow. This idea is highlighted in the Flux architecture. The easiest way to visualize it is to think up an infinite waterfall or a snake eating its tail. That's how the flow in the world of React generally works. Compared to this two way binding feels more chaotic.
175 |
176 | 尽管双向数据绑定的缺失听起来让人沮丧,但实际上并不是一件坏事,它能够让系统更加轻松的运行,你可能需要跟踪数据流。不过 FB 提出了 Flux 架构,最简单的方式去想出一个无限瀑布流,或者贪吃蛇,就是 React 的世界在做的这个数据流的事情,对比这两种绑定方式让人感觉更加迷茫。
177 |
178 | ### 使用一个Mixin
179 |
180 | If we wanted to model the code above using a ReactLink, we would end up with something like this:
181 |
182 | 如果我们想使用 ReactLink的话,就像下面这样:
183 |
184 | ```javascript
185 | // ReactLink 是一个插件,所以我们需要把它引入。
186 | var React = require('react/addons');
187 |
188 | ...
189 |
190 | module.exports = React.createClass({
191 | mixins: [React.addons.LinkedStateMixin],
192 |
193 | ...
194 |
195 | render() {
196 | var todoItems = this.state.todoItems;
197 |
198 | return
199 |
200 |
201 |
202 |
203 |
204 |
{todoItems.map((todoItem, i) =>
205 |
206 |
207 |
208 | )}
209 |
210 |
;
211 | },
212 | });
213 | ```
214 |
215 | Now we can skip that `onChange` handler. That `React.addons.LinkedStateMixin` encapsulates the logic. [Mixins](http://facebook.github.io/react/docs/reusable-components.html#mixins) provide us one way to encapsulate shared concerns such as this into something which can be reused easily.
216 |
217 | 现在我们可以跳过绑定 `onChange` 事件了,`React.addons.LinkedStateMixin` 封装了逻辑。[Mixins](http://facebook.github.io/react/docs/reusable-components.html#mixins) 给我们提供了一种可以重复使用的封装方法。
218 |
219 | > It would be easy to start expanding the example now. You could for instance provide means to manipulate the contents of the Todo list or start extracting various parts into components of their own. It is up to you to make the app yours. If you are still feeling a bit lost, please read on. This is supposed to be a brief introduction to the topic!
220 |
221 | > 现在拓展例子已经非常容易了,你现在应该就可以拓展 Todo 列表,或者把各种组件分离,这取决于你。如果你现在还是觉得不够掌握,那么继续阅读,这节只是话题的一个介绍。
222 |
223 | ### 测试
224 |
225 | If you get serious about the Todo app, I recommend trying [Jest](https://facebook.github.io/jest/) out. Getting the initial test run might be a bit challenging but after you learn the basics of the API, it gets a lot simpler. The basic idea is that you instantiate a component with some properties and then query DOM using Jest and finally assert that the values in the UI are what you expect.
226 |
227 | 如果你觉得这个 Todo 应用需要测试,那么我推荐 [Jest](https://facebook.github.io/jest/),刚开始写测试用例可能是一点挑战但是在你学习一些基础的 API 之后,它会变得更加简单,最基本的是你实例化一个带有一些属性的组件的时候,然后用 Jest 查询 DOM,最后断言界面中的值是你期望的值。
228 |
229 | When you go beyond component level, that is where tools such as Selenium come in. You can use standard end to end testing tools on a higher level.
230 |
231 | 当你站在组件层级之上时,就有了比如类似 Selenium 的组件,你可以在更高层级使用标准的端对端测试工具。
232 |
233 | ## Flux 架构及其变种
234 |
235 | As you saw above, it is quite simple to throw together a couple of components and start building an app. You can get quite far with `props` and `state`. Just load up some data over AJAX at `getInitialState` and pass it around. After a while this all might start feeling a bit unwieldy. Why, for instance, my components should have to know something about how to communicate with the backend?
236 |
237 | 就像你看到的,把一些组件放到一起就可以组成一个应用,你可以用 `props` 和 `state` 做的更多,或者在 `getInitialState` 中使用 AJAX 加载数据然后传给其他组件。这些使用一段时间之后可能会觉得有些笨拙,为什么?实践中,组件们需要知道如何和后端通讯。
238 |
239 | This is where Flux architecture and its variants come in. I will start by describing [Reflux](https://github.com/spoike/refluxjs), a simplified variant of it. You can then work up to [understanding Flux](http://facebook.github.io/flux/docs/overview.html) in fuller detail once you understand this simplified setup.
240 |
241 | 所以出现了 Flux 架构和它的一些变种,我会介绍 [Reflux](https://github.com/spoike/refluxjs) 一种非常简单的 Flux 变种,你可以阅读这个 [understanding Flux](http://facebook.github.io/flux/docs/overview.html) 来全面了解 Flux。
242 |
243 | In addition to View Components which we just discussed, Reflux introduces the concepts of Actions and Stores. The flow goes like this: Components -> Actions -> Stores -> Components. Ie. you could have some control in a Component which then triggers some Action which then performs some operation (say PUT) and updates Store state. This state change is then propagated to Components listening to the Store.
244 |
245 | 并且,Reflux 介绍了一种 Actions 和 Stores 的概念去组成刚才我们讨论的视图组件。整个数据流是这样的:组件 -> Actions -> Stores -> 组件。这样你可以在一个组件中控制触发一些 Action 然后执行一些操作(比如 PUT)然后更新 Store 的状态,状态的更新传播给监听 Store 的那些组件们。
246 |
247 | In case of our Todo example we would define basic `TodoActions` like create, update, delete and such. We would also have a `TodoStore`. It would maintain a data structure of a `TodoList`. Our components would then consume that data and display it as appropriate.
248 |
249 | 在我们的这个 Todo 例子中,我们定义了一个基础的 `TodoActions` 比如创建、更新、删除之类的,我们也有个 `TodoStore`,它是整个 `TodoList` 的数据结构中心,组件们会读取那里的数据,然后适当得展现出来。
250 |
251 | As development of Reflux is quite in flux I won't give you a full example in this case. I just wanted to illustrate one possible way to deal with scaling up from bare React. You should explore various options and deepen your understanding of possible architectures. The ideas are quite similar but the devil is in the details as always. There are always drawbacks to consider.
252 |
253 | Reflux 的开发和 Flux 差不多,我就不在这里详细讲述了,我只是想说明如何处理从纯 React 扩大的一种可能的方式。你需要去浏览一些相关看法,然后深入理解那些架构。那些想法都差不多,就是细节不太一样,都有各自的一些缺点有待考虑。
254 |
255 | ### 同构渲染
256 |
257 | One of the big features which React provides thanks to its design is so called isomorphic rendering. Back in the day we used to render whole HTML in the backend and provide just that for the client to render. Then we would sprinkle a little JavaScript magic to make things more interactive and so on. After a while the pendulum swung to frontend side. We served minimal amount of HTML to the client and constructed the rest, including routing, using JavaScript entirely on frontend.
258 |
259 | React 设计了一种叫做两端渲染的重要功能。过去我们在后端渲染整个 HTML,然后交给客户端去渲染,然后我们加上一点点 JavaScript 做的交互。再后来,这个活交给浏览器做去,后端返回最小的 HTML 给客户端,然后在客户端构建了一整套用 JavaScript 全权控制的系统,包括路由。
260 |
261 | The main problems with frontend driven rendering have to do with performance, high dependency on JavaScript (think of the noscript folk!) and poor SEO. With isomorphic rendering you can mitigate these problems effectively. React allows you to prerender HTML at backend side. You can also hydrate some stores with pre-existing data making it possible to skip certain data queries altogether initially! Even web crawlers will be happy as they get some HTML to scrape.
262 |
263 | 前端驱动渲染的主要问题是性能问题、 JavaScript 的高度依赖(设想那些不能运行 JavaScript 的情况)和 SEO 问题。使用两端渲染,你可以轻松解决这些问题。React 允许你在服务器端预渲染 HTML,你也可以在服务器端预先存储一些数据来跳过初始化的一些数据查询。甚至一些网络爬虫能够轻松地获取到一些 HTML 内容。
264 |
265 | This is still partly uncharted territory. Various implementations of Flux still struggle with the concept. I have no doubt we will see stronger solutions in the future, however, as people learn to deal with isomorphism better. That said isomorphic rendering can be considered a nice extra capability to have but it definitely isn't something that's just must have. There are some ways to work around certain issues, such as poor SEO, even without it. It just depends on where you want to put the effort.
266 |
267 |
268 | 这一部分仍然是一个未知的领域(译者注:原文发布于2015年4月),很多 Flux 的实现在这个概念上还没同意,但是毋庸置疑,我们在未来能够看到更加完善的解决方案,无论如何,大家会认识到两端渲染的好处。虽然两端渲染听起来是一个非常好的解决方案,但是它不是必要的。现在已经有很多能够解决这些问题的方案,比如 SEO 的问题,甚至没有用这种解决方案,它只是依赖于你想要如何付出努力。
269 |
--------------------------------------------------------------------------------
/examples/content/Introduction-to-Webpack.md:
--------------------------------------------------------------------------------
1 | ---
2 | search:
3 | keywords: ['webpack', 'meta']
4 |
5 | ---
6 |
7 | In web development we deal with a lot of small technical artifacts. You use HTML to describe page structure, CSS how to style it and JavaScript for logic. Or you can replace HTML with something like Jade, CSS with Sass or LESS, JavaScript with CoffeeScript, TypeScript and the ilk. In addition you have to deal with project dependencies (ie. external libraries and such).
8 |
9 | 在 Web 开发历程上,我们构建了很多小型的技术解决方案,比如用 HTML 去描述页面结构,CSS 去描述页面样式,JavaScript 去描述页面逻辑,或者你也可以用一些比如 Jade 去取代 HTML,用 Sass 或 Less 去取代CSS,用 CoffeeScript 或者 TypeScript 之类的去取代 JavaScript,不过项目中的依赖可能是一件比较烦恼的事情。(需要安装额外很多的库)
10 |
11 | There are good reasons why we use these various technologies. Regardless of what we use, however, we still want to end up with something that can be run on the browsers of the clients. This is where build systems come in. Historically speaking there have been many. [Make](https://en.wikipedia.org/wiki/Make_%28software%29) is perhaps the most known one and still a viable option in many cases. In the world of frontend development particularly [Grunt](http://gruntjs.com/) and [Gulp](http://gulpjs.com/) have gained popularity. Both are made powerful by plugins. [NPM](https://www.npmjs.com/), the Node.js package manager, is full of those.
12 |
13 | 这里有很多为什么我们需要尝试那些新技术的理由。不管我们用什么,总之,我们还是希望使用那些能够处理在浏览器端的方案,所以出来了编译方案。历史上已经有很多分享了,比如 [Make](https://en.wikipedia.org/wiki/Make_%28software%29) 可能是很多解决方案中最知名且是可行的方案。[Grunt](http://gruntjs.com/) 和 [Gulp](http://gulpjs.com/) 是在是前端的世界中最流行的解决方案,他们两个都有很多非常有用的插件。[NPM](https://www.npmjs.com/)(Node.js 的包管理器)则包含了他们两个。
14 |
15 | ## Grunt
16 |
17 | Grunt is the older project. It relies on plugin specific configuration. This is fine up to a point but believe me, you don't want to end up having to maintain a 300 line `Gruntfile`. The approach simply turns against itself at some point. Just in case you are curious what the configuration looks like, here's an example from [Grunt documentation](http://gruntjs.com/sample-gruntfile):
18 |
19 | Grunt 是相比后面几个更早的项目,他依赖于各种插件的配置。这是一个很好的解决方案,但是请相信我,你不会想看到一个 300 行的 `Gruntfile`。如果你好奇 Grunt 的配置会如何,那么这里是有个从 [Grunt 文档](http://gruntjs.com/sample-gruntfile) 的例子:
20 |
21 | ```javascript
22 | module.exports = function(grunt) {
23 |
24 | grunt.initConfig({
25 | jshint: {
26 | files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
27 | options: {
28 | globals: {
29 | jQuery: true
30 | }
31 | }
32 | },
33 | watch: {
34 | files: ['<%= jshint.files %>'],
35 | tasks: ['jshint']
36 | }
37 | });
38 |
39 | grunt.loadNpmTasks('grunt-contrib-jshint');
40 | grunt.loadNpmTasks('grunt-contrib-watch');
41 |
42 | grunt.registerTask('default', ['jshint']);
43 |
44 | };
45 | ```
46 |
47 | ## Gulp
48 |
49 | Gulp takes a different approach. Instead of relying on configuration per plugin you deal with actual code. Gulp builds on top of the tried and true concept of piping. If you are familiar with Unix, it's the same here. You simply have sources, filters and sinks. In this case sources happen to match to some files, filters perform some operations on those (ie. convert to JavaScript) and then output to sinks (your build directory etc.). Here's a sample `Gulpfile` to give you a better idea of the approach taken from the project README and abbreviated a bit:
50 |
51 | Gulp 提供了一个不一样的解决方案,而不是依赖于各种插件的配置。Gulp 使用了一个文件流的概念。如果你熟悉 Unix,那么 Gulp 对你来说会差不多,Gulp 会提供你一些简单化的操作。在这个解决方案中,是去匹配一些文件然后操作(就是说和 JavaScript 相反)然后输出结果(比如输出在你设置的编译路径等)。这里有一个简单的 `Gulpfile` 的例子:
52 |
53 |
54 | ```javascript
55 | var gulp = require('gulp');
56 | var coffee = require('gulp-coffee');
57 | var concat = require('gulp-concat');
58 | var uglify = require('gulp-uglify');
59 | var sourcemaps = require('gulp-sourcemaps');
60 | var del = require('del');
61 |
62 | var paths = {
63 | scripts: ['client/js/**/*.coffee', '!client/external/**/*.coffee'],
64 | };
65 |
66 | // 不是所有的任务需要使用 streams
67 | // 一个 gulpfile 只是另一个node的程序,所以你可以使用所有 npm 的包
68 | gulp.task('clean', function(cb) {
69 | // 你可以用 `gulp.src` 来使用多重通配符模式
70 | del(['build'], cb);
71 | });
72 |
73 | gulp.task('scripts', ['clean'], function() {
74 | // 压缩和复制所有 JavaScript (除了第三方库)
75 | // 加上 sourcemaps
76 | return gulp.src(paths.scripts)
77 | .pipe(sourcemaps.init())
78 | .pipe(coffee())
79 | .pipe(uglify())
80 | .pipe(concat('all.min.js'))
81 | .pipe(sourcemaps.write())
82 | .pipe(gulp.dest('build/js'));
83 | });
84 |
85 | // 监听文件修改
86 | gulp.task('watch', function() {
87 | gulp.watch(paths.scripts, ['scripts']);
88 | });
89 |
90 | // 默认任务(就是你在命令行输入 `gulp` 时运行)
91 | gulp.task('default', ['watch', 'scripts']);
92 | ```
93 |
94 | Given the configuration is code you can always just hack it if you run into troubles. You can wrap existing Node.js modules as Gulp plugins and so on. You still end up writing a lot of boilerplate for casual tasks, though.
95 |
96 | 这些配置都是代码,所以当你遇到问题也可以修改,你也可以使用已经存在的 Gulp 插件,但是你还是需要写一堆模板任务。
97 |
98 | ## Browserify
99 |
100 | Dealing with JavaScript modules has always been a bit of a problem given the language actually doesn't have a concept of module till ES6. Ergo we are stuck with the 90s when it comes to browser environment. Various solutions, including [AMD](http://browserify.org/), have been proposed. In practice it can be useful just to use CommonJS, the Node.js format, and let tooling deal with the rest. The advantage is that you can often hook into NPM and avoid reinventing the wheel.
101 |
102 | 处理 JavaScript 模块一直是一个大问题,因为这个语言在 ES6 之前没有这方面的概念。因此我们还是停留在90年代,各种解决方案,比如提出了 [AMD](http://browserify.org/)。在实践中只使用 CommonJS ( Node.js 所采用的格式)会比较有帮助,而让工具去处理剩下的事情。它的优势是你可以发布到 NPM 上来避免重新发明轮子。
103 |
104 | [Browserify](http://browserify.org/) solves this problem. It provides a way to bundle CommonJS modules together. You can hook it up with Gulp. In addition there are tons of smaller transformation tools that allow you to move beyond the basic usage (ie. [watchify](https://www.npmjs.com/package/watchify) provides a file watcher that creates bundles for you during development automatically). This will save some effort and no doubt is a good solution up to a point.
105 |
106 | [Browserify](http://browserify.org/) 解决了这个问题,它提供了一种可以把模块集合到一起的方式。你可以用 Gulp 调用它,此外有很多转换小工具可以让你更兼容的使用(比如 [watchify](https://www.npmjs.com/package/watchify) 提供了一个文件监视器帮助你在开发过程中更加自动化地把文件合并起来),这样会省下很多精力。毋庸置疑,一定程度来讲,这是一个很好的解决方案。
107 |
108 |
109 | ## Webpack
110 |
111 | Webpack expands on the idea of hooking into CommonJS `require`. What if you could just `require` whatever you needed in your code, be it CoffeeScript, Sass, Markdown or something? Well, Webpack does just this. It takes your dependencies, puts them through loaders and outputs browser compatible static assets. All of this is based on configuration. Here is a sample configuration from [the official Webpack tutorial](http://webpack.github.io/docs/tutorials/getting-started/):
112 |
113 | Webpack 扩展了 CommonJs 的 `require` 的想法,比如你想在 CoffeeScript、Sass、Markdown 或者其他什么代码中 `require` 你想要的任何代码的话?那么 Webpack 正是做这方面的工作。它会通过配置来取出代码中的依赖,然后把他们通过加载器把代码兼容地输出到静态资源中。这里是一个 [Webpack 官网](http://webpack.github.io/docs/tutorials/getting-started/) 上的例子:
114 |
115 | ```javascript
116 | module.exports = {
117 | entry: "./entry.js",
118 | output: {
119 | path: __dirname,
120 | filename: "bundle.js"
121 | },
122 | module: {
123 | loaders: [
124 | { test: /\.css$/, loader: "style!css" }
125 | ]
126 | }
127 | };
128 | ```
129 |
130 | In the following sections we'll build on top of this idea and show how powerful it is. You can, and probably should, use Webpack with some other tools. It won't solve everything. It does solve the difficult problem of bundling, however, and that's one worry less during development.
131 |
132 | 在接下来的章节中我们会使用 Webpack 来构建项目来展示它的能力。你可以用其他工具和 Webpack 一起使用。它不会解决所有事情,只是解决一个打包的难题,无论如何,这是在开发过程中需要解决的问题。
--------------------------------------------------------------------------------
/examples/content/Isomorphic-app.md:
--------------------------------------------------------------------------------
1 | So the great thing about React JS is that it runs on the server too. But that does not mean you can just create any app and run it on the server. You have to make some decisions on the architecture. The reason is that even though React JS and the components run on the server, you might be having dependencies in those components that does not run on the server.
2 |
3 | React Js 最伟大的地方是它也可以运行在服务端,不过这不意味着你可以创建任何一个应用然后运行在服务端,你需要做一些决策和架构。原因是哪怕 React JS 和一些组件可以在服务端运行,但还是有一些组件中的依赖不能在服务端运行。
4 |
5 | ## 注入状态
6 | One of the most important decisions you make is to inject the state of your application through the top component. This basically means that your components does not have any external dependencies at all. All they need to know comes through this injected state.
7 |
8 | 一个重要的事情是应用需要通过顶层组件把状态注入,这意味着你的组件没有了任何的外部依赖,他们只能通过注入的状态来获取信息。
9 |
10 | This cookbook is not about isomorphic apps, but let us take a look at an example. We will not use ES6 syntax here because Node JS does not support it yet.
11 |
12 | 这本小书不是主要讲同构渲染的应用,不过让我们来看一下例子,我们这次不使用 ES6 语法了,因为 Node JS 还不完全支持。
13 |
14 | *main.js (client)*
15 | ```javascript
16 | var React = require('react');
17 | var AppState = require('./client/AppState.js');
18 | var App = require('./App.js');
19 |
20 | React.render(, document.body);
21 | ```
22 |
23 | *router.js (server)*
24 | ```javascript
25 | var React = require('react');
26 | var App = require('./App.js');
27 | var AppState = require('./server/AppState.js');
28 | var index = '{{component}}';
29 |
30 | app.get('/', function (req, res) {
31 | var componentHtml = React.renderToString(App({state: AppState}));
32 | var html = index.replace('{{component}}', componentHtml);
33 | res.type('html');
34 | res.send(html);
35 | });
36 | ```
37 |
38 | So this was a very naive and simple way of showing it, but what you should notice here is that we use the same **App.js** file on the client and server, but we have two different ways of producing the state.
39 |
40 | 所以这是一个非常初级且简单的例子来展示它,不过你需要注意的是我们在客户端和服务端使用了同一个 **App.js**,但是我们需要两种方式来提供状态。
--------------------------------------------------------------------------------
/examples/content/Javascript-next.md:
--------------------------------------------------------------------------------
1 | ## 类
2 |
3 | As of React JS 0.13 you will be able to define components as classes.
4 |
5 | 在 React JS 0.13 中,你可以把组件定义为类。
6 |
7 | ```javascript
8 | class MyComponent extends React.Component {
9 | constructor() {
10 | this.state = {message: 'Hello world'};
11 | }
12 | render() {
13 | return (
14 | {this.state.message}
15 | );
16 | }
17 | }
18 | ```
19 |
20 | This gives you a very short and nice syntax for defining components. A drawback with using classes though is the lack of mixins. That said, you are not totally lost. Lets us see how we could still use the important **PureRenderMixin**.
21 |
22 | 这样能够写出非常短且优雅的语法来定义组件。使用类的缺点是缺乏了很多 mixin,不过,不是所有的不能用,让我们来看看使用重要的 **PureRenderMixin**:
23 |
24 | ```javascript
25 | import React from 'react/addons';
26 |
27 | class Component extends React.Component {
28 | shouldComponentUpdate() {
29 | return React.addons.PureRenderMixin.shouldComponentUpdate.apply(this, arguments);
30 | }
31 | }
32 |
33 | class MyComponent extends Component {
34 | constructor() {
35 | this.state = {message: 'Hello world'};
36 | }
37 | render() {
38 | return (
39 | {this.state.message}
40 | );
41 | }
42 | }
43 | ```
--------------------------------------------------------------------------------
/examples/content/Lazy-loaded-entry-points.md:
--------------------------------------------------------------------------------
1 | It is also possible to lazy load entry points. This means that you load parts of your application as they are requested. A typical scenario for this would be that your users only visits specific parts of the application. And an example of that would be twitter.com. You do not always visit your profile page, so why load the code for that? Here is a summary of requirements:
2 |
3 | Webpack 也可以实现懒加载入口文件,意味着应用的一部分只在需要的时候加载,一个典型的例子是用户只有访问一些应用特定的部分,典型的例子是 Twitter.com,你不会一直访问你的个人页,所以为什么要加载那部分的代码?这里有个主要的要求:
4 |
5 | - You have a relatively big application where users can visit different parts of it
6 | - You do care a lot about initial render time
7 |
8 |
9 | - 你有一个相对比较大的应用,可以让用户可以访问应用的不同部分。
10 | - 你非常关注初始渲染时间
11 |
12 |
13 | *webpack.production.config.js*
14 | ```javascript
15 | var path = require('path');
16 | var webpack = require('webpack');
17 | var node_modules_dir = path.resolve(__dirname, 'node_modules');
18 |
19 | var config = {
20 | entry: {
21 | app: path.resolve(__dirname, 'app/main.js'),
22 | vendors: ['react']
23 | },
24 | output: {
25 | path: path.resolve(__dirname, 'dist'),
26 | filename: 'app.js'
27 | },
28 | module: {
29 | loaders: [{
30 | test: /\.js$/,
31 | exclude: [node_modules_dir],
32 | loader: 'babel'
33 | }]
34 | },
35 | plugins: [
36 | new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js')
37 | ]
38 | };
39 |
40 | module.exports = config;
41 | ```
42 | So we are pretty much back where we started with a split application and vendors bundle. You do not really define your lazy dependencies in a configuration, Webpack automatically understands them when analyzing your code. So let us see how we would lazy load a **profile page**:
43 |
44 | 所以我们把应用和第三方分离是一件非常漂亮的事,你不需要在配置中设置懒加载依赖,Webpack 会自动理解他们,然后分析你的代码。所以让我们看看我们是如何加载一个 **个人信息页**:
45 |
46 | *main.js (使用 ES6 语法)*
47 | ```javascript
48 | import React from 'react';
49 | import Feed from './Feed.js';
50 |
51 | class App extends React.Component {
52 | constructor() {
53 | this.state = { currentComponent: Feed };
54 | }
55 | openProfile() {
56 | require.ensure([], () => {
57 | var Profile = require('./Profile.js');
58 | this.setState({
59 | currentComponent: Profile
60 | });
61 | });
62 | }
63 | render() {
64 | return (
65 | return {this.state.currentComponent()}
66 | );
67 | }
68 | }
69 | React.render( , document.body);
70 | ```
71 | So this is just an example. You would probably hook this up to a router, but the important part is using `require.ensure`.
72 |
73 | 这只是一个例子,你需要把这些写入到一个路由中,不过重要的事情是使用了 `require.ensure`。
74 |
75 | **What is the array on the first argument?**: If you try to lazy load a chunk that depends on an other lazy loaded chunk you can set it as a dependency in the array. Just type in the path to the chunk. E.g. `['./FunnyButton.js']`
76 |
77 | **第一个数组参数是什么?**:如果你尝试去懒加载一段由另一个懒加载的代码加载的代码的话,把它作为依赖写在数组里,就把路径写进去,比如 `['./FunnyButton.js']`
78 |
--------------------------------------------------------------------------------
/examples/content/Loading-CSS.md:
--------------------------------------------------------------------------------
1 | Webpack allows you to load CSS like you load any other code. What strategy you choose is up to you, but you can do everything from loading all your css in the main entry point file to one css file for each component.
2 |
3 | Webpack允许像加载任何代码一样加载 CSS。你可以选择你所需要的方式,但是你可以为每个组件把所有你的 CSS 加载到入口主文件中来做任何事情。
4 |
5 | Loading CSS requires the **css-loader** and the **style-loader**. They have two different jobs. The **css-loader** will go through the CSS file and find `url()` expressions and resolve them. The **style-loader** will insert the raw css into a style tag on your page.
6 |
7 | 加载 CSS 需要 **css-loader** 和 **style-loader**,他们做两件不同的事情,**css-loader**会遍历 CSS 文件,然后找到 `url()` 表达式然后处理他们,**style-loader** 会把原来的 CSS 代码插入页面中的一个 style 标签中。
8 |
9 | ## 准备加载 CSS
10 |
11 |
12 | Install the two loaders: `npm install css-loader style-loader --save-dev`.
13 |
14 | 安装这两个加载器:`npm install css-loader style-loader --save-dev`
15 |
16 | In the *webpack.config.js* file you can add the following loader configuration:
17 |
18 | 你可以把下面的加载器配置加到 *Webpack.config.js* 文件中。
19 |
20 | **webpack.config.js**
21 |
22 |
23 | ```javascript
24 | var path = require('path');
25 | var config = {
26 | entry: path.resolve(__dirname, 'app/main.js')
27 | output: {
28 | path: path.resolve(__dirname, 'build'),
29 | filename: 'bundle.js'
30 | },
31 | module: {
32 | loaders: [{
33 | test: /\.jsx$/,
34 | loader: 'babel'
35 | }, {
36 | test: /\.css$/, // Only .css files
37 | loader: 'style!css' // Run both loaders
38 | }]
39 | }
40 | };
41 |
42 | module.exports = config;
43 | ```
44 |
45 | ## 加载 CSS 文件
46 |
47 | Loading a CSS file is a simple as loading any file:
48 |
49 | 加载一个 CSS 文件就和加载其他文件一样简单:
50 |
51 |
52 | **main.js**
53 |
54 | ```javascript
55 | import './main.css';
56 | // Other code
57 | ```
58 |
59 | **Component.jsx**
60 |
61 | ```javascript
62 | import './Component.css';
63 | import React from 'react';
64 |
65 | export default React.createClass({
66 | render: function () {
67 | return Hello world!
68 | }
69 | });
70 | ```
71 |
72 | **Note!** You can of course do this with both CommonJS and AMD.
73 |
74 | **注意!** 你也可以在 CommonJS 和 AMD 中做同样的事情。
75 |
76 | ## CSS 加载策略
77 |
78 | Depending on your application you might consider three main strategies. In addition to this you should consider including some of your basic CSS inlined with the initial payload (index.html). This will set the structure and maybe a loader while the rest of your application is downloading and executing.
79 |
80 | 根据你的应用,你可能会考略三种策略。另外,你需要考虑把一些基础的 CSS 内联到初始容器中(index.html),这样设置的结构能够在应用下载和执行的时候加载剩下的应用。
81 |
82 | ### 所有合并成一个
83 |
84 | In your main entry point, e.g. `app/main.js` you can load up your entire CSS for the whole project:
85 |
86 | 在你的主入口文件中个,比如 `app/main.js` 你可以为整个项目加载所有的 CSS:
87 |
88 |
89 | **app/main.js**
90 |
91 |
92 | ```javascript
93 | import './project-styles.css';
94 | // 其他 JS 代码
95 | ```
96 |
97 | The CSS is included in the application bundle and does not need to download.
98 |
99 |
100 | CSS 就完全包含在合并的应用中,再也不需要重新下载。
101 |
102 |
103 | ### 懒加载
104 |
105 | If you take advantage of lazy loading by having multiple entry points to your application, you can include specific CSS for each of those entry points:
106 |
107 | 如果你想发挥应用中多重入口文件的优势,你可以在每个入口点包含各自的 CSS:
108 |
109 |
110 | **app/main.js**
111 |
112 | ```javascript
113 | import './style.css';
114 | // 其他 JS 代码
115 | ```
116 |
117 | **app/entryA/main.js**
118 |
119 | ```javascript
120 | import './style.css';
121 | // 其他 JS 代码
122 | ```
123 |
124 | **app/entryB/main.js**
125 |
126 | ```javascript
127 | import './style.css';
128 | // 其他 JS 代码
129 | ```
130 |
131 | You divide your modules by folders and include both CSS and JavaScript files in those folders. Again, the imported CSS is included in each entry bundle when running in production.
132 |
133 | 你把你的模块用文件夹分离,每个文件夹有各自的 CSS 和 JavaScript 文件。再次,当应用发布的时候,导入的 CSS 已经加载到每个入口文件中。
134 |
135 | ### 制定的组件
136 |
137 | With this strategy you create a CSS file for each component. It is common to namespace the CSS classes with the component name, thus avoiding some class of one component interfering with the class of an other.
138 |
139 | 你可以根据这个策略为每个组件创建 CSS 文件,可以让组件名和 CSS 中的 class 使用一个命名空间,来避免一个组件中的一些 class 干扰到另外一些组件的 class。
140 |
141 |
142 | **app/components/MyComponent.css**
143 |
144 | ```css
145 | .MyComponent-wrapper {
146 | background-color: #EEE;
147 | }
148 | ```
149 |
150 | **app/components/MyComponent.jsx**
151 |
152 | ```
153 | import './MyComponent.css';
154 | import React from 'react';
155 |
156 | export default React.createClass({
157 | render: function () {
158 | return (
159 |
160 |
Hello world
161 |
162 | )
163 | }
164 | });
165 | ```
166 |
167 | ## 使用内联样式取代 CSS 文件
168 |
169 | With "React Native" you do not use stylesheets at all, you only use the *style-attribute*. By defining your CSS as objects. Depending on your project, you might consider this as your CSS strategy.
170 |
171 | 在 “React Native” 中你不再需要使用任何 CSS 文件,你只需要使用 *style 属性*,可以把你的 CSS 定义成一个对象,那样就可以根据你的项目重新来考略你的 CSS 策略。
172 |
173 |
174 | **app/components/MyComponent.jsx**
175 |
176 |
177 | ```javascript
178 | import React from 'react';
179 |
180 | var style = {
181 | backgroundColor: '#EEE'
182 | };
183 |
184 | export default React.createClass({
185 | render: function () {
186 | return (
187 |
188 |
Hello world
189 |
190 | )
191 | }
192 | });
193 | ```
194 |
--------------------------------------------------------------------------------
/examples/content/Loading-LESS-or-SASS.md:
--------------------------------------------------------------------------------
1 | If you want to use compiled CSS, there are two loaders available for you. The **less-loader** and the **sass-loader**. Depending on your preference, this is how you set it up.
2 |
3 | 如果你想使用编译 CSS,这里有两种可用的加载器:**less-loader** 和 **sass-loader**,看你喜欢哪种。下面是如何设置。
4 |
5 | ## 安装和设置加载器
6 | `npm install less-loader` or `npm install sass-loader`.
7 |
8 | `npm install less-loader` 或者 `npm install sass-loader`.
9 |
10 |
11 | **webpack.config.js**
12 |
13 |
14 | ```javascript
15 | var path = require('path');
16 | var config = {
17 | entry: path.resolve(__dirname, 'app/main.js')
18 | output: {
19 | path: path.resolve(__dirname, 'build'),
20 | filename: 'bundle.js'
21 | },
22 | module: {
23 | loaders: [{
24 | test: /\.jsx$/,
25 | loader: 'babel'
26 | },
27 |
28 | // LESS
29 | {
30 | test: /\.less$/,
31 | loader: 'style!css!less'
32 | },
33 |
34 | // SASS
35 | {
36 | test: /\.scss$/,
37 | loader: 'style!css!sass'
38 | }]
39 | }
40 | };
41 | ```
42 |
43 | ## LESS 和 SASS 中的 imports 怎么办?
44 | If you import one LESS/SASS file from an other, use the exact same pattern as anywhere else. Webpack will dig into these files and figure out the dependencies.
45 |
46 | 如果你从另外一个文件中导入一个 LESS/SASS 文件,像其他地方一样使用准确的路径,Webpack 会找出那些文件,然后识别里面的依赖。
47 |
48 | ```less
49 | @import "./variables.less";
50 | ```
51 |
52 | You can also load LESS files directly from your node_modules directory.
53 |
54 | 你也可以直接从你的 node_modules 文件夹中加载 LESS 文件。
55 |
56 | ```less
57 | $import "~bootstrap/less/bootstrap";
58 | ```
59 |
60 |
--------------------------------------------------------------------------------
/examples/content/Loading-SVG.md:
--------------------------------------------------------------------------------
1 | Webpack has a [few ways](https://github.com/webpack/webpack/issues/595) to load SVG. However the simplest way is through **file-loader**.
2 |
3 | ## Installation and configuration
4 |
5 | Install the loader: `npm install file-loader --save-dev`.
6 |
7 | In the webpack config file you can add the following loader configuration:
8 |
9 | **webpack.config.js**
10 |
11 | ```javascript
12 | var path = require('path');
13 | var config = {
14 | entry: path.resolve(__dirname, 'app/main.js')
15 | output: {
16 | path: path.resolve(__dirname, 'build'),
17 | filename: 'bundle.js'
18 | },
19 | module: {
20 | loaders: [{
21 | test: /\.jsx$/,
22 | loader: 'babel'
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file-loader'
26 | }]
27 | }
28 | };
29 | ```
30 |
31 | Then in your CSS:
32 |
33 | ```css
34 | .icon {
35 | background-image: url(../assets/icon.svg);
36 | }
37 | ```
38 |
39 | In this example the `assets` folder is relative to your CSS file.
40 |
41 | For SVG compression check out the [svgo-loader](https://github.com/pozadi/svgo-loader).
--------------------------------------------------------------------------------
/examples/content/Matchers.md:
--------------------------------------------------------------------------------
1 | ## 我可以使用哪种匹配器?
2 |
3 | * `{ test: /\.js$/, loader: 'babel-loader' }` - Matches just .js
4 | * `{ test: /\.(js|jsx)$/, loader: 'babel-loader' }` - Matches both js and jsx
5 | * Generally put it's just a JavaScript regex so standard tricks apply
6 |
7 |
8 | * `{ test: /\.js$/, loader: 'babel-loader' }` - 只匹配 .js
9 | * `{ test: /\.(js|jsx)$/, loader: 'babel-loader' }` - 匹配 js 和 jsx
10 | * 一般来说它就是一段 JavaScript 的正则,所以按照标准来即可
--------------------------------------------------------------------------------
/examples/content/Multiple-entry-points.md:
--------------------------------------------------------------------------------
1 | Maybe you are building an application that has multiple urls. An example of this would be a solution where you have two, or more, different URLs responding with different pages. Maybe you have one user page and one admin page. They both share a lot of code, but you do not want to load all the admin stuff for normal users. That is a good scenario for using multiple entry points. A list of use cases could be:
2 |
3 | 你的应用可能有多个路径, 就是应用中有两个或者多个 URL 相应不同的页面,这里就是提供这样的解决方案。可能你有一个普通用户页和一个管理员页,他们共享了很多代码,但是不想在普通用户页中加载所有管理员页的代码,所以好方案是使用多重入口。使用缘由有下面几条:
4 |
5 | - You have an application with multiple isolated user experiences, but they share a lot of code
6 | - You have a mobile version using less components
7 | - You have a typical user/admin application where you do not want to load all the admin code for a normal user
8 |
9 |
10 | - 你的应用有多种不同的用户体验,但是他们共享了很多代码。
11 | - 你有一个使用更少组件的手机版本
12 | - 你的应用是典型的权限控制,你不想为普通用户加载所有管理用户的代码。
13 |
14 | Let us create an example with a mobile experience using less components:
15 |
16 | 让我们创建一个使用更少组件的手机页面的例子:
17 |
18 | *webpack.production.config.js*
19 | ```javascript
20 | var path = require('path');
21 | var webpack = require('webpack');
22 | var node_modules_dir = path.resolve(__dirname, 'node_modules');
23 |
24 | var config = {
25 | entry: {
26 | app: path.resolve(__dirname, 'app/main.js'),
27 | mobile: path.resolve(__dirname, 'app/mobile.js'),
28 | vendors: ['react'] // 其他库
29 | },
30 | output: {
31 | path: path.resolve(__dirname, 'dist'),
32 | filename: '[name].js' // 注意我们使用了变量
33 | },
34 | module: {
35 | loaders: [{
36 | test: /\.js$/,
37 | exclude: [node_modules_dir],
38 | loader: 'babel'
39 | }]
40 | },
41 | plugins: [
42 | new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js')
43 | ]
44 | };
45 |
46 | module.exports = config;
47 | ```
48 | This configuration will create three files in the `dist/` folder. **app.js**, **mobile.js** and **vendors.js**. Most of the code in the **mobile.js** file also exists in **app.js**, but that is what we want. We will never load **app.js** and **mobile.js** on the same page.
49 |
50 | 这个配置会在 `dist/` 文件夹下创建三个文件:**app.js**、**mobile.js**和**vendors.js**,大部分的代码在**mobile.js**文件中,也有一部分在 **app.js** 中,不过这是我们需要的,我们不会在同一个页面中同时加载 **app.js** 和 **mobile.js**。
--------------------------------------------------------------------------------
/examples/content/Navigation.md:
--------------------------------------------------------------------------------
1 | 1. [something](/christianalfoni/react-webpack-cookbook/wiki/02.-Why-Webpack-and-React-JS%3F)
--------------------------------------------------------------------------------
/examples/content/Optimizing-caching.md:
--------------------------------------------------------------------------------
1 | When users hit the URL of your application they will need to download different assets. CSS, JavaScript, HTML, images and fonts. The great thing about Webpack is that you can stop thinking how you should download all these assets. You can do it through JavaScript.
2 |
3 | 当用户输入你应用的地址的时候,他们需要去下载不同的资源,比如 CSS、JavaScript、HTML、图片和字体。不过 Webpack 做了一件事情,让你不用去考虑如何不用下载全部资源。
4 |
5 | > OccurenceOrderPlugin
6 |
7 |
8 | ## 如何让生产输出附上哈希值?
9 |
10 | * Use `[hash]`. Example: `'assets/bundle.[hash].js'`
11 | * 使用 `[hash]`。比如:`'assets/bundle.[hash].js'`
12 |
13 | The benefit of this is that this will force the client to reload the file. There is more information about `[hash]` at [the long term caching](http://webpack.github.io/docs/long-term-caching.html) section of the official documentation.
14 |
15 | 这个的好处是能够让客户端强制重新加载这个文件,可以在 [the long term caching](http://webpack.github.io/docs/long-term-caching.html) 了解更多关于 `[hash]`,
16 |
17 | > Is it possible to change the hash only if bundle changed?
18 | > 有可能只有合并文件变化了才会修改哈希值么?
--------------------------------------------------------------------------------
/examples/content/Optimizing-development.md:
--------------------------------------------------------------------------------
1 | We talked about how you could use the minified versions of your dependencies in development to make the rebundling go as fast as possible. Let us look at a small helper you can implement to make this a bit easier to handle.
2 |
3 | 之前介绍了如何在开发中使用依赖的压缩版本来让合并尽可能加速,让我们看一下这个小的例子来让你更加轻松去处理:
4 |
5 | *webpack.config.js*
6 | ```javascript
7 | var webpack = require('webpack');
8 | var path = require('path');
9 | var node_modules_dir = path.join(__dirname, 'node_modules');
10 |
11 | var deps = [
12 | 'react/dist/react.min.js',
13 | 'react-router/dist/react-router.min.js',
14 | 'moment/min/moment.min.js',
15 | 'underscore/underscore-min.js',
16 | ];
17 |
18 | var config = {
19 | entry: ['webpack/hot/dev-server', './app/main.js'],
20 | output: {
21 | path: path.resolve(__dirname, './build'),
22 | filename: 'bundle.js'
23 | },
24 | resolve: {
25 | alias: {}
26 | },
27 | module: {
28 | noParse: [],
29 | loaders: []
30 | }
31 | };
32 |
33 | // Run through deps and extract the first part of the path,
34 | // as that is what you use to require the actual node modules
35 | // in your code. Then use the complete path to point to the correct
36 | // file and make sure webpack does not try to parse it
37 | // 通过在第一部分路径的依赖和解压
38 | // 就是你像引用 node 模块一样引入到你的代码中
39 | // 然后使用完整路径指向当前文件,然后确认 Webpack 不会尝试去解析它
40 |
41 | deps.forEach(function (dep) {
42 | var depPath = path.resolve(node_modules_dir, dep);
43 | config.resolve.alias[dep.split(path.sep)[0]] = depPath;
44 | config.module.noParse.push(depPath);
45 | });
46 |
47 | module.exports = config;
48 | ```
49 | Not all modules include a minified distributed version of the lib, but most do. Especially with large libraries like React JS you will get a significant improvement.
50 |
51 | 不是所有的模块需要一个压缩的版本,不过大多数需要,尤其是像 React JS 这种大型库,之后你会有明显的提升。
52 |
53 | ## 把 React 暴露到全局中
54 | You might be using distributed versions that requires React JS on the global scope. To fix that you can install the expose-loader by `npm install expose-loader --save-dev` and set up the following config, focusing on the *module* property:
55 |
56 | 你可能在全局中使用了一个压缩版本的 React,为了修复你可以安装这个暴露全局加载器 `npm install expose-loader --save-dev`,然后像下面这样配置,注意 *module* 属性:
57 |
58 | ```javascript
59 | var webpack = require('webpack');
60 | var path = require('path');
61 | var node_modules_dir = path.join(__dirname, 'node_modules');
62 |
63 | var deps = [
64 | 'react/dist/react.min.js',
65 | 'react-router/dist/react-router.min.js',
66 | 'moment/min/moment.min.js',
67 | 'underscore/underscore-min.js',
68 | ];
69 |
70 | var config = {
71 | entry: ['webpack/hot/dev-server', './app/main.js'],
72 | output: {
73 | path: path.resolve(__dirname, './build'),
74 | filename: 'bundle.js'
75 | },
76 | resolve: {
77 | alias: {}
78 | },
79 | module: {
80 | noParse: [],
81 |
82 | // Use the expose loader to expose the minified React JS
83 | // distribution. For example react-router requires this
84 | // 使用暴露全局加载器来暴露压缩版的 React JS,比如 react-router 需要这个。
85 | loaders: [{
86 | test: path.resolve(node_modules_dir, deps[0]),
87 | loader: "expose?React"
88 | }]
89 | }
90 | };
91 |
92 | deps.forEach(function (dep) {
93 | var depPath = path.resolve(node_modules_dir, dep);
94 | config.resolve.alias[dep.split(path.sep)[0]] = depPath;
95 | config.module.noParse.push(depPath);
96 | });
97 |
98 | module.exports = config;
99 | ```
--------------------------------------------------------------------------------
/examples/content/Optimizing-rebundling.md:
--------------------------------------------------------------------------------
1 | You might notice after requiring React JS into your project that the time it takes from a save to a finished rebundle of your application takes more time. In development you ideally want from 200-800 ms rebundle speed, depending on what part of the application you are working on.
2 |
3 | 你可能注意到在引入 React JS 到你的项目之后,给你的应用重新合并会花费太多的时间。在开发环境中,最理想的是编译最多 200 到 800 毫秒的速度,取决于你在开发的应用。
4 |
5 | > IMPORTANT! This setup a minified, production version of React. As a result you will lose `propTypes` based type validation!
6 |
7 | > 注意!这个是设置一个压缩和发布的 React 版本,结果你可能会失去 `propTypes` 基础类型检查!
8 |
9 | ## 在开发环境中使用压缩文件
10 |
11 | Instead of making Webpack go through React JS and all its dependencies, you can override the behavior in development.
12 |
13 | 为了不让 Webpack 去遍历 React JS 及其所有依赖,你可以在开发中重写它的行为。
14 |
15 | **webpack.config.js**
16 |
17 | ```javascript
18 | var path = require('path');
19 | var node_modules = path.resolve(__dirname, 'node_modules');
20 | var pathToReact = path.resolve(node_modules, 'react/dist/react.min.js');
21 |
22 | config = {
23 | entry: ['webpack/hot/dev-server', path.resolve(__dirname, 'app/main.js')],
24 | resolve: {
25 | alias: {
26 | 'react': pathToReact
27 | }
28 | },
29 | output: {
30 | path: path.resolve(__dirname, 'build'),
31 | filename: 'bundle.js',
32 | },
33 | module: {
34 | loaders: [{
35 | test: /\.jsx?$/,
36 | loader: 'babel'
37 | }],
38 | noParse: [pathToReact]
39 | }
40 | };
41 |
42 | module.exports = config;
43 | ```
44 |
45 | We do two things in this configuration:
46 |
47 | 我们在配置中做了两件事:
48 |
49 | 1. Whenever "react" is required in the code it will fetch the minified React JS file instead of going to *node_modules*
50 |
51 | 2. Whenever Webpack tries to parse the minified file, we stop it, as it is not necessary
52 |
53 |
54 |
55 | 1. 每当 "react" 在代码中被引入,它会使用压缩后的 React JS 文件,而不是到 *node_modules* 中找。
56 | 2. 每当 Webpack 尝试去解析那个压缩后的文件,我们阻止它,因为这不必要。
57 |
58 | Take a look at [Optimizing development](Optimizing-development) for more information on this.
59 |
60 | 可以到 [优化开发](Optimizing-development) 看到更多这方面的信息。
61 |
--------------------------------------------------------------------------------
/examples/content/Optimizing-workflow.md:
--------------------------------------------------------------------------------
1 | - Using bower files with noparse to improve rebundle speed
--------------------------------------------------------------------------------
/examples/content/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | search:
3 | keywords: ['readme', 'meta']
4 | ---
5 |
6 |
7 | [Gitbook 英文原版](http://christianalfoni.github.io/react-webpack-cookbook/)
8 | =======
9 | > [zh-cn](https://fakefish.github.io/react-webpack-cookbook/)
10 |
11 | > 如果你想修改中文版,请提交PR [中文版本](https://github.com/fakefish/react-webpack-cookbook) 或者在 [原 Repo](https://github.com/christianalfoni/react-webpack-cookbook/issues) 中提 Issues。
12 |
13 | 这本小书的目的是引导你进入 React 和 Webpack 的世界。他们两个都是非常有用的技术,如果同时使用他们,前端开发会更加有趣。
14 |
15 |
16 | 这本小书会提供所有相关的技能。如果你只是对 React 感兴趣,那可以跳过 Webpack 相关的内容,反之亦然。 如果想学习更多的相关知识可以移步 [SurviveJS - Webpack and React](http://survivejs.com/)。
17 |
18 |
19 | ## React
20 |
21 | React 是一个能够让开发模块变成简单的库。一旦你理解他的工作原理,那你就可以用它搭建自己的程序,这是不同类似 Angular 那种试着包揽一切的框架不同的地方。
22 |
23 | 如果你想很快过一遍 React 的知识点,那么 [React 官方教程](http://facebook.github.io/react/docs/tutorial.html) 是一个很好的开始。
24 |
25 | 可能 React 最有趣的事是它一直会尝试调整传统的 web 组件的思路。它让我们重新思考关注点的分离。它([React Native](https://facebook.github.io/react-native/))也会影响 App 开发。 React Native 提供了一种使用 JavaScript 开发原生应用同时保证了原生性能。
26 |
27 | ## Webpack
28 |
29 | Webpack 非常容易操作,它是一个模块合并的工具,本质就是一个能够把各种组件(HTML,CSS,JS)构建成项目。最方便的是你只需要初始化配置一次,Webpack 会替你做那些繁琐的事情,同时也保证了让你可以在项目中混合使用各种技术而不头疼。
30 |
31 |
32 | 如果你在 Webpack 方面完全是新手的,但想开始一个简单的教程的话,可以去 [Pete Hunt's guide](https://github.com/petehunt/webpack-howto)。你可以在那里学习到一些基础的使用,这里只是那边的一个补充。
33 |
34 |
35 | ## 作者
36 |
37 | [Christian Alfoni](http://www.christianalfoni.com/) and [Juho Vepsäläinen](http://survivejs.com/).
38 |
39 | ## 中文译者
40 |
41 | [Fakefish](http://fakefish.github.io/)
42 |
43 |
--------------------------------------------------------------------------------
/examples/content/Requiring-files.md:
--------------------------------------------------------------------------------
1 | ## 模块
2 |
3 | Webpack allows you to use different module patterns, but "under the hood" they all work the same way. All of them also works straight out of the box.
4 |
5 | Webpack 允许你使用不同的模块类型,但是 “底层”必须使用同一种实现。所有的模块都能够开箱即用。
6 |
7 | #### ES6 模块
8 |
9 | ```javascript
10 | import MyModule from './MyModule.js';
11 | ```
12 |
13 | #### CommonJS
14 |
15 | ```javascript
16 | var MyModule = require('./MyModule.js');
17 | ```
18 |
19 | #### AMD
20 |
21 | ```javascript
22 | define(['./MyModule.js'], function (MyModule) {
23 |
24 | });
25 | ```
26 |
27 | ## 理解文件路径
28 |
29 | A module is loaded by filepath. Imagine the following tree structure:
30 |
31 | 一个模块会按它的文件路径来加载,看一下下面的这个结构:
32 |
33 | - /app
34 | - /modules
35 | - MyModule.js
36 | - main.js (entry point)
37 | - utils.js
38 |
39 | Lets open up the *main.js* file and require *app/modules/MyModule.js* in the two most common module patterns:
40 |
41 | 打开 *main.js* 然后可以通过下面两种方式引入 *app/modules/MyModule.js*
42 |
43 | *app/main.js*
44 | ```javascript
45 | // ES6
46 | import MyModule from './modules/MyModule.js';
47 |
48 | // CommonJS
49 | var MyModule = require('./modules/MyModule.js');
50 | ```
51 |
52 | The `./` at the beginning states "relative to the file I am in now".
53 |
54 | 最开始的 `./` 是 “相对当前文件路径”
55 |
56 | Now let us open the *MyModule.js* file and require **app/utils**.
57 |
58 | 让我们打开 *MyModule.js* 然后引入 **app/utils**:
59 |
60 | *app/modules/MyModule.js*
61 | ```javascript
62 | // ES6 相对路径
63 | import utils from './../utils.js';
64 |
65 | // ES6 绝对路径
66 | import utils from '/utils.js';
67 |
68 | // CommonJS 相对路径
69 | var utils = require('./../utils.js');
70 |
71 | // CommonJS 绝对路径
72 | var utils = require('/utils.js');
73 | ```
74 |
75 | The **relative path** is relative to the current file. The **absolute path** is relative to the entry file, which in this case is *main.js*.
76 |
77 | **相对路径**是相对当前目录。**绝对路径**是相对入口文件,这个案例中是 *main.js*。
78 |
79 | ### 我需要使用文件后缀么?
80 |
81 | No, you do not have to use *.js*, but it highlights better what you are requiring. You might have some .js files, and some .jsx files and even images and css can be required by Webpack. It also clearly differs from required node_modules and specific files.
82 |
83 | 不,你不需要去特意去使用 *.js*,但是他能够更让你更清楚你正引入的档案。因為你可能有一些 .js 文件和一些 .jsx 文件,甚至一些图片和 css 可以用 Webpack 來引入。加入文件后缀,可以让你清楚地区分你引入的是 node_modules 或特定档案还是一般文件档案。
84 |
85 | Remember that Webpack is a module bundler! This means you can set it up to load any format you want given there is a loader for it. We'll delve into this topic later on.
86 |
87 | 记住,Webpack 只是一个模块合并器!也就是说你可以设置他去加载任何你写的匹配,只要有一个加载器。我们稍后会继续深入这个话题。
88 |
--------------------------------------------------------------------------------
/examples/content/Requiring-images-and-fonts.md:
--------------------------------------------------------------------------------
1 | - Inlining images and fonts
--------------------------------------------------------------------------------
/examples/content/Running-a-workflow.md:
--------------------------------------------------------------------------------
1 | Hitting `npm run build` all the time will get boring eventually. Fortunately we can work around that quite easily. Let's set up `webpack-dev-server`.
2 |
3 | 如果需要一直输入 `npm run build` 确实是一件非常无聊的事情,幸运的是,我们可以把让他安静的运行,让我们设置 `webpack-dev-server`。
4 |
5 | ## 设置 `webpack-dev-server`
6 |
7 | As a first step, hit `npm i webpack-dev-server --save`. In addition we'll need to tweak `package.json` *scripts* section to include it. Here's the basic idea:
8 |
9 | 第一步,输入 `npm i webpack-dev-server --save`,此外,我们需要去调整 `package.json` *scripts* 部分去包含这个指令,下面是基本的设置:
10 |
11 | *package.json*
12 | ```json
13 | {
14 | "scripts": {
15 | "build": "webpack",
16 | "dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build"
17 | }
18 | }
19 | ```
20 |
21 | When you run `npm run dev` from your terminal it will execute the command stated as a value on the **dev** property. This is what it does:
22 |
23 | 当你在命令行里运行 `npm run dev` 的时候他会执行 **dev** 属性里的值。这是这些指令的意思:
24 |
25 | 1. `webpack-dev-server` - Starts a web service on localhost:8080
26 | 2. `--devtool eval` - Creates source urls for your code. Making you able to pinpoint by filename and line number where any errors are thrown
27 | 3. `--progress` - Will show progress of bundling your application
28 | 4. `--colors` - Yay, colors in the terminal!
29 | 5. `--content-base build` - Points to the output directory configured
30 |
31 |
32 | 1. `webpack-dev-server` - 在 localhost:8080 建立一个 Web 服务器
33 | 2. `--devtool eval` - 为你的代码创建源地址。当有任何报错的时候可以让你更加精确地定位到文件和行号
34 | 3. `--progress` - 显示合并代码进度
35 | 4. `--colors` - Yay,命令行中显示颜色!
36 | 5. `--content-base build` - 指向设置的输出目录
37 |
38 | To recap, when you run `npm run dev` this will fire up the webservice, watch for file changes and automatically rebundle your application when any file changes occur. How neat is that!
39 |
40 | 总的来说,当你运行 `npm run dev` 的时候,会启动一个 Web 服务器,然后监听文件修改,然后自动重新合并你的代码。真的非常简洁!
41 |
42 | Go to **http://localhost:8080** and you should see something.
43 |
44 | 访问 **http://localhost:8080** 你会看到效果。
--------------------------------------------------------------------------------
/examples/content/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # Navigation
2 |
3 | [序](Home.md)
4 |
5 | * [介绍 Webpack](Introduction-to-Webpack.md)
6 | * [第一步](Getting-started.md)
7 | * [开始工作流](Running-a-workflow.md)
8 | * [浏览器自动刷新](Automatic-browser-refresh.md)
9 | * [引入文件](Requiring-files.md)
10 | * [React JS](Introduction-to-React-JS.md)
11 | * [配置 React JS](Configuring-react-js.md)
12 | * [优化重合并](Optimizing-rebundling.md)
13 | * [Flow](Type-checking-with-flow.md)
14 | * [CSS, Fonts and Images](CSS-Fonts-Images.md)
15 | * [加载 CSS](Loading-CSS.md)
16 | * [自动刷新 CSS](Automatic-CSS-refresh.md)
17 | * [加载 LESS 和 SASS](Loading-LESS-or-SASS.md)
18 | * [内联 images](Inlining-images.md)
19 | * [内联 fonts](Inlining-fonts.md)
20 | * [部署策略](Deployment-strategies.md)
21 | * [发布配置](Structuring-configuration.md)
22 | * [合并成单文件](Single-bundle.md)
23 | * [分离应用和第三方](Split-app-and-vendors.md)
24 | * [多重入口](Multiple-entry-points.md)
25 | * [懒加载入口文件](Lazy-loaded-entry-points.md)
26 | * [同构渲染](Isomorphic-app.md)
27 | * [进阶](Wing-It-Like-a-Pro.md)
28 | * [优化开发](Optimizing-development.md)
29 | * [热加载组件](Hot-loading-components.md)
30 | * [使用下一代 JavaScript](JavaScript-next.md)
31 | * [优化缓存](Optimizing-caching.md)
32 | * [匹配器](Matchers.md)
33 | * [懒加载入口](Lazy-loading-entry-points.md)
34 | * [创建一个复用代码](Creating-a-common-bundle.md)
35 | * [理解 Chunks](Understanding-chunks.md)
36 | * [创建库](Authoring-libraries.md)
--------------------------------------------------------------------------------
/examples/content/Single-bundle.md:
--------------------------------------------------------------------------------
1 | Lets have a look at the simplest setup you can create for your application. Use a single bundle when:
2 |
3 | 让我们看一下为应用创建的最简单的配置,只有在下面的情况下才使用单入口模式:
4 |
5 | - You have a small application
6 | - You will rarely update the application
7 | - You are not too concerned about perceived initial loading time
8 |
9 |
10 | - 应用很小
11 | - 很少会更新应用
12 | - 你不太关心初始加载时间
13 |
14 |
15 | *webpack.production.config.js*
16 | ```javascript
17 | var path = require('path');
18 | var config = {
19 | entry: path.resolve(__dirname, 'app/main.js'),
20 | output: {
21 | path: path.resolve(__dirname, 'dist'),
22 | filename: 'bundle.js'
23 | },
24 | module: {
25 | loaders: [{
26 | test: /\.js$/,
27 | loader: 'babel'
28 | }]
29 | }
30 | };
31 |
32 | module.exports = config;
33 | ```
--------------------------------------------------------------------------------
/examples/content/Split-app-and-vendors.md:
--------------------------------------------------------------------------------
1 | When your application is depending on other libraries, especially large ones like React JS, you should consider splitting those dependencies into its own vendors bundle. This will allow you to do updates to your application, without requiring the users to download the vendors bundle again. Use this strategy when:
2 |
3 | 当你的应用依赖其他库尤其是像 React JS 这种大型库的时候,你需要考虑把这些依赖分离出去,这样就能够让用户在你更新应用之后不需要再次下载第三方文件。当满足下面几个情况的时候你就需要这么做了:
4 |
5 | - When your vendors reaches a certain percentage of your total app bundle. Like 20% and up
6 | - You will do quite a few updates to your application
7 | - You are not too concerned about perceived initial loading time, but you do have returning users and care about optimizing the experience when you do updates to the application
8 | - Users are on mobile
9 |
10 |
11 | - 当你的第三方的体积达到整个应用的 20% 或者更高的时候。
12 | - 更新应用的时候只会更新很小的一部分
13 | - 你没有那么关注初始加载时间,不过关注优化那些回访用户在你更新应用之后的体验。
14 | - 有手机用户。
15 |
16 | *webpack.production.config.js*
17 | ```javascript
18 | var path = require('path');
19 | var webpack = require('webpack');
20 | var node_modules_dir = path.resolve(__dirname, 'node_modules');
21 |
22 | var config = {
23 | entry: {
24 | app: path.resolve(__dirname, 'app/main.js'),
25 |
26 | // Since react is installed as a node module, node_modules/react,
27 | // we can point to it directly, just like require('react');
28 | // 当 React 作为一个 node 模块安装的时候,
29 | // 我们可以直接指向它,就比如 require('react')
30 | vendors: ['react']
31 | },
32 | output: {
33 | path: path.resolve(__dirname, 'dist'),
34 | filename: 'app.js'
35 | },
36 | module: {
37 | loaders: [{
38 | test: /\.js$/,
39 | exclude: [node_modules_dir],
40 | loader: 'babel'
41 | }]
42 | },
43 | plugins: [
44 | new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js')
45 | ]
46 | };
47 |
48 | module.exports = config;
49 | ```
50 | This configuration will create two files in the `dist/` folder. **app.js** and **vendors.js**.
51 |
52 | 这些配置会在 `dist/` 文件夹下创建两个文件:**app.js** 和 **vendors.js**。
53 |
54 | #### 重要的事情!
55 | Remember to add both files to your HTML file, or you will get the error: `Uncaught ReferenceError: webpackJsonp is not defined`.
56 |
57 | 记住要把这些文件都加入到你的 HTML 代码中,不然你会得到一个错误:`Uncaught ReferenceError: webpackJsonp is not defined`。
--------------------------------------------------------------------------------
/examples/content/Structuring-configuration.md:
--------------------------------------------------------------------------------
1 | There are two things you want to do preparing for a production build.
2 |
3 | 这里有两件事你需要为生产发布做准备。
4 |
5 | 1. Configure a script to run in your package.json file
6 | 2. Create a production config
7 |
8 |
9 | 1. 配置你的 package.json 里的脚本
10 | 2. 创建一个生产的配置
11 |
12 |
13 | ### 创建脚本
14 | We have already used *package.json* to create the `npm run dev` script. Now let us set up `npm run deploy`.
15 |
16 | 我们已经使用过 *package.json* 来创建 `npm run dev` 的脚本,现在让我们设置 `npm run deploy`。
17 |
18 | ```json
19 | {
20 | "name": "my-project",
21 | "version": "0.0.0",
22 | "description": "My awesome project!",
23 | "main": "app/main.js",
24 | "scripts": {
25 | "dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build",
26 | "deploy": "NODE_ENV=production webpack -p --config webpack.production.config.js"
27 | },
28 | "author": "",
29 | "license": "ISC",
30 | "devDependencies": {
31 | "webpack": "^1.4.13",
32 | "webpack-dev-server": "^1.6.6"
33 | },
34 | "dependencies": {}
35 | }
36 | ```
37 |
38 | As you can see we are just running webpack with the production argument and pointing to a different configuration file. We also use the environment variable "production" to allow our required modules to do their optimizations. Lets us create the config file now.
39 |
40 | 正如你所见,我们只是用生产参数运行 Webpack 来指向另一个配置文件。我们也使用了环境变量 “production” 来让我们的模块自动去优化。让我们开始来创建配置文件。
41 |
42 | ### 创建生产配置
43 | So there really is not much difference in creating the dev and production versions of your webpack config. You basically point to a different output path and there are no workflow configurations or optimizations. What you also want to bring into this configuration is cache handling.
44 |
45 | 可以看到,其实生产环境的配置和开发的配置没有太大的不同,主要的不同是指向了一个不同的输出路径,然后也没有了 workflow 的配置和优化,可以看到新加入到配置里的是处理缓存的配置。
46 |
47 | ```javascript
48 | var path = require('path');
49 | var node_modules_dir = path.resolve(__dirname, 'node_modules');
50 |
51 | var config = {
52 | entry: path.resolve(__dirname, 'app/main.js'),
53 | output: {
54 | path: path.resolve(__dirname, 'dist'),
55 | filename: 'bundle.js'
56 | },
57 | module: {
58 | loaders: [{
59 | test: /\.js$/,
60 |
61 | // There is not need to run the loader through
62 | // vendors
63 | // 这里再也不需通过任何第三方来加载
64 | exclude: [node_modules_dir],
65 | loader: 'babel'
66 | }]
67 | }
68 | };
69 |
70 | module.exports = config;
71 | ```
72 |
73 | ### 发布
74 | Run `npm run deploy` in the root of the project. Webpack will now run in production mode. It does some optimizations on its own, but also React JS will do its optimizations. Look into caching for even more production configuration.
75 |
76 | 在项目根目录处运行 `npm run deploy`,Webpack 现在会运行生产模式,他会自动做一些优化,不过,React Js 也会做自己的优化。可以深入了解缓存处理来做更多的生产配置。
77 |
--------------------------------------------------------------------------------
/examples/content/Type-checking-with-flow.md:
--------------------------------------------------------------------------------
1 | If you come to JavaScript from other programming languages you are familiar with types. You have types in JavaScript too, but you do not have to specify these types when declaring variables, receiving arguments etc. This is one of the things that makes JavaScript great, but at the same time not so great.
2 |
3 | 如果你是从其他你更熟悉类型的编程语言转到 JavaScript 的,那么,你也可以在 JavaScript 中使用类型,不过你不需要在声明变量或者接收参数的时候指定类型。这可以让你的代码更加优雅,但是不是最优雅的。
4 |
5 | Specifically when working on very large projects with many developers type checking gives stability to your project, much like a good test does. So using **Flow** is definitely not a requirement. It is for developers who depends on type checking as more of a routine and for the before mentioned large projects with many developers. Webpack makes it easy to include **Flow** in your workflow.
6 |
7 | 具体来说,当你在一个大项目中和很多开发者一起工作的时候,类型检查对你的项目来讲是保证了稳定性,就像一个很好的测试做的事情。所以使用 **Flow** 当然不是必要条件。对于那些需要和很多开发者一起做大项目的开发者来说类型检测是一种非常寻常的事。Webpack 引入 **Flow** 之后会非常方便。
8 |
9 | ## 安装 flow
10 |
11 | - 还没尝试:)
12 | - 尝试一下 "flowcheck-loader"? https://www.npmjs.com/package/flowcheck-loader (还没用过:))
13 | - https://tryflow.org/
--------------------------------------------------------------------------------
/examples/content/Understanding-chunks.md:
--------------------------------------------------------------------------------
1 | - Explain how webpack thinks chunks and not files
2 | - What are files to load? And what does webpack create for you? And how?
3 |
4 | - 解释 Webpack 如何理解 chunks 而不是文件。
5 | - 加载什么文件?Webpack 会创建怎么样的?如何?
--------------------------------------------------------------------------------
/examples/content/Wing-It-Like-a-Pro.md:
--------------------------------------------------------------------------------
1 | > TODO: what to discuss in intro? Maybe summarize what makes a pro. Like using hot loader, caching etc. hm hm... maybe look at it after the sub pages are done, cherry on the top :-)
--------------------------------------------------------------------------------
/examples/content/Writing-loaders.md:
--------------------------------------------------------------------------------
1 | Let's say we want a custom Markdown loader. Ie. we would like to do something like `var readme = require('../README.md');` at our JavaScript file and inject some Markdown converted as HTML there.
2 |
3 | As it happens doing something like this is quite easy with Webpack. We'll need to implement a little loader for this and hook it up with our Webpack configuration. Consider the example below. I've included syntax highlighting just for the kicks.
4 |
5 | **loaders/markdown.js**
6 |
7 | ```javascript
8 | 'use strict';
9 |
10 | var marked = require('marked');
11 | var highlight = require('highlight.js');
12 |
13 | marked.setOptions({
14 | highlight: function(code) {
15 | return highlight.highlightAuto(code).value;
16 | }
17 | });
18 |
19 |
20 | module.exports = function(markdown) {
21 | this.cacheable();
22 |
23 | return marked(markdown);
24 | };
25 | ```
26 |
27 | **Webpack configuration**
28 |
29 | ```javascript
30 | resolve: {
31 | extensions: ['.md', ...],
32 | ...
33 | },
34 | loaders: [
35 | {
36 | test: /\.md$/,
37 | loader: 'html!./loaders/markdown',
38 | },
39 | ]
40 | ```
41 |
42 | Simple as that! You can read more about [loaders at the official documentation](http://webpack.github.io/docs/loaders.html).
43 |
44 | If you want to attach some CSS for syntax highlighting by the way, you can just `require` the needed CSS like this: `require('highlight.js/styles/github.css');`. That expects `highlight.js` has been installed correctly (ie. within `node_modules`) and Webpack can find it. You should also have `css-loader` set up like this:
45 |
46 | ```javascript
47 | {
48 | test: /\.css$/,
49 | loaders: ['style', 'css'],
50 | },
51 | ```
52 |
53 | This expects you have `style-loader` and `css-loader` installed into your project, preferably as development dependencies (`npm i style-loader css-loader --save-dev`).
--------------------------------------------------------------------------------
/examples/content/_Footer.md:
--------------------------------------------------------------------------------
1 | The React Webpack Cookbook is a work in progress by @bebraw and @christianalfoni
--------------------------------------------------------------------------------
/examples/content/book.json:
--------------------------------------------------------------------------------
1 | {
2 | "gitbook": ">=2.0.0",
3 | "title": "React Webpack 小书",
4 | "description": "解决 Webpack 的一些通用小问题",
5 | "language": "zh-cn"
6 | }
7 |
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/examples/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-webpack-cookbook",
3 | "version": "0.0.0",
4 | "description": "React Webpack cookbook",
5 | "main": "./index.js",
6 | "devDependencies": {
7 | "gitbook": "^3.2.2",
8 | "gitbook-cli": "^2.3.0",
9 | "gitbook-plugin-search-plus": "latest",
10 | "gitbook-plugin-fontsettings": "^2.0.0",
11 | "pre-commit": "^1.2.2"
12 | },
13 | "scripts": {
14 | "start": "npm run watch",
15 | "build": "npm run cli build . book --force",
16 | "watch": "npm run cli serve . book --force",
17 | "commit": "git add -A",
18 | "cli": "node ./cli.js"
19 | },
20 | "pre-commit": {
21 | "run": ["build", "commit"],
22 | "silent": true
23 | },
24 | "repository": {
25 | "type": "git",
26 | "url": "https://github.com/christianalfoni/react-webpack-cookbook.git"
27 | },
28 | "keywords": [
29 | "react",
30 | "webpack"
31 | ],
32 | "author": "",
33 | "license": "MIT",
34 | "bugs": {
35 | "url": "https://github.com/christianalfoni/react-webpack-cookbook/issues"
36 | },
37 | "homepage": "https://github.com/christianalfoni/react-webpack-cookbook"
38 | }
39 |
--------------------------------------------------------------------------------
/examples/search.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lwdgit/gitbook-plugin-search-plus/4be5e093436adb80fbd3c95a8ebc497588ee3522/examples/search.gif
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var Entities = require('html-entities').AllHtmlEntities
2 |
3 | var Html = new Entities()
4 |
5 | // Map of Lunr ref to document
6 | var documentsStore = { }
7 |
8 | module.exports = {
9 | book: {
10 | assets: './assets',
11 | js: [
12 | 'jquery.mark.min.js',
13 | 'search.js'
14 | ],
15 | css: [
16 | 'search.css'
17 | ]
18 | },
19 |
20 | hooks: {
21 | // Index each page
22 | 'page': function (page) {
23 | if (this.output.name !== 'website' || page.search === false) {
24 | return page
25 | }
26 |
27 | var text
28 |
29 | this.log.debug.ln('index page', page.path)
30 |
31 | text = page.content
32 | // Decode HTML
33 | text = Html.decode(text)
34 | // Strip HTML tags
35 | text = text.replace(/(<([^>]+)>)/ig, '')
36 | text = text.replace(/[\n ]+/g, ' ')
37 | var keywords = []
38 | if (page.search) {
39 | keywords = page.search.keywords || []
40 | }
41 |
42 | // Add to index
43 | var doc = {
44 | url: this.output.toURL(page.path),
45 | title: page.title,
46 | summary: page.description,
47 | keywords: keywords.join(' '),
48 | body: text
49 | }
50 |
51 | documentsStore[doc.url] = doc
52 |
53 | return page
54 | },
55 |
56 | // Write index to disk
57 | 'finish': function () {
58 | if (this.output.name !== 'website') return
59 |
60 | this.log.debug.ln('write search index')
61 | return this.output.writeFile('search_plus_index.json', JSON.stringify(documentsStore))
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gitbook-plugin-search-plus",
3 | "version": "1.0.4-alpha-3",
4 | "description": "gitbook powerful search plugin",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "cd examples&&npm install&&npm start",
8 | "test": "echo \"Error: no test specified\" && exit 1",
9 | "add": "git add -A",
10 | "standard": "standard --fix assets/search.js, index.js",
11 | "pages:build": "cd examples&&npm install&&npm run build",
12 | "pages:push": "git subtree --prefix=examples push pages gh-pages"
13 | },
14 | "repository": {
15 | "type": "git",
16 | "url": "git+https://github.com/lwdgit/gitbook-plugin-search-plus.git"
17 | },
18 | "engines": {
19 | "gitbook": ">=3.0.0"
20 | },
21 | "dependencies": {
22 | "html-entities": "1.2.0"
23 | },
24 | "devDependencies": {
25 | "pre-commit": "^1.2.2",
26 | "standard": "^9.0.2"
27 | },
28 | "pre-commit": {
29 | "run": [
30 | "standard",
31 | "pages:build",
32 | "add"
33 | ],
34 | "silent": true
35 | },
36 | "author": "lwdgit",
37 | "license": "Apache-2.0",
38 | "bugs": {
39 | "url": "https://github.com/lwdgit/gitbook-plugin-search-plus/issues"
40 | },
41 | "homepage": "https://github.com/lwdgit/gitbook-plugin-search-plus#readme"
42 | }
43 |
--------------------------------------------------------------------------------
/search.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lwdgit/gitbook-plugin-search-plus/4be5e093436adb80fbd3c95a8ebc497588ee3522/search.gif
--------------------------------------------------------------------------------
/search2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lwdgit/gitbook-plugin-search-plus/4be5e093436adb80fbd3c95a8ebc497588ee3522/search2.gif
--------------------------------------------------------------------------------
/search3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lwdgit/gitbook-plugin-search-plus/4be5e093436adb80fbd3c95a8ebc497588ee3522/search3.gif
--------------------------------------------------------------------------------