Как включить скрипты, расположенные в папке node_modules?

218

У меня есть вопрос относительно наилучшей практики для включения node_modules в веб-сайт HTML.

Представьте, что у меня есть Bootstrap внутри моей папки node_modules. Теперь для дистрибутивной версии сайта (живой версии), как бы я включил скрипт Bootstrap и CSS файлы, расположенные внутри папки node_modules? Есть ли смысл оставлять Bootstrap внутри этой папки и делать что-то вроде следующего?

<script src="./node_modules/bootstrap/dist/bootstrap.min.js></script>

Или мне нужно добавить правила в мой файл gulp, которые затем скопируют эти файлы в мою папку dist? Или лучше было бы позволить gulp каким-то образом полностью удалить локальный загрузчик из моего HTML файла и заменить его версией CDN?

  • 2
    Связанная тема stackoverflow.com/questions/24397379/… . Так вот, квестино @Palak Bhansali Если предположить, что требуется только одна, то оправдывает ли это реализацию bower для этой единственной цели, например, при запуске приложения gulp express непосредственно из npm, требующего доступа к файлам в gulp, которые находятся в node_modules. Оправдывает ли это единственный случай использования сейчас беседки для этой единственной цели? Это проблема, с которой я сталкиваюсь. Я уже использую composer, npm, gulp, grunt, лично не хочу bower, и тоже не хочу grunt в этом приложении.
  • 0
    Отличный вопрос, который требует интуитивного решения!
Теги:
npm
node-modules

9 ответов

224
Лучший ответ

Обычно вы не хотите раскрывать какие-либо внутренние пути для того, как ваш сервер структурирован по отношению к внешнему миру. Что вы можете сделать, так это создать на вашем сервере статический маршрут /scripts который извлекает его файлы из любого каталога, в котором они находятся. Так что, если ваши файлы находятся в "./node_modules/bootstrap/dist/". Затем тег script на ваших страницах выглядит так:

<script src="/scripts/bootstrap.min.js"></script>

Если вы использовали экспресс с nodejs, статический маршрут так же прост:

app.use('/scripts', express.static(__dirname + '/node_modules/bootstrap/dist/'));

Затем любые запросы браузера из /scripts/xxx.js будут автоматически выбираться из вашего каталога dist адресу __dirname +/node_modules/bootstrap/dist/xxx.js.

Примечание: более новые версии NPM помещают больше вещей на верхний уровень, не вкладываясь так глубоко, поэтому, если вы используете более новую версию NPM, имена путей будут отличаться от указанных в вопросе OP и в текущем ответе. Но концепция все та же. Вы узнаете, где файлы физически расположены на диске сервера и вы делаете app.use() с express.static(), чтобы сделать псевдо-путь к этим файлам, так что вы не подвергая организации фактической файловой системы сервера в клиент.


Если вы не хотите создавать статический маршрут, подобный этому, то вам, вероятно, лучше просто скопировать общедоступные сценарии в путь, который ваш веб-сервер обрабатывает как /scripts или любое другое обозначение верхнего уровня, которое вы хотите использовать. Обычно вы можете сделать это копированием частью процесса сборки/развертывания.


Если вы хотите сделать общедоступным только один конкретный файл в каталоге, а не все, что находится в этом каталоге, вы можете вручную создать отдельные маршруты для каждого файла, а не использовать express.static() например:

<script src="/bootstrap.min.js"></script>

И код для создания маршрута для этого

app.get('/bootstrap.min.js', function(req, res) {
    res.sendFile(__dirname + '/node_modules/bootstrap/dist/bootstrap.min.js');
});

Или, если вы все еще хотите разграничить маршруты для скриптов с помощью /scripts, вы можете сделать это:

<script src="/scripts/bootstrap.min.js"></script>

И код для создания маршрута для этого

app.get('/scripts/bootstrap.min.js', function(req, res) {
    res.sendFile(__dirname + '/node_modules/bootstrap/dist/bootstrap.min.js');
});
  • 2
    Нужно ли копировать их вручную или есть Grunt способ сделать это? Я думаю, что лучше всего было бы полностью скопировать папку начальной загрузки в /scripts потому что таким образом будут поддерживаться любые зависимости внутри модуля.
  • 0
    @phpheini - возможно, это поможет: stackoverflow.com/questions/18966485/… и это npmjs.com/package/grunt-copy
Показать ещё 24 комментария
16

Я бы использовал модуль npm пути, а затем сделал что-то вроде этого:

var path = require('path');
app.use('/scripts', express.static(path.join(__dirname, 'node_modules/bootstrap/dist')));
  • 0
    пометьте дубликаты, как указано выше, path.join - это просто дополнительная мера, но все же то же решение, добавив статический путь в каталог node_modules.
  • 2
    «path.join - это просто дополнительная мера, но все же то же решение», а не то же самое решение. Строго говоря, он использует специфичное для системы соединение (имейте в виду / и разделители в Windows и Unix)
Показать ещё 1 комментарий
7

Как упомянуто jfriend00, вы не должны раскрывать структуру вашего сервера. Вы можете скопировать файлы зависимостей вашего проекта в нечто вроде public/scripts. Вы можете сделать это очень легко с помощью dep-linker:

