[Перевод] Руководство по веб-пакету Ruan Yifeng (демонстрационная коллекция)

JavaScript React.js CSS Webpack

Переведите, это в основном используется для изучения Webpack, исходный адресGitHub.com/Ruan Yifeng/Web P…

Руководство по установке и использованию

Во-первых, глобально установите Webpack и webpack-dev-server.

$ npm i -g webpack webpack-dev-server

Затем клонируйте репозиторий клона Ruan Yifeng.

$ git clone https://github.com/ruanyf/webpack-demos.git

Установить зависимости

$ cd webpack-demos
$ npm install

Теперь перейдите в каталог demo* и запустите их.

$ cd demo01
$ npm run dev

Приведенный выше код не откроет ваш браузер автоматически, вам необходимо получить к нему доступ вручную.http://127.0.0.1:8080

Предисловие: Что такое Webpack

WebPack используется для создания сценария модуля JavaScript, чтобы предоставить интерфейсный инструмент, используемый браузером.
Это похоже на Browserify, но может больше~

$ browserify main.js > bundle.js
# 上下代码作用相同
$ webpack main.js bundle.js

Webpack требует файл с именемwebpack.config.jsФайл конфигурации, этот файл представляет собой модуль CommonJS (модуль)

// webpack.config.js的内容
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  }
};

когда построенwebpack.config.jsЗатем вы можете запустить Webpack напрямую без параметров

$ webpack

Ниже приведены некоторые обязательные параметры параметров.

  • webpack- команда сборки во время разработки
  • webpack -p- Команды сборки при выпуске продукта
  • webpack --watch- Сборки для инкрементной разработки
  • webpack -d- включая исходные карты
  • webpack --colors- сделать вывод сборки лучше

можно настроитьwebpack.config.jsсерединаscriptsварианты, как показано ниже

// package.json
{
  // ...
  "scripts": {
    "dev": "webpack-dev-server --devtool eval --progress --colors",
    "deploy": "NODE_ENV=production webpack -p"
  },
  // ...
}

Demo01: Входной файл

Файл входа используется Webpack для его чтения и сборки.bundle.js
Например ниже,main.jsявляется входным файлом

// main.js
document.write('<h1>Hello World</h1>');

index.html

<html>
  <body>
    <script type="text/javascript" src="bundle.js"></script>
  </body>
</html>

Веб-пакет отwebpack.config.jsстроитьbundle.js

// webpack.config.js
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  }
};

Выполните следующую команду и получите доступhttp://127.0.0.1:8080

$ cd demo01
$ npm run dev

Demo02: файлы с несколькими записями

WebpackПозволяет существовать нескольким файлам ввода, что полезно в многостраничных приложениях, где каждая страница имеет отдельный файл ввода.

// main1.js
document.write('<h1>Hello World</h1>');

// main2.js
document.write('<h2>Hello Webpack</h2>');

index.html

<html>
  <body>
    <script src="bundle1.js"></script>
    <script src="bundle2.js"></script>
  </body>
</html>

webpack.config.js

module.exports = {
  entry: {
    bundle1: './main1.js',
    bundle2: './main2.js'
  },
  output: {
    filename: '[name].js'
  }
};

Demo03:Babel-loader

Загрузчики — это препроцессоры, которые преобразуют некоторые файлы ресурсов в вашем приложении перед процессом сборки Webpack.
Например, Babel-loader может конвертировать файлы JSX/ES6 в обычные файлы JS, после чего Webpack может начать их сборку. В официальной документации веб-пакета есть список загрузчиков.адрес
main.jsxэто файл JSX

// main.jsx
const React = require('react');
const ReactDOM = require('react-dom');

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.querySelector('#wrapper')
);

index.html

<html>
  <body>
    <div id="wrapper"></div>
    <script src="bundle.js"></script>
  </body>
</html>

webpack.config.js

module.exports = {
  entry: './main.jsx',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['es2015', 'react']
          }
        }
      }
    ]
  }
};

В приведенном выше коде два плагина babel-loader, babel-preset-es2015 и babel-preset-react, необходимы для преобразования ES6 и React (перевод: теперь устарело,Подробности)

Demo04:CSS-loader

Webpack позволяет включать CSS в файлы JS и требует, чтобы CSS-загрузчик обрабатывал эти CSS.
main.js

