I'm trying to create a react-native-for-web app to build for iOS and web platforms. A solution to my question will get the xcode/mac Simulator running with hot reloading of the iOS version, while also running the web version, of a "react-native-web": "^0.9.x" app.
I googled how to start one of these, and found the top few articles were written by the creator of create-react-native-web-app, so I decided to try this method. It has however been an uphill battle.
But first of all, the part that seems to work out of the box is the web part. In my first attempt, after running npx create-react-native-web-app demo-app, yarn web immediately worked. :)
But yarn iOS wouldn't build, and there were multiple issues.
I have node -v >> v11.5.0. I'm on Mohave, with xcode 10.1 already setup (for iOS development).
I needed to install the xcode 10.1 commandline tools though.
Then, I needed to yarn iOS
followed by opening the creaternwapp project under ios/ and change the Project Settings > Build System to Legacy Build System.
Then I had to attempt to build it in xcode. (turns out this is important, even though build will fail)
Then, (cd node_modules/react-native/third-party/glog-0.3.4/ && ./configure) // those numbers may change apparently, depending on install
whether I needed to or not, I changed the .babelrc from:
{
"presets": ["module:metro-react-native-babel-preset"],
}
to:
{
"presets": [["module:metro-react-native-babel-preset"], ["react-app"]],
"ignore": ["node_modules/art/core/color.js"],
"plugins": [
["module-resolver", {
"alias": {
"^react-native$": "react-native-web"
}
}]
],
}
then: npm install && npm audit fix and followed that with yarn install so yarn could get control back.
At this point yarn ios succeeds, but the error with setTimeout is showing on the simulator. I researched that, and apparently these sorts of errors happen when react-native install isn't complete, with the suggested solution to yarn upgrade react native. But yarn upgrade react-native#0.57.8 doesn't change anything for me.
This is not the answer I was looking for, I would love create-react-native-web-app to work out of the box .. but for now -- here's how I am using rn + rnw , even with react-native-paper:
I can describe how to get react-native-paper working in expo.
expo init --yarn --template blank demo-app
-- cd demo-app
yarn add react-native-web react-router-dom react-router-native react-app-polyfill react-art react-native-paper react-dom
-- yarn add -D react-scripts #babel/preset-flow #babel/plugin-proposal-class-properties
code package.json and add scripts:
"web": "react-scripts start",
"build-web": "react-scripts build"
-- we're going to be cheating and editing them in-place. A better practice is to copy node-modules/react-scripts/ config and scripts into your project folder, install their dependencies and get them working locally. But this is just a proof-of-concept (so .. just be sure not to reinstall node_modules or react-scripts for now on)
-- configure/add main:
"main": "react-native-main.js",
code react-native-main.js saving:
import { KeepAwake, registerRootComponent } from 'expo'
import App from './src/App'
if (__DEV__) {
KeepAwake.activate()
}
registerRootComponent(App)
mkdir src public
rm App.js
-- code src/App.js saving:
import React from 'react'
import { StyleSheet, View } from 'react-native'
import { Provider as PaperProvider } from 'react-native-paper'
import { Router, Switch, Route } from './routing'
import Home from './Controllers/Home'
export default class App extends React.Component {
render () {
return (
<PaperProvider>
<View style={styles.app}>
<Router>
<Route exact path="/" render={props => <Home {...props} />} />
</Router>
</View>
</PaperProvider>
)
}
}
const styles = StyleSheet.create({
app: {
flex:1
}
})
mkdir src/Controllers && code src/Controllers/Home.js saving: (need to make something to demo Paper .. this is essentially just the text example from the examples folder)
/* #flow */
import React from 'react'
import { View, StyleSheet, Platform } from 'react-native'
import {
Caption,
Headline,
Paragraph,
Subheading,
Title,
withTheme,
type Theme,
} from 'react-native-paper'
type Props = {
theme: Theme,
};
class TextExample extends React.Component<Props> {
render() {
const {
theme: {
colors: { background },
},
} = this.props
return (
<View style={[styles.container, { backgroundColor: background }]}>
<Caption style={styles.text}>Home</Caption>
<Paragraph style={styles.text}>This is the home component</Paragraph>
<Subheading style={styles.text}>home component</Subheading>
<Title style={styles.text}>Home</Title>
<Headline style={styles.text}>Home on { Platform.OS }</Headline>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
padding: 16,
flex: 1,
},
text: {
marginVertical: 4,
},
})
export default withTheme(TextExample)
code public/index.html saving:
<!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>Third Party Demo</title>
</head>
<body>
<div id="react-native-web-app"></div>
</body>
</html>
code src/index.js saving:
import React from 'react'
import ReactDom from 'react-dom'
import App from './App'
ReactDom.render(<App />, document.getElementById('react-native-web-app'))
code src/routing.native.js saving:
export { NativeRouter as Router, Switch, Route, Link } from 'react-router-native'
-- code src/routing.web.js saving:
export { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom'
at this point, yarn iosshould work but yarn web gives the error reported here. We need to edit the react-scripts Webpack config node_modules/react-scripts/config/webpack.config.js:
-- to the plugins of the section marked:
// Process application JS with Babel.
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
(at about line 387) add this plugin:
[
"#babel/plugin-proposal-class-properties",
{
"loose": false
}
]
after that section, create a new section:
// Process paper specially
{
test: /\.js$/,
exclude: /node_modules(?!\/react-native-paper|\/react-native-vector-icons)/,
use: {
loader: require.resolve('babel-loader'),
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [
'#babel/preset-env',
'#babel/preset-react',
'#babel/preset-flow',
],
cacheDirectory: true,
plugins: [
[
"#babel/plugin-proposal-class-properties",
{
"loose": false
}
],
],
// Don't waste time on Gzipping the cache
cacheCompression: false,
// If an error happens in a package, it's possible to be
// because it was compiled. Thus, we don't want the browser
// debugger to show the original code. Instead, the code
// being evaluated would be much more helpful.
sourceMaps: false,
},
}
},
Related
I am trying to use Vue.js 3 inside a Rails app to use a few components but I got this error in dev console
[Vue warn]: Component provided template option but runtime compilation is not
supported in this build of Vue. Configure your bundler to alias "vue"
to "vue/dist/vue.esm-bundler.js".
I tried installing using the "without build tools" version and it works.
app/javascript/components/index.js
import { createApp } from 'vue'
import MyComponent from './dropdown'
document.addEventListener('DOMContentLoaded', function(){
createApp(MyComponent).mount('#app')
})
app/javascript/components/dropdown.js
export default {
data() {
return {
message: 'Hello Vue!'
}
},
}
app/views/index.html
<div id="app">{{ message }}</div>
package.json
{
"vue": "^3.2.36"
},
"scripts": {
"build": "node esbuild.config.js",
"build:css": "sass ./app/assets/stylesheets/application.scss ./app/assets/builds/application.css --no-source-map --load-path=node_modules"
}
}
esbuild doesn't have an alias feature out of the box. Just import esm bundler directly:
import { createApp } from "vue/dist/vue.esm-bundler.js"
There is a plugin for configuring aliases esbuild-plugin-alias:
https://www.npmjs.com/package/esbuild-plugin-alias
I've scoured the internet and have bits and pieces but nothing is coming together for me. I have a local Drupal environment running with Lando. I've successfully installed and configured webpack. Everything is working except when I try to watch or hot reload.
When I run lando npm run build-dev (that currently uses webpack --watch I can see my changes compiled successfully into the correct folder. However, when I refresh my Drupal site, I do not see that changes. The only time I see my updated JS changes are when I run lando drush cr to clear cache. Same things are happening when I try to configure the webpack-dev-server. I can get everything to watch for changes and compile correctly but I cannot get my browser to reload my files, they stay cached. I'm at a loss.
I've tried configuring a proxy in my .lando.yml , and have tried different things with the config options for devServer. I'm just not getting a concise answer, and I just don't have the knowledge to understand exactly what is happening. I believe it has to do with Docker containers not being exposed to webpack (??) but I don't understand how to configure this properly.
These are the scripts I have set up in my package.json , build outputs my production ready files into i_screamz/js/dist, build-dev starts a watch and compiles non-minified versions to i_screamz/js/dist-dev - start I have in here from trying to get the devServer to work. I'd like to get webpack-dev-server running as I'd love to have reloading working.
"scripts": {
"start": "npm run build:dev",
"build:dev": "webpack --watch --progress --config webpack.config.js",
"build": "NODE_ENV=production webpack --progress --config webpack.config.js"
},
This is my webpack.config.js - no sass yet, this is just a working modular js build at this point.
const path = require("path");
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
const isDevMode = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevMode ? 'development' : 'production',
devtool: isDevMode ? 'source-map' : false,
entry: {
main: ['./src/index.js']
},
output: {
filename: isDevMode ? 'main-dev.js' : 'main.js',
path: isDevMode ? path.resolve(__dirname, 'js/dist-dev') : path.resolve(__dirname, 'js/dist'),
publicPath: '/web/themes/custom/[MYSITE]/js/dist-dev'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
},
plugins: [
new BrowserSyncPlugin({
proxy: {
target: 'http://[MYSITE].lndo.site/',
proxyReq: [
function(proxyReq) {
proxyReq.setHeader('Cache-Control', 'no-cache, no-store');
}
]
},
open: false,
https: false,
files: [
{
match: ['**/*.css', '**/*.js'],
fn: (event, file) => {
if (event == 'change') {
const bs = require("browser-sync").get("bs-webpack-plugin");
if (file.split('.').pop()=='js') {
bs.reload();
} else {
bs.stream();
}
}
}
}
]
}, {
// prevent BrowserSync from reloading the page
// and let Webpack Dev Server take care of this
reload: false,
injectCss: true,
name: 'bs-webpack-plugin'
}),
],
watchOptions: {
aggregateTimeout: 300,
ignored: ['**/*.woff', '**/*.json', '**/*.woff2', '**/*.jpg', '**/*.png', '**/*.svg', 'node_modules'],
}
};
And here is the config I have setup in my .lando.yml - I did have the proxy key in here but it's been removed as I couldn't get it setup right.
name: [MYSITE]
recipe: pantheon
config:
framework: drupal8
site: [MYPANTHEONSITE]
services:
node:
type: node
build:
- npm install
tooling:
drush:
service: appserver
env:
DRUSH_OPTIONS_URI: "http://[MYSITE].lndo.site"
npm:
service: node
settings.local.php
<?php
/**
* Disable CSS and JS aggregation.
*/
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;
I've updated my code files above to reflect reflect a final working setup with webpack. The main answer was a setting in
/web/sites/default/settings.local.php
**Disable CSS & JS aggregation. **
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;
I found a working setup from saschaeggi and just tinkered around until I found this setting. So thank you! I also found more about what this means here. This issue took me way longer than I want to admit and it was so simple. I don't know why the 'Disabling Caching css/js aggregation' page never came up when I was furiously googling a caching issue. Hopefully this answer helps anyone else in this very edge case predicament.
I have webpack setup within my theme root folder with my Drupal theme files. I run everything with Lando, including NPM. I found a nifty trick to switch the dist-dev and dist libraries for development / production builds from thinkshout.
I should note my setup does not include hot-reloading but I can at least compile my files and refresh immediately and see my changes. The issue I was having before is that I would have to stop my watches to drush cr and that workflow was ridiculous. I've never gotten hot reloading to work with with either BrowserSync or Webpack Dev Server and I might try to again but I need to move on with my life at this point.
I've also note included sass yet, so these files paths will change to include compilation and output for both .scss and .js files but this is the basic bare min setup working.
I would like to create a simple npm package and import that into svelte components, however, I cannot seem to use index files to import deeply nested files, e.g.
// routes/test.svelte
<script lang="ts">
import { Test } from '#my-co/my-lib/dist/folder1/folder2/test';
const test = new Test('foo', 'bar');
</script>
works, but
// routes/test.svelte
<script lang="ts">
import { Test } from '#my-co/my-lib';
const test = new Test('foo', 'bar');
</script>
does not. I have the following in the index.ts file in my npm module:
export { Test } from './folder1/folder2/test';
This strangely also does seem to work in ssr (dev server output in console seems to pick the import {Test} from '#my-co/my-lib' correctly), but not in the browser, where I get the error that Test is not a constructor...
Npm library package.json:
{
"name": "#myco/my-lib",
"version": "0.0.2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "tsc",
"prepare": "npm run build"
},
"author": "redacted",
"license": "ISC",
"dependencies": {
"#types/rosie": "0.0.40",
"#types/slug": "^5.0.3",
"rosie": "^2.1.0",
"slug": "^5.1.1"
}
}
Npm library tsconfig
{
"compilerOptions": {
"declaration": true,
"strictNullChecks": true,
"outDir": "dist",
"moduleResolution": "node",
"module": "es2015",
"target": "es5",
"sourceMap": true,
"lib": ["es2015", "dom"],
"rootDir": "src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Lib structure
my-lib/
| dist/
| node_modules/
| src/
| | folder1/
| | | folder2/
| | | | test.ts
test.ts
export class Test {
foo: string;
bar: string;
constructor(foo: string, bar: string) {
this.foo = foo;
this.bar = bar;
}
testMe() {
console.log("foobar", this.foo, this.bar);
}
}
The svelte-kit package command should automatically do everything for you (docs).
This Youtube video should explain everything.
The steps it provides to publish are:
npm init svelte#next project-name
cd project-name
Create component
npx svelte-kit package
cd package
Login to npm / create an account
npm publish --access public
While Caleb's answer did not really help in my case, I think it was a bit of a pointer as to what was going wrong. I did not intend to write a svelte-focused Component library, but rather a general model/factory library to be reused between the front- and backend.
I did a couple of things since this issue occurred and here is a list of things I think went wrong:
Local linking of the npm package into my project caused issues (npm link). I have very little experience with all the build tools in sveltekit but figured out where those stale/non-functional libs are referenced from. I deleted the node-modules/.vite folder which sometimes resolved my issues (I greped for seemingly cached values which led me to this directory. In my dev experience quite uncommon to have found build artifacts in node-modules, so that was a bit tedious to find in that place).
I converted my npm package to a hybrid ESM/CJS module (previously CommonJS only). I'm unsure whether that resolved the initial issues, but might be worth a try.
I think the main issue was the local linking and some sort of build caching going on in vite.
That being said, I haven't encountered any issues with the library ever since.
I use Webpack 4 in a project where I only need to compile and bundle styles so far. There's no Javascript.
Here's the config I have:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: {
'css/bundle': path.resolve(__dirname, 'static/scss/index.scss'),
},
output: {
path: path.resolve(__dirname, 'static'),
},
module: {
rules: [
{
test: /\.s[ac]ss$/,
include: path.resolve(__dirname, 'static/scss'),
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
],
},
plugins: [
new MiniCssExtractPlugin(),
],
};
The problem is that it outputs two files: bundle.css and bundle.js. Is there a way to configure Webpack so that it doesn't output the Javascript bundle? I tried to navigate the docs, tried a dozen different things, but it didn't really work.
One important note here is that if I remove the css-loader, bundling fails. So while css-loader is most likely responsible for outputting the bundle.js file, I'm not entirely sure how to avoid using it.
webpack-extraneous-file-cleanup-plugin has no effect with webpack 4.12.0.
I can suggest to remove bundle.js manually with on-build-webpack plugin:
var WebpackOnBuildPlugin = require('on-build-webpack');
// ...
plugins: [
// ...
new WebpackOnBuildPlugin(function () {
fs.unlinkSync(path.join('path/to/build', 'bundle.js'));
}),
],
March 2021:
In Webpack 5, on-build-webpack plugin did not work for me.
I found this:
Webpack Shell Plugin Next
The project I’m working on we’re using Webpack 5 as a build tool for a CSS pattern library. Therefore, we didn’t need the main.js in our dist.
Run npm i -D webpack-shell-plugin-next
Then in webpack.config.ts (just showing the pertinent parts):
import WebpackShellPluginNext from "webpack-shell-plugin-next";
module.exports = {
output: {
path: path.resolve(__dirname, "static/dist")
},
plugins: [
// Run commands before or after webpack 5 builds:
new WebpackShellPluginNext({
onBuildEnd: {
scripts: [
() => {
fs.unlinkSync(path.join(config.output.path, "main.js"));
}
]
}
})
]
};
export default config;
Unfortunately, this is just the way that webpack currently works. However, we are not alone in this problem! There's a plugin to cleanup any unwanted files:
install the plugin:
yarn add webpack-extraneous-file-cleanup-plugin -D
and then in your config:
const ExtraneousFileCleanupPlugin = require('webpack-extraneous-file-cleanup-plugin');
plugins: [
new ExtraneousFileCleanupPlugin({
extensions: ['.js'],
minBytes: 1024,
paths: ['./static']
}),
]
I simply delete the unneeded output with rm in package.json:
"scripts": {
"build": "npm run clean && webpack -p && rm ./dist/unneeded.js"
},
The webpack-remove-empty-scripts plugin, compatible with webpack 5, cover the current issue. It remove unexpected empty js file.
I am using yeoman webapp generator to generate a template to kick start of my work. At this moment, my bower.json looks like this
{
"name": "sample-project",
"private": true,
"dependencies": {
"bootstrap-sass": "~3.3.5",
"modernizr": "~2.8.3",
"fontawesome": "~4.3.0",
"jquery.smooth-scroll": "~1.5.5",
"animate.css": "~3.3.0",
"jquery.appear": "*"
},
"overrides": {
"bootstrap-sass": {
"main": [
"assets/stylesheets/_bootstrap.scss",
"assets/fonts/bootstrap/*",
"assets/javascripts/bootstrap.js"
]
}
},
"devDependencies": {
"chai": "~3.0.0",
"mocha": "~2.2.5"
}
}
Now, in cmd prompt I type this while grunt watch is running
bower install bootstrap-datepicker -S
Then I found "bootstrap-datepicker": "~1.4.0" is inserted into the dependencies section, then
<script src="bower_components/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>
will be automatically wiredep into my index.html, it becomes this
<!-- build:js(.) scripts/vendor.js -->
<!-- bower:js -->
.
.
<script src="bower_components/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>
<!-- endbower -->
<!-- endbuild -->
Then I try to install another bower component to my webapp
bower install country-region-selector -S
The next thing happens is I found "country-region-selector": "~0.1.8" is under dependencies section of bower.json like bootstrap-datepicker, however the corresponding
<script src="bower_components/country-region-selector/dist/crs.min.js"></script>
doesn't get wiredep into my index.html.
So my question is why grunt wiredep doesn't work on some bower components? The same thing happens to form.validation Could anybody shed some light on this problem?
grunt-wiredep works in a very specific way. The dependencies should be listed in an array inside the main property in bower.josn like the example you mentioned from bootstrap.
The problem you are facing is probably those packages doesn't have a main property or it is using multiple files in a string not an array.
To fix that, you can always define an override for the packages main property likes the following ...
In your grunt file:
wiredep: {
...
overrides: {
'package-name': {
'main': [
'link-to-css-file.css',
'link-to-js-file.js'
]
},
},
},