var DepLinker = require('dep-linker');
DepLinker.copyDependenciesTo('./public/scripts')
// Done
  • 1
    Сценарии src s будут в таком случае похожи на /scripts/[package-name]/dist/file.min.js .
4

Каталог 'node_modules' может не находиться в текущем каталоге, поэтому вы должны разрешить путь динамически.

var bootstrap_dir = require.resolve('bootstrap')
                           .match(/.*\/node_modules\/[^/]+\//)[0];
app.use('/scripts', express.static(bootstrap_dir + 'dist/'));
  • 0
    +1, хотя я не думаю, что это будет работать во всех случаях - связанный модуль egan npm, которого нет в подпапке node_modules
3

Я не нашел никаких чистых решений (я не хочу раскрывать источник всех моих node_modules), поэтому я просто написал Powershell script, чтобы скопировать их:

$deps = "leaflet", "leaflet-search", "material-components-web"

foreach ($dep in $deps) {
    Copy-Item "node_modules/$dep/dist" "static/$dep" -Recurse
}
3

Я хочу обновить этот вопрос с помощью более простого решения. Создайте символическую ссылку на node_modules.

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

Например, если сервер node имеет код для обслуживания статических файлов

app.use(serveStatic(path.join(__dirname, 'dist')));

и __dirname ссылаются на /path/to/app, чтобы ваши статические файлы были отправлены из /path/to/app/dist

и node_modules находится в /path/to/app/ node_modules, затем создайте символическую ссылку, подобную этой в mac/linux:

ln -s /path/to/app/node_modules /path/to/app/dist/node_modules

или как это в окнах:

mklink /path/to/app/node_modules /path/to/app/dist/node_modules

Теперь получите запрос для:

node_modules/some/path 

получит ответ с файлом

/path/to/app/dist/node_modules/some/path 

который действительно является файлом в

/path/to/app/node_modules/some/path

Если ваш каталог в /path/to/app/dist не является безопасным местом, возможно, из-за помех от процесса сборки с помощью gulp или grunt, тогда вы можете добавить отдельный каталог для ссылки и добавить новый serveStatic call, например:

ln -s /path/to/app/node_modules /path/to/app/newDirectoryName/node_modules

и в node добавить:

app.use(serveStatic(path.join(__dirname, 'newDirectoryName')));
  • 1
    Но затем вы переместили свое приложение по другому пути, и символическая ссылка недействительна. Или вы хотите запустить свое приложение на другом компьютере (test / prod), вам нужно будет создать его заново. Любой участник вашего приложения должен сделать то же самое. Это добавляет некоторый maintanace по вышеупомянутым решениям.
  • 0
    @ mati.o А как насчет относительных символических ссылок? Мне нравится это решение, но только с относительными символическими ссылками.
1

Если вы хотите быстрое и простое решение (и у вас установлено gulp).

В моем gulpfile.js я запускаю простую задачу копирования и вставки, которая помещает любые файлы, которые могут мне понадобиться, в каталог ./public/modules/.

gulp.task('modules', function() {
    sources = [
      './node_modules/prismjs/prism.js',
      './node_modules/prismjs/themes/prism-dark.css',
    ]
    gulp.src( sources ).pipe(gulp.dest('./public/modules/'));
});

gulp.task('copy-modules', ['modules']);

Недостатком этого является то, что он не автоматизирован. Однако, если все, что вам нужно, это скопировать несколько сценариев и стилей (и сохранить их в списке), это должно сработать.

  • 0
    Это можно добавить в их package.json в скриптах 'scripts': {'install':'yarn gulp copy-modules'} , предполагая, что yarn является менеджером пакетов, а gulp установлен в пакет.
1

Я сделал следующие изменения для AUTO-INCLUDE файлов в индекс html. Так что, когда вы добавляете файл в папку, он будет автоматически загружен из папки, без необходимости включать файл в index.html

//// THIS WORKS FOR ME 
///// in app.js or server.js

var app = express();

app.use("/", express.static(__dirname));
var fs = require("fs"),

function getFiles (dir, files_){
    files_ = files_ || [];
    var files = fs.readdirSync(dir);
    for (var i in files){
        var name = dir + '/' + files[i];
        if (fs.statSync(name).isDirectory()){
            getFiles(name, files_);
        } else {
            files_.push(name);
        }
    }
    return files_;
}
//// send the files in js folder as variable/array 
ejs = require('ejs');

res.render('index', {
    'something':'something'...........
    jsfiles: jsfiles,
});

///--------------------------------------------------

///////// in views/index.ejs --- the below code will list the files in index.ejs

<% for(var i=0; i < jsfiles.length; i++) { %>
   <script src="<%= jsfiles[i] %>"></script>
<% } %>
0

В моем приложении Angular 2 у меня есть это в файле Index.html:

<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>

Вот полный файл:

<!DOCTYPE html>
<html>
<head>
    <base href="/" />
    <title>TripMate - PPS</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">
    <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css" />

    <!-- Polyfill(s) for older browsers -->
    <script src="node_modules/core-js/client/shim.min.js"></script>

    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/reflect-metadata/Reflect.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>

    <script src="node_modules/jquery/dist/jquery.min.js"></script>
    <script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
        System.import('app').catch(function(err) { console.error(err); });
    </script>
</head>

  <body>
    <my-app>Loading...</my-app>
  </body>
</html>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню