Есть ли способ динамически загружать фрагменты JS без предварительного знания о них? - PullRequest
0 голосов
/ 07 ноября 2018

Я пытаюсь модулировать веб-приложение, вот несколько основных моментов:

  • есть контейнерное приложение (основной пакет JS, загруженный веб-страницей) с роутером
  • данные о маршрутах извлекаются динамически (или встраиваются в HTML)
  • маршруты строятся динамически на основе этих данных
  • каждый маршрут отображается динамически извлекаемым блоком JS, URL для извлечения должен быть взят из данных маршрутов

Итак, мой вопрос: как мне добиться этого с помощью веб-пакета? Мне известна динамическая функция import(), но для нее требуется путь модуля, которого у меня нет, так как он должен быть определен позже, и он должен отличаться для каждого маршрута. Я подумываю о написании плагина для переопределения внутренних элементов выборки фрагментов, предоставляемых самим веб-пакетом, но, может быть, есть лучший способ?

1 Ответ

0 голосов
/ 07 ноября 2018

Я сам пережил эту боль. Webpack и Browserify могут сделать это, но я не большой поклонник того, как он это делает. Вы действительно правы - вам нужно заранее знать, что можно / нужно загружать.

Я использую Go и GopherJS в моей текущей установке, но моя предыдущая использовала NodeJS, SystemJS и RollupJS , и я до сих пор использую компоненты SystemJS и RollupJS.

Core Bundle

Для объединения вы должны подумать заранее, лично я связываю основные компоненты и обычно называю это core.bundle.js. В своих проектах я помещаю все компоненты на стороне клиента в собственную папку jslib:

Стандартная схема проекта

Я использую TypeScript, поэтому в ./src/index.ts я ссылаюсь на мои основные библиотеки ..:

//@ts-ignore
import * as jquery from "jquery";
import * as popper from "popper.js"
import * as bootstrap from "../vendor/bootstrap/index.js"
import * as backbone from "backbone"
import * as lodash from "lodash"

//@ts-ignore
window.jquery = window.jQuery = window.$ = jquery;
//@ts-ignore
window.popper = popper;
//@ts-ignore
window.bootstrap = bootstrap;
//@ts-ignore
window.Backbone = backbone;
//@ts-ignore
window._ = window.lodash = lodash;

Извиняюсь за многословие, но GopherJS может смешно нуждаться в вещах в определенных местах - но по крайней мере все настроено на объекте окна, который должен быть там.

Тогда у нас есть динамический загрузчик в том же файле:

import * as SystemJS from 'systemjs';
import * as Promise from "bluebird";

export class DynamicModuleManager {

  constructor() {
    //load up the main package and initialise SystemJS for use

    SystemJS.config({
      baseURL: '/_pkg', //your dynamic requires will use this folder for the root
      meta: { '*': { scriptLoad: true } }
    });
  }

  public init() {
    //Register the modules you have already loaded!

    //@ts-ignore
    SystemJS.set('lodash', SystemJS.newModule({
      //@ts-ignore
      "default": window.lodash
    }));
    //@ts-ignore
    SystemJS.set('jquery', SystemJS.newModule({
      //@ts-ignore
      "default": window.$
    }));

    //Optionally add some shim/fake modules to allow NodeJS stuff to be used if needed

    //@ts-ignore
      SystemJS.set('child_process', SystemJS.newModule({
      ChildProcess: {}
    }));
  }

  public import(moduleId:string) {
    return SystemJS.import(moduleId).then((m) => {

      console.log(`Loading Module: ${moduleId}`);

      //m is the module object just like you had "required" it
      return m

    });
  }

}

Если вы используете машинопись, мой tsconfig будет таким для основного пакета:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "lib": ["es2015", "dom"],
    "baseUrl": "./src/",
    "outDir": "./build/",
    "inlineSourceMap": true,
    "paths": {
      "*": [
        "./node_modules/*"
      ]
    }
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "src/**/*"
  ]
}

И тогда конфиг накопления выглядит так:

// rollup.config.js
import builtins from 'rollup-plugin-node-builtins';
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';

export default {
  input: './build/index.js',
  output: {
    file: '../assets/js/core.bundle.js',
    format: 'cjs'
  },
  name: 'core_bundle',
  plugins: [
    json(),
    builtins(),
    nodeResolve(),
    commonjs(),
  ]
}

Я не использую плагин rollup-typcript, потому что он вызвал у меня проблему, так что это 3-этапная сборка:

$ cd ~/your_web_project/jslib

$ npm init && npm install --save jquery... [OTHER DEPS] 
## When you clone just make sure to do npm install

$ tsc -p tsconfig.json 
## if you are running typescript remember to install globally

$ rollup -c
## again install globally

Теперь у вас будет ~ / your_web_project / assets / js / core.bundle.js

Субмодули

Так что теперь вы можете создавать другие модули / чанки. Для вышеупомянутой конфигурации вам нужно иметь их в директории, которую обслуживает ваш любимый сервер, или из маршрута внутри узла, например: GET / _pkg /: имя_модуля -> ~ / your_web_project / resources / _pkg /: имя_модуля.js

В ваших модулях все, что вам нужно сделать, - это установить другую папку jslib, примерно такую ​​же, но на этот раз расскажите rollupjs о ваших внешних пакетах ...

Динамически загружаемая среда VSCode / Monaco для структуры папок Golang

// rollup.config.js
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import json from 'rollup-plugin-json';
import alias from 'rollup-plugin-alias';
import babel from 'rollup-plugin-babel';
import * as filepath from "path"


//export an array of webpack configs for multiple modules..
export default [
  {
    input: './build/index.js',
    external : ["lodash", "jquery"], //make sure to make the module aware of anything external otherwise it will get bundled!
    output: {
      file: '../resources/devide.go.js',
      format: 'cjs',
    },
    plugins: [
      nodeResolve({
        module: true,
        jsnext: true,
        extensions: [ '.js', '.json' ]
      }),
      commonjs(),
      alias({
        'golangcli': filepath.resolve(__dirname, 'build/golangcli/client'),
        'vscode': require.resolve('monaco-languageclient/lib/vscode-compatibility')
      }),
      json(),
      postcss({
        plugins: [] //you can even embed CSS in your sources and have it load here...
      }),
      babel({
        "presets": ["@babel/preset-env"],
        "plugins": ["@babel/plugin-syntax-dynamic-import"]
      })
    ]
  }
];

Приведенный выше пример немного экстремален, так как я использую Typescript и Babel до объединения с Rollup.

Цконфиг тоже нуждается в небольших изменениях:

{
  "compilerOptions": {
    "noImplicitAny": false,
    "module": "es2015",
    "target": "es2015",
    "lib": ["es2015", "dom"],
    "baseUrl": "./src/",
    "outDir": "./build/",
    "inlineSourceMap": false,
    "moduleResolution": "node",
    "skipLibCheck": true,
    "paths": {
      "*": [
        "./node_modules/*"
      ]
    }
  },
  "include": [
    "src/**/*"
  ]
}

Это приведет к правильному дрожанию дерева, когда источник сворачивается, и гарантирует, что импортируется только то, что действительно нужно. Важно, когда полезная нагрузка Монако превышает 10 МБ!

Свертывание - отличный набор, я даже использую его для свертывания целых серверных кодовых баз, чтобы их можно было копировать и запускать зависимости и все без проблем (если у вас есть двоичный файл узла), и он работает очень хорошо с настройками Golang, Buffalo, GopherJS, которые у меня есть.

TL; DR

Вышеупомянутая проблема - это то, с чем я боролся долгое время и чувствовал, что это достойно моего первого в истории Ответа на SO. Без сомнения, в указанном решении есть дыры, но, надеюсь, оно кого-то вдохновит!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...