Создайте с нуля простую среду разработки vue на основе веб-пакетов.

Vue.js Webpack

Прошло 8102 года, а я до сих пор говорю о настройке вебпака.Ну поздновато. Более того, проекты, сгенерированные на основе vue-cli или create-react-app, уже настроили для нас webpack в один клик, что, похоже, не требует от нас глубокого понимания.

Однако для того, чтобы узнать и понять, какие болевые точки веб-пакет решает во внешнем интерфейсе, все же необходимо создать простую среду разработки с нуля. Конфигурация веб-пакета в этой статье относится к предоставлению vue-cli.webpack-simpleШаблон, который также является самой простой конфигурацией веб-пакета в vue-cli, очень подходит для обучения с нуля.

Примечание. Веб-пакет для этой статьи основан на версии 3.10.0.

скачать демо-код

Установить веб-пакет

npm i webpack -g

Инициализация проекта

Создайте новую папку vue-webpack-simple

Новый пакет.json

npm init -y

Установите vue webpack webpack-dev-сервер

npm i vue --save
npm i webpack webpack-dev-server --save-dev

Создайте новый index.html в корневом каталоге

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
</body>
</html>

Создайте новый файл webpack.config.js в корневом каталоге.

var path = require('path');
var webpack = require('webpack');

module.exports = {};

Создайте новую папку src и создайте новый файл main.js в папке src.

Текущая структура всего проекта выглядит следующим образом:

модульность js

До появления ES6 в js не было единой модульной системы. На стороне сервера используется спецификация CommonJS, а на стороне браузера — две спецификации: AMD и CMD.

Идея webpack заключается в том, что все является модулем.Официальная рекомендация — использовать спецификацию commonJS, которая позволяет нам использовать модульный метод написания commonJS на стороне браузера.

module.exports = {}

Создайте новый util.js в каталоге src

module.exports = function say() {
    console.log('hello world');
}

main.js

var say = require('./util');
say();

Изменить webpack.config.js

var path = require('path');
var webpack = require('webpack');

module.exports = {
    entry: './src/main.js', // 项目的入口文件,webpack会从main.js开始,把所有依赖的js都加载打包
    output: {
        path: path.resolve(__dirname, './dist'), // 项目的打包文件路径
        publicPath: '/dist/', // 通过devServer访问路径
        filename: 'build.js' // 打包后的文件名
    },
    devServer: {
        historyApiFallback: true,
        overlay: true
    }
};

Изменить package.json

"scripts": {
    "dev": "webpack-dev-server --open --hot",
    "build": "webpack --progress --hide-modules"
  },

Примечание: webpack-dev-server автоматически запустит веб-сервер статического ресурса --параметр hot означает запуск горячего обновления

Измените index.html и импортируйте упакованный файл.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script src="/dist/build.js"></script>
</body>

</html>

бегать

npm run dev

Вы можете найти страницу, автоматически открываемую браузером, просмотреть консоль, естьhello worldразыгрывать

Мы модифицируем util.js по желанию, и мы можем обнаружить, что браузер будет автоматически обновляться, что очень удобно.

файл bundle.js, если мы хотим посмотреть на пакет, запустите

npm run build

Вы можете видеть, что создается каталог dist, который содержит упакованный пакет bundle.js.

webpack не поддерживает транскодирование es6 по умолчанию, ноimport exportЭти два синтаксиса поддерживаются отдельно. Таким образом, мы можем переписать предыдущую модульную запись

util.js

export default function say() {
    console.log('hello world ');
}

main.js

import say from './util';

say();

Представьте вью

Давайте попробуем представить vue (в настоящее время не рассматриваем отдельный файл .vue)

main.js

import Vue from 'vue';

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
});

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        {{message}}
    </div>
    <script src="/dist/build.js"></script>
    
</body>

</html>

Также обратите внимание, что: чтобы изменить файл webpack.config.js

var path = require('path');
var webpack = require('webpack');

module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, './dist'),
        publicPath: '/dist/',
        filename: 'build.js'
    },
    devServer: {
        historyApiFallback: true,
        overlay: true
    },
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    }
};

Перезапустите npm run dev, вы увидите, что страница отображается нормально.Hello World

Внедрить scss и css

По умолчанию webpack поддерживает только модульность js.Если вам нужно импортировать другие файлы как модули, вам нужен соответствующий парсер загрузчика

npm i node-sass css-loader vue-style-loader sass-loader --save-dev

webpack.config.js

var path = require('path');
var webpack = require('webpack');

module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, './dist'),
        publicPath: '/dist/',
        filename: 'build.js'
    },
    devServer: {
        historyApiFallback: true,
        overlay: true
    },
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader',
                    'css-loader'
                ],
            }
        ]
    }
};

объяснять:

{
    test: /\.css$/,
    use: [
        'vue-style-loader',
        'css-loader'
    ],
}

Этот код означает: сопоставьте файл с суффиксом css, а затем используйте css-loader и vue-style-loader для его анализа соответственно. Порядок выполнения парсера снизу вверх (сначала css-loader, а затем vue-style-loader)

Примечание. Поскольку здесь мы используем разработку vue, мы используем vue-style-loader и используем style-loader в других случаях.

css-loader позволяет нам импортировать css модульным способом, vue-style-loader вставит импортированный css в тег стиля на странице html.

Для внедрения scss используется тот же метод записи конфигурации:

module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader',
                    'css-loader'
                ],
            },
            {
                test: /\.scss$/,
                use: [
                    'vue-style-loader',
                    'css-loader',
                    'sass-loader'
                ],
            },
            {
                test: /\.sass$/,
                use: [
                    'vue-style-loader',
                    'css-loader',
                    'sass-loader?indentedSyntax'
                ],
            }]
    }

Давайте попробуем сейчас Создайте новый каталог стилей в каталоге src и создайте новый файл common.scss в каталоге стилей.

body {
    background: #fed;
}

main.js

import './style/common.scss';

Найдены полезные стили css

Транскодирование с помощью Babel

Синтаксис ES6 все еще не поддерживается большинством браузеров, bable может перекодировать ES6 в синтаксис ES5, так что мы можем смело использовать последние функции в проекте.

npm i babel-core babel-loader babel-preset-env babel-preset-stage-3 --save-dev

Создайте новый файл .babelrc в корневом каталоге проекта.

{
  "presets": [
    ["env", { "modules": false }],
    "stage-3"
  ]
}

webpack.config.js добавить загрузчик

{
    test: /\.js$/,
    loader: 'babel-loader',
    exclude: /node_modules/
}

exclude означает игнорирование файлов в папке node_modules без перекодирования.

Теперь давайте попробуем асинхронный синтаксис ожидания util.js

export default function getData() {
    return new Promise((resolve, reject) => {
        resolve('ok');
    })
}

main.js

import getData from './util';
import Vue from 'vue';

import './style/common.scss';

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  },
  methods: {
    async fetchData() {
      const data = await getData();
      this.message = data;
    }
  },
  created() {
    this.fetchData();
  }
});

Тогда консоль сообщит об ошибкеregeneratorRuntime is not defined, потому что мы не устанавливалиbabel-polyfill

npm i babel-polyfill --save-dev

Затем измените запись webpack.config.js

entry: ['babel-polyfill', './src/main.js'],

Re-npm run dev, вы можете обнаружить, что он работает нормально

Внедрение ресурсов изображений

Представьте изображения как модули

npm i file-loader --save-dev

webpack.config.js добавить загрузчик

{
    test: /\.(png|jpg|gif|svg)$/,
    loader: 'file-loader',
    options: {
        name: '[name].[ext]?[hash]'
    }
}

Создайте новый каталог img в каталоге src и сохраните изображение logo.png

Изменить main.js

import getData from './util';
import Vue from 'vue';

import './style/common.scss';


Vue.component('my-component', {
  template: '<img :src="url" />',
  data() {
    return {
      url: require('./img/logo.png')
    }
  }
})

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue !'
  },
  methods: {
    async fetchData() {
      const data = await getData();
      this.message = data;
    }
  },
  created() {
    this.fetchData()
  }
});

Изменить index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        {{message}}
        <my-component/>
    </div>
    <script src="/dist/build.js"></script>
    
</body>

</html>

Как видите, изображение также загружается корректно.

компонент одного файла

В предыдущем примере мы использовали Vue.component для определения глобального компонента. В реальных проектах более рекомендуется использовать однофайловые компоненты

npm i vue-loader vue-template-compiler --save-dev

добавить загрузчик

{
    test: /\.vue$/,
    loader: 'vue-loader',
    options: {
        loaders: {
            'scss': [
                'vue-style-loader',
                'css-loader',
                'sass-loader'
            ],
            'sass': [
                'vue-style-loader',
                'css-loader',
                'sass-loader?indentedSyntax'
            ]
        }
    }
}

Создайте новый App.vue в каталоге src.

<template>
  <div id="app">
    <h1>{{ msg }}</h1>
    <img src="./img/logo.png">
    <input type="text" v-model="msg">
  </div>
</template>

<script>

import getData from './util';

export default {
  name: 'app',
  data () {
    return {
      msg: 'Welcome to Your Vue.js'
    }
  },
  created() {
    this.fetchData();
  },
  methods: {
     async fetchData() {
      const data = await getData();
      this.msg = data;
    }
  }
}
</script>

<style lang="scss">
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;

  h1 {
    color: green;
  }
}
</style>

main.js

import Vue from 'vue';
import App from './App.vue';

import './style/common.scss';

new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
    <script src="/dist/build.js"></script>
</body>

</html>

npm run dev, вы можете обнаружить, что один файл загружается правильно.

source-map

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

App.vue

created() {
    this.fetchData();
    console.log('23333');
}

Мы намеренно нажимаем на консоль, чтобы открыть консоль

Нажимаем ввести подробный адрес этой консоли

Заходя в упакованный build.js я не знаю в каком компоненте он написан, что затрудняет отладку

На данный момент нам нужно изменить webpack.config.js

module.exports = {
    entry: ['babel-polyfill', './src/main.js'],
    // 省略其他...

    devtool: '#eval-source-map'
};

Re-npm запустить разработчика

Это отладка, она напрямую возвращает исходный код того компонента, который не запакован!

Релиз пакета

Давайте попробуем npm run build, чтобы сначала упаковать файл.

Вы обнаружите, что упакованный файл build.js очень большой, более 500 тыс.

При фактической публикации файлы будут сжаты, кэшированы, разделены и т. д. оптимизированы.

npm i cross-env --save-dev

Изменить package.json

"scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
}

На этот раз мы устанавливаем переменную среды, при упаковке NODE_ENV является производственной.

Затем измените webpack.config.js и сожмите код js, если решите, что NODE_ENV является производственным.

var path = require('path');
var webpack = require('webpack');

module.exports = {
    // 省略...
}

if (process.env.NODE_ENV === 'production') {
    module.exports.devtool = '#source-map';
    module.exports.plugins = (module.exports.plugins || []).concat([
      new webpack.DefinePlugin({
        'process.env': {
          NODE_ENV: '"production"'
        }
      }),
      new webpack.optimize.UglifyJsPlugin(),
    ])
  }
  

переупаковывать

Как видите, эффект сжатия очень очевиден!

До сих пор была успешно построена очень простая среда разработки Vue.

Уведомление:В этой статье еще много мест для оптимизации конфигурации, например разделение js и css

Читатели могут сами разобраться в соответствующих знаниях, здесь мы просто познакомим вас с самой базовой конфигурацией веб-пакета.