require('./app.css');

app.css

body {
  background-color: blue;
}

index.html

<html>
  <head>
    <script type="text/javascript" src="bundle.js"></script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

webpack.config.js

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules:[
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      },
    ]
  }
};

Уведомление! Файлы CSS должны быть преобразованы с помощью двух загрузчиков. CSS-загрузчик используется для чтения файлов CSS для преобразования, другой Style-загрузчик используется для вставки в HTML<style>Этикетка.
Затем откройте сервер

$ cd demo04
$ npm run dev

Фактически, Webpack вставляет содержимое файлов CSS прямо вindex.html

<head>
  <script type="text/javascript" src="bundle.js"></script>
  <style type="text/css">
    body {
      background-color: blue;
    }
  </style>
</head>

Demo5: Image loader

Webpack может включать изображения в файлы JS
main.js

var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1);

var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);

index.html

<html>
  <body>
    <script type="text/javascript" src="bundle.js"></script>
  </body>
</html>

webpack.config.js

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules:[
      {
        test: /\.(png|jpg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192
            }
          }
        ]
      }
    ]
  }
};

url-loaderПреобразование файлов изображений в<img>Тег, если размер изображения составляет 8192 байта, он будет преобразован в URL-адрес данных (перевод: изображение будет закодировано в Base64, что уменьшит количество запросов), в противном случае оно будет преобразовано в обычный URL-адрес файла.

<img src="data:image/png;base64,iVBOR...uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">

Demo06:CSS Module

css-loader?modules(Параметром запроса являются модули) Можно использовать модуль CSS, модуль CSS обеспечивает локальную область действия CSS в вашем файловом модуле JS, вы также можете использовать:global(selector)Сделайте CSS глобальным.
index.html

<html>
<body>
  <h1 class="h1">Hello World</h1>
  <h2 class="h2">Hello Webpack</h2>
  <div id="example"></div>
  <script src="./bundle.js"></script>
</body>
</html>

app.css

/* local scope */
.h1 {
  color:red;
}

/* global scope */
:global(.h2) {
  color: blue;
}

main.jsx

var React = require('react');
var ReactDOM = require('react-dom');
var style = require('./app.css');

ReactDOM.render(
  <div>
    <h1 className={style.h1}>Hello World</h1>
    <h2 className="h2">Hello Webpack</h2>
  </div>,
  document.getElementById('example')
);

webpack.config.js

module.exports = {
  entry: './main.jsx',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules:[
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['es2015', 'react']
          }
        }
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader'
          },
          {
             loader: 'css-loader',
             options: {
               modules: true
             }
          }
        ]
      }
    ]
  }
};

доступ http://127.0.0.1:8080увидит толькоh1красный, потому что его CSS имеет локальную область видимости, тогдаh2Он весь синий, потому что это глобальная область.

Demo07:UglifyJs Plugin

Webpack с системой плагинов для расширения его функций. Например,UglifyJs Plugin, который используется для сжатия кода JS, чтобы уменьшить размер файлов JS.
main.js

var longVariableName = 'Hello';
longVariableName += ' World';
document.write('<h1>' + longVariableName + '</h1>');

index.html

<html>
<body>
  <script src="bundle.js"></script>
</body>
</html>

webpack.config.js

var webpack = require('webpack');
var UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new UglifyJsPlugin()
  ]
};

После доступа к серверу вы можете увидетьmain.jsСведен к следующему коду:

var o="Hello";o+=" World",document.write("<h1>"+o+"</h1>")

(перевод: находится вbundle.jsПоследние несколько кодов того, вот эти коды)

Demo08: Плагин HTML Webpack и плагин Open Browser Webpack

Эта демонстрация используется для демонстрации того, как загружать сторонние плагины.
html-webpack-pluginможет создать для васindex.html,open-browser-webpack-pluginВозможность открывать новую вкладку браузера при загрузке Webpack
main.js

document.write('<h1>Hello World</h1>');

webpack.config.js

var HtmlwebpackPlugin = require('html-webpack-plugin');
var OpenBrowserPlugin = require('open-browser-webpack-plugin');

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlwebpackPlugin({
      title: 'Webpack-demos',
      filename: 'index.html'
    }),
    new OpenBrowserPlugin({
      url: 'http://localhost:8080'
    })
  ]
};

