English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Подробное описание разработки многостраничного сайта с использованием webpack + express

После изучения продвинутых уроков webpack, я считаю, что он создан специально для одностраничных приложений, например, webpack+react, webpack+vue и т.д., которые могут решить проблемы загрузки и打包 различных ресурсов. Даже css может быть打包 в js и динамически добавлен в документ DOM.

Если мы хотим создать многостраничный обычный веб-сайт, можно ли отделить css и загрузку js в виде модулей?

Адрес проекта:webpackDemo_jb51.rar

Инициализация проекта, установка зависимостей

package.json

"devDependencies": {
  "css-loader": "^0.23.1",
  "extract-text-webpack-plugin": "^1.0.1",
  "file-loader": "^0.8.5",
  "html-loader": "^0.4.3",
  "html-webpack-plugin": "^2.9.0",
  "jquery": "^1.12.0",
  "less": "^2.6.0",
  "less-loader": "^2.2.2",
  "sass-loader": "^4.0.2",
  "style-loader": "^0.13.0",
  "url-loader": "^0.5.7",
  "webpack": "^1.12.13",
  "webpack-dev-server": "^1.14.1"
}

Структура каталога (я использую фреймворк express, другие в зависимости от личных потребностей)

- webpackDemo
  - src        #каталог разработки кода
    - css      #каталог css, организованный по уровням страницы (модуля), общего использования и сторонних библиотек
      + page
      + common
      + lib
    - js       #JS скрипт, организованный по page, components
      + page
      + components
    + template      # шаблоны HTML
  - node_modules    # используемые модули nodejs
  - public            # статические ресурсы express
    - dist            # каталог вывода webpack компиляции, не нужно создавать каталог, webpack автоматически создаст его по конфигурации
      + css        
      + js
    + img      # ресурсы изображений
  + view            # статические ресурсы express (вывод webpack компиляции в папку view)
  package.json      # конфигурация проекта
  webpack.config.js  # конфигурация webpack

Разработка страницы

Создайте файл index.js в папке src/js/page и файл index.html в папке src/view. Имя входного JS файла и шаблона должны соответствовать.

содержимое index.html таково:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Главная страница</title>
  <!--
    Описание: В head больше не нужно вносить css и favicon, webpack автоматически включит их по мере необходимости или создаст тег style.
  -->
</head>
<body>
  <!--
    Описание: В body не нужно вносить отдельные файлы JS, webpack автоматически включит их по мере необходимости или создаст тег script, а также создаст соответствующий хеш.
  -->
</body>
</html>

Это такой простой шаблон HTML, не нужно вносить CSS и JS, достаточно打包 через webpack, и он автоматически поможет нам включить.

содержимое index.js таково:

// Включение css
require("../../css/lib/base.css");
require("../../css/page/index.scss");
$('body').append('<p class="text">index</p>');

page1.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>page1</title>
</head>
<body>
</body>
</html>

page1.js:

// Включение css
require("../../css/lib/base.css");
require("../../css/page/page1.less");
$('body').html('page1');

конфигурация webpack (я использую фреймворк express, другие в зависимости от ваших потребностей)

var path = require('path');
var webpack = require('webpack');
/*
plugin extract-text-webpack-plugin
С его помощью можно извлечь ваши стили в отдельные файлы css
Теперь мама больше не worries, что стили будут打包 в файлы js
 */
var ExtractTextPlugin = require('extract-text-webpack-plugin');
/*
html-webpack-plugin плагин,极为重要,webpack中生成HTML的插件
Конкретно можно проверить здесь https://www.npmjs.com/package/html-webpack-plugin
 */
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: { // Настройка входного файла, указывайте столько, сколько нужно
    index: './src/js/page/index.js'
    page1: './src/js/page/page1.js'
  },
  output: { 
    path: path.join(__dirname, './public/dist/'), //输出目录的配置,模板、样式、脚本、图片等资源的路径配置都相对于它
    publicPath: '/dist/',        // путь сервера для шаблонов, стилей, скриптов, изображений и других ресурсов
    filename: 'js/[name].js',      // конфигурация генерации основного js для каждой страницы
    chunkFilename: 'js/[id].chunk.js'  //chunk生成的配置
  },
  module: {
    loaders: [ //加载器,关于各个加载器的参数配置,可自行搜索之。
      {
        test: /\.css$/,
        //配置css的抽取器、加载器。'-loader'可以省去
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader') 
      }, {
        test: /\.less$/,
        //配置less的抽取器、加载器。中间!有必要解释一下,
        //根据从右到左的顺序依次调用less、css加载器,前一个的输出是后一个的输入
        //你也可以开发自己的loader哟。有关loader的写法可自行谷歌之。
        loader: ExtractTextPlugin.extract('css!less')
      }, {
        test: /\.scss$/
        //配置scss的抽取器、加载器。中间!有必要解释一下,
        //根据从右到左的顺序依次调用scss、css加载器,前一个的输出是后一个的输入
        //你也可以开发自己的loader哟。有关loader的写法可自行谷歌之。
        loader: ExtractTextPlugin.extract('css!scss')
      }, {
        //html模板加载器,可以处理引用的静态资源,默认配置参数attrs=img:src,处理图片的src引用的资源
        //比如你配置,attrs=img:src img:data-src就可以一并处理data-src引用的资源了,就像下面这样
        test: /\.html$/,
        loader: "html?attrs=img:src img:data-src"
      }, {
        //文件加载器,处理文件静态资源
        test: /\.(woff|woff2|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        loader: 'file-loader?name=./fonts/[name].[ext]'
      }, {
        //图片加载器,雷同file-loader,更适合图片,可以将较小的图片转成base64,减少http请求
        //如下配置,将小于8192byte的图片转成base64码
        test: /\.(png|jpg|gif)$/
        loader: 'url-loader?limit=8192&name=./img/[hash].[ext]'
      }
    }]
  },
  plugins: [
    new webpack.ProvidePlugin({ //加载jq
      $: 'jquery'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'commons', // 将公共模块提取,生成名为`commons`的chunk
      chunks: ['index','page1'], // извлекать общие части этих модулей
      minChunks: 2 // извлекать по крайней мере 2 модуля, имеющих общие части
    }),
    new ExtractTextPlugin('css/[name].css'), //单独使用link标签加载css并设置路径,相对于output配置中的publickPath
    // HtmlWebpackPlugin, конфигурации шаблона генерации, для каждого шаблона страницы пишется несколько
    new HtmlWebpackPlugin({ // вставка css/js и т.д. на основе шаблона для создания конечного HTML
      favicon: './src/favicon.ico', // путь к favicon, включается через webpack и может генерировать hash-значение
      filename: '../../views/index.html', // путь сохранения созданного html, относительно path
      template: './src/template/index.html', // путь к шаблону html
      inject: 'body', // положение вставки js, true/'head'/'body'/false
      hash: true, // генерировать хэш-значения для статических ресурсов
      chunks: ['commons', 'index'],// необходимые чanky, при отсутствии конфигурации будут загружены ресурсы всех страниц
      minify: { // сжатие файлов HTML  
        removeComments: true, // удалять комментарии в HTML
        collapseWhitespace: false // удалять пробельные символы и переводы строк
      }
    }),
    new HtmlWebpackPlugin({ // вставка css/js и т.д. на основе шаблона для создания конечного HTML
      favicon: './src/favicon.ico', // путь к favicon, включается через webpack и может генерировать hash-значение
      filename: '../../views/page1.html', // путь сохранения созданного html, относительно path
      template: './src/template/page1.html', // путь к шаблону html
      inject: true, // положение вставки js, true/'head'/'body'/false
      hash: true, // генерировать хэш-значения для статических ресурсов
      chunks: ['commons', 'list'],// необходимые чанки, при отсутствии конфигурации будут загружены ресурсы всех страниц
      minify: { // сжатие файлов HTML  
        removeComments: true, // удалять комментарии в HTML
        collapseWhitespace: false // удалять пробельные символы и переводы строк
      }
    })
    // new webpack.HotModuleReplacementPlugin() // загрузка горячего модуля
  ],
  // использование webpack-dev-server, чтобы повысить эффективность разработки
  // devServer: {
  // contentBase: './',
  // host: 'localhost',
  // port: 9090, // по умолчанию 8080
  // inline: true, // можно отслеживать изменения в js
  //   hot: true, //горячий запуск
  // }
};

Теперь, после выполнения всех этих настроек, выполните команду webpack для завершения процесса компиляции проекта.

Хэш: e6219853995506fd132a
Версия: webpack 1.14.0
Время: 1338ms
        Активный    Размер Части        Названия Части
     js/index.js 457 bytes    0 [выпущен] index
     js/page1.js 392 bytes    1 [выпущен] page1
    js/commons.js   306 kB    2 [выпущен] commons
    css/index.css  62 bytes    0 [выпущен] index
    css/page1.css  62 bytes    1 [выпущен] page1
   css/commons.css 803 bytes    2 [выпущен] commons
     favicon.ico  1.15 kB     [выпущен]
../../view/index.html 496 bytes     [выпущен]
../../view/page1.html 499 bytes     [выпущен]
  [0] ./src/js/page/index.js 170 bytes {0} [скомпилирован]
  [0] ./src/js/page/page1.js 106 bytes {1} [скомпилирован]
  + 7 скрытых модулей
Child html-webpack-plugin для "../../view/page1.html":
    + 1 скрытых модуля
Child html-webpack-plugin для "../../view/index.html":
    + 1 скрытых модуля
Child extract-text-webpack-plugin:
    + 2 скрытых модуля
Child extract-text-webpack-plugin:
    + 2 скрытых модуля
Child extract-text-webpack-plugin:
    + 2 скрытых модуля

В этот момент перейдите в папку views, чтобы проверить созданный файл index.html, например:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Главная страница</title>  
<link rel="shortcut icon" href="/dist/favicon.ico" rel="external nofollow" ><link href="/dist/css/commons.css?e6219853995506fd132a" rel="external nofollow" rel="stylesheet"><link href="/dist/css/index.css?e6219853995506fd132a" rel="external nofollow" rel="stylesheet"></head>
<body>
  <script type="text/javascript" src="/dist/js/commons.js?e6219853995506fd132a"></script><script type="text/javascript" src="/dist/js/index.js?e6219853995506fd132a"></script></body>
</html>

Как видно, созданные файлы, кроме сохранения содержимого исходного шаблона, также автоматически добавляют необходимые файлы CSS и JS, а также favicon, а также добавляют соответствующие значения hash.

Два вопроса

  1. Как webpack автоматически обнаруживает файлы entry и выполняет соответствующие настройки шаблонов
  2. Как напрямую обрабатывать автоматическое включение стилей и скриптов
var path = require('path');
var webpack = require('webpack');
var glob = require('glob');
/*
plugin extract-text-webpack-plugin
С его помощью можно извлечь ваши стили в отдельные файлы css
Теперь мама больше не worries, что стили будут打包 в файлы js
 */
var ExtractTextPlugin = require('extract-text-webpack-plugin');
/*
html-webpack-plugin плагин,极为重要,webpack中生成HTML的插件
Конкретно можно проверить здесь https://www.npmjs.com/package/html-webpack-plugin
 */
var HtmlWebpackPlugin = require('html-webpack-plugin');
/**
 * извлекает общие модули, создавая chunk с именем `commons`
 */
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
// сжатие
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
// определяем режим разработки
var debug = process.env.NODE_ENV !== 'production';
var getEntry = function(globPath, pathDir) {
  var files = glob.sync(globPath);
  var entries = {},
    entry, dirname, basename, pathname, extname;
  for (var i = 0; i < files.length; i++) {
    entry = files[i];
    dirname = path.dirname(entry);  // директория файла
    extname = path.extname(entry);  // расширение файла
    basename = path.basename(entry, extname); // имя файла
    pathname = path.join(dirname, basename);
    pathname = pathDir ? pathname.replace(new RegExp('^' + pathDir), '') : pathname;
    entries[pathname] = ['./' + entry]; // так пишется в системе osx, в win7 entries[basename]
  }
  console.log(entries);
  return entries;
}
// вход (получен через метод getEntry все файлы входа страниц)
var entries = getEntry('src/js/page/**/*.js', 'src/js/page/');
// извлечь общие части модулей, полученные из entries, файловые имена
var chunks = Object.keys(entries);
// шаблоны страниц (полученные через метод getEntry)
var pages = Object.keys(getEntry('src/template/**/*.html', 'src/template/'));
console.log(pages)
var config = {
  entry: entries,
  output: {
    path: path.join(__dirname, './public/dist/'),// конфигурация выходного каталога, путь для шаблонов, стилей, скриптов, изображений и других ресурсов относительно него
    publicPath: '/dist/',        // путь сервера для шаблонов, стилей, скриптов, изображений и других ресурсов
    filename: 'js/[name].js',      // конфигурация генерации основного js для каждой страницы
    chunkFilename: 'js/[id].chunk.js?[chunkhash]'  // конфигурация генерации chunk
  },
  module: {
    loaders: [ // загрузчики
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style', 'css')
      }, {
        test: /\.less$/,
        loader: ExtractTextPlugin.extract('css!less')
      }, {
        test: /\.html$/,
        loader: "html?-minimize"  // избегать сжатия html, https://github.com/webpack/html-loader/issues/50
      }, {
        test: /\.(woff|woff2|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        loader: 'file-loader?name=fonts/[name].[ext]'
      }, {
        test: /\.(png|jpe?g|gif)$/,
        loader: 'url-loader?limit=8192&name=imgs/[name]-[hash].[ext]'
      }
    }]
  },
  plugins: [
    new webpack.ProvidePlugin({ //加载jq
      $: 'jquery'
    }),
    new CommonsChunkPlugin({
      name: 'commons', // 将公共模块提取,生成名为`commons`的chunk
      chunks: chunks,
      minChunks: chunks.length // 提取所有entry共同依赖的模块
    }),
    new ExtractTextPlugin('css/[name].css'), //单独使用link标签加载css并设置路径,相对于output配置中的publickPath
    debug ? function() {} : new UglifyJsPlugin({ //压缩代码
      compress: {
        warnings: false
      },
      except: ['$super', '$', 'exports', 'require'] //排除关键字
    }),
  }]
};
pages.forEach(function(pathname) {
  var conf = {
    filename: '../../views/' + pathname + '.html', //生成的html存放路径,相对于path
    template: 'src/template/' + pathname + '.html', //html模板路径
    inject: false, //js插入的位置,true/'head'/'body'/false
    /*
    * 压缩这块,调用了html-minify,会导致压缩时候的很多html语法检查问题,
    * 如在html标签属性上使用{{...}}表达式,所以很多情况下并不需要在此配置压缩项,
    * 另外,UglifyJsPlugin会在压缩代码的时候连同html一起压缩。
    * 为避免压缩html,需要在html-loader上配置'html?-minimize',见loaders中html-loader的配置。
     */
    // minify: { //压缩HTML文件
    // removeComments: true, //移除HTML中的注释
    // collapseWhitespace: false //删除空白符与换行符
    // }
  };
  if (pathname in config.entry) {
    favicon: './src/favicon.ico', // путь к favicon, включается через webpack и может генерировать hash-значение
    conf.inject = 'body';
    conf.chunks = ['commons', pathname];
    conf.hash = true;
  }
  config.plugins.push(new HtmlWebpackPlugin(conf));
});
module.exports = config;  

Следующий код очень похож на предыдущий, но по сути разница в том, что все соответствующие файлы помещаются в один объект, и таким образом достигается эффект автоматического включения!

Все это конфигурации для системы mac osx, путь в win7 может отличаться

glob: различие в том, что здесь:

но требуют в конечном итоге

entries:
 {
 index: [ './src/template/index.js' ],
 page1: [ './src/template/page1.js' ]
 }
pages:
 [ 'index', 'page1' ]

Следует вносить соответствующие изменения в зависимости от конфигурации вашего компьютера

Вот весь контент статьи, надеюсь, он поможет вам в изучении, также希望大家多多支持呐喊教程。

Заявление: содержимое этой статьи взято из интернета, авторские права принадлежат соответствующему автору, контент был предложен и загружен пользователями Интернета, сайт не имеет права собственности, не был обработан вручную, и не несет ответственности за соответствующие юридические вопросы. Если вы обнаружите подозрительное содержимое, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (при отправке письма замените # на @) для сообщения о нарушении авторских прав,并提供 соответствующие доказательства. Если обнаружено нарушение, сайт немедленно удаляет подозрительное содержимое.

Рекомендуем также