Теперь вам не нужно вручную создаватьindex.htmlНет необходимости открывать браузер вручную.

Demo09: Флаги среды

Используйте переменные среды, чтобы сделать код только при разработке среды.
main.js

document.write('<h1>Hello World</h1>');

if (__DEV__) {
  document.write(new Date());
}

index.html

<html>
<body>
  <script src="bundle.js"></script>
</body>
</html>

webpack.config.js

var webpack = require('webpack');

var devFlagPlugin = new webpack.DefinePlugin({
  __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
});

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [devFlagPlugin]
};

Теперь передайте переменные среды в Webpack. Открытьdemo09/package.json, находится следующим образомscriptsОпции

// package.json
{
  // ...
  "scripts": {
    "dev": "cross-env DEBUG=true webpack-dev-server --open",
  },
  // ...
}

Demo10: Разделение кода

В большом веб-приложении помещать весь код в один файл очень неэффективно. Webpack позволяет разбивать большие файлы JS на куски. В частности, некоторые блоки кода загружаются по запросу, если они нужны только в определенных ситуациях.
Webpack используетrequire.ensureопределить точку разделения

// main.js
require.ensure(['./a'], function (require) {
  var content = require('./a');             
  document.open();
  document.write('<h1>' + content + '</h1>');
  document.close();
});

require.ensureсказать вебпак./a,jsнужно отbundle.jsвыделен в виде отдельного файла фрагмента

// a.js
module.exports = 'Hello World';

Теперь Webpack заботится о зависимостях, выходных файлах, вещах во время выполнения. Вам не нужно класть лишние вещиindex.htmlа такжеwebpack.config.jsсередина
index.html

<html>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>


webpack.config.js

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  }
};

После доступа к серверу вы не почувствуете никакой разницы. На самом деле, Webpack будет строитьmain.jsа такжеa.jsв другой блок(bundle.jsа также0.bundle.js), то изbundle.jsнагрузка по требованию0.bundle.js

Demo11: разделение кода в пакетном загрузчике

Еще один способ расщепления кодаbundle-loader

// main.js

// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader!./a.js');

// To wait until a.js is available (and get the exports)
//  you need to async wait for it.
load(function(file) {
  document.open();
  document.write('<h1>' + file + '</h1>');
  document.close();
});

require('bundle-loader!./a.js')Скажите WebPack нагрузки с других блоковa.js
Сейчасmain.jsпостроить какbundle.js,a.jsпостроить как0.bundle.js

Demo12: Общий блок

В нескольких сценариях JS есть общие блоки, черезCommonsChunkPluginВы можете извлекать общие части из разных файлов, что очень полезно для кэширования браузера для экономии полосы пропускания.

// main1.jsx
var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h1>Hello World</h1>,
  document.getElementById('a')
);

// main2.jsx
var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h2>Hello Webpack</h2>,
  document.getElementById('b')
);

index.html

<html>
  <body>
    <div id="a"></div>
    <div id="b"></div>
    <script src="commons.js"></script>
    <script src="bundle1.js"></script>
    <script src="bundle2.js"></script>
  </body>
</html>

надcommons.jsдаmain1.jsxа такжеmain2.jsxобщая часть. Как ты думаешь,commons.jsвключатьreactа такжеreact-dom
Webpack.config.js

var webpack = require('webpack');

module.exports = {
  entry: {
    bundle1: './main1.jsx',
    bundle2: './main2.jsx'
  },
  output: {
    filename: '[name].js'
  },
  module: {
    rules:[
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['es2015', 'react']
          }
        }
      },
    ]
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: "commons",
      // (the commons chunk name)

      filename: "commons.js",
      // (the filename of the commons chunk)
    })
  ]
}

Demo13:Vendor chunk

пройти черезCommonsChunkPlugin, вы можете извлекать официальные библиотеки из JS-скриптов в отдельные файлы
main.js

var $ = require('jquery');
$('h1').text('Hello World');

index.html

<html>
  <body>
    <h1></h1>
    <script src="vendor.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>

webpack.config.js

var webpack = require('webpack');

module.exports = {
  entry: {
    app: './main.js',
    vendor: ['jquery'],
  },
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      filename: 'vendor.js'
    })
  ]
};

В приведенном выше кодеentry.vendor:['jquery']скажи вебпак,jqueryдолжен быть включен в общий блокvendor.jsсередина.
Если вы хотите, чтобы модуль как глобальная переменная использовался в разных модулях, например, не в каждом файлеrequire('jquery'), но пусть$илиjQueryВ качестве глобальной переменной вам нужно использоватьProvidePlugin, который может автоматически загружать модули без необходимости ходить куда угодноimportилиrequire

// main.js
$('h1').text('Hello World');


// webpack.config.js
var webpack = require('webpack');

module.exports = {
  entry: {
    app: './main.js'
  },
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery'
    })
  ]
};

Конечно, в Demo13 вам нужно загрузить его глобально самостоятельно.jquery.js

Демонстрация 14: предоставление глобальных переменных

Если вы хотите использовать некоторые глобальные переменные, не включая их в пакет webpack, вы можете использовать файл webpack.config.jsexternalsполе
Например, у нас естьdata.js

// data.js
var data = 'Hello World';

index.html

<html>
  <body>
    <script src="data.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>

Обратите внимание, что Webpack будет собирать толькоbundle.js, вместо построенияdata.js
мы можем поставитьdataкак глобальная переменная

// webpack.config.js
module.exports = {
  entry: './main.jsx',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules:[
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['es2015', 'react']
          }
        }
      },
    ]
  },
  externals: {
    // require('data') is external and available
    //  on the global var data
    'data': 'data'
  }
};

В этот момент вы можетеrequire('data')Как переменная модуля, это на самом деле глобальная переменная

// main.jsx
var data = require('data');
var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h1>{data}</h1>,
  document.body
);

так же может бытьreactа такжеreact-domположить вexternals, что значительно сокращает сборкуbundle.jsвремя и размер файла

Demo15:React router

В этой демонстрации используется Webpack для создания официального примера маршрутизатора React.
Сначала представьте небольшое приложение с панелью управления, почтовым ящиком, календарем.

+---------------------------------------------------------+
| +---------+ +-------+ +--------+                        |
| |Dashboard| | Inbox | |Calendar|      Logged in as Jane |
| +---------+ +-------+ +--------+                        |
+---------------------------------------------------------+
|                                                         |
|                        Dashboard                        |
|                                                         |
|                                                         |
|   +---------------------+    +----------------------+   |
|   |                     |    |                      |   |
|   | +              +    |    +--------->            |   |
|   | |              |    |    |                      |   |
|   | |   +          |    |    +------------->        |   |
|   | |   |    +     |    |    |                      |   |
|   | |   |    |     |    |    |                      |   |
|   +-+---+----+-----+----+    +----------------------+   |
|                                                         |
+---------------------------------------------------------+

webpack.config.js

module.exports = {
  entry: './index.js',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      },
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['es2015', 'react']
          }
        }
      },
    ]
  }
};

index.js

import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Switch, Route, Link } from 'react-router-dom';

import './app.css';

class App extends React.Component {
  render() {
    return (
      <div>
        <header>
          <ul>
            <li><Link to="/app">Dashboard</Link></li>
            <li><Link to="/inbox">Inbox</Link></li>
            <li><Link to="/calendar">Calendar</Link></li>
          </ul>
          Logged in as Jane
        </header>
        <main>
          <Switch>
            <Route exact path="/" component={Dashboard}/>
            <Route path="/app" component={Dashboard}/>
            <Route path="/inbox" component={Inbox}/>
            <Route path="/calendar" component={Calendar}/>
            <Route path="*" component={Dashboard}/>
          </Switch>
        </main>
      </div>
    );
  }
};

class Dashboard extends React.Component {
  render() {
    return (
      <div>
        <p>Dashboard</p>
      </div>
    );
  }
};

class Inbox extends React.Component {
  render() {
    return (
      <div>
        <p>Inbox</p>
      </div>
    );
  }
};

class Calendar extends React.Component {
  render() {
    return (
      <div>
        <p>Calendar</p>
      </div>
    );
  }
};

render((
  <BrowserRouter>
    <Route path="/" component={App} />
  </BrowserRouter>
), document.querySelector('#app'));

index.html

<html>
  <body>
    <div id="app"></div>
    <script src="/bundle.js"></script>
  </body>
</htmL>

затем посетитеhttp://127.0.0.1